diff --git a/res/drawable-hdpi/ic_qs_nfc_off.png b/res/drawable-hdpi/ic_qs_nfc_off.png
new file mode 100644
index 0000000000..9f5ad63fc4
Binary files /dev/null and b/res/drawable-hdpi/ic_qs_nfc_off.png differ
diff --git a/res/drawable-hdpi/ic_qs_nfc_on.png b/res/drawable-hdpi/ic_qs_nfc_on.png
new file mode 100644
index 0000000000..1ff664f610
Binary files /dev/null and b/res/drawable-hdpi/ic_qs_nfc_on.png differ
diff --git a/res/drawable-mdpi/ic_qs_nfc_off.png b/res/drawable-mdpi/ic_qs_nfc_off.png
new file mode 100644
index 0000000000..0e2bea8fe1
Binary files /dev/null and b/res/drawable-mdpi/ic_qs_nfc_off.png differ
diff --git a/res/drawable-mdpi/ic_qs_nfc_on.png b/res/drawable-mdpi/ic_qs_nfc_on.png
new file mode 100644
index 0000000000..e728ab18bc
Binary files /dev/null and b/res/drawable-mdpi/ic_qs_nfc_on.png differ
diff --git a/res/drawable-xhdpi/ic_qs_nfc_off.png b/res/drawable-xhdpi/ic_qs_nfc_off.png
new file mode 100644
index 0000000000..d660b8780e
Binary files /dev/null and b/res/drawable-xhdpi/ic_qs_nfc_off.png differ
diff --git a/res/drawable-xhdpi/ic_qs_nfc_on.png b/res/drawable-xhdpi/ic_qs_nfc_on.png
new file mode 100644
index 0000000000..fc1093c381
Binary files /dev/null and b/res/drawable-xhdpi/ic_qs_nfc_on.png differ
diff --git a/res/layout/quick_settings_tile_nfc.xml b/res/layout/quick_settings_tile_nfc.xml
new file mode 100644
index 0000000000..d10d58bbb9
--- /dev/null
+++ b/res/layout/quick_settings_tile_nfc.xml
@@ -0,0 +1,24 @@
+
+
+
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index b2b341719e..d3bcef12cf 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -83,6 +83,7 @@
- @string/qs_tile_bluetooth
- @string/qs_tile_gps
- @string/qs_tile_gps_alt
+ - @string/qs_tile_nfc
- @string/qs_tile_mobile_data
- @string/qs_tile_network_mode
- @string/qs_tile_data_usage
@@ -113,6 +114,7 @@
- bluetooth_textview
- gps_textview
- gps_tileview
+ - nfc_tileview
- data_conn_textview
- network_mode_tileview
- rssi_textview
@@ -145,6 +147,7 @@
- @string/qs_tile_airplane_mode
- @string/qs_tile_bluetooth
- @string/qs_tile_gps
+ - @string/qs_tile_nfc
- @string/qs_tile_ringer_mode
- @string/qs_tile_volume
- @string/qs_tile_network_mode
@@ -171,6 +174,7 @@
- airplane_mode_textview
- bluetooth_textview
- gps_tileview
+ - nfc_tileview
- ringer_mode_tileview
- volume_tileview
- network_mode_tileview
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3c2abedda6..1ac7ea34bf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -99,6 +99,8 @@
Wi-Fi off
Not connected
Turning on…
+ NFC
+ NFC off
Statusbar QuickSettings tiles
@@ -129,6 +131,7 @@
Expanded desktop
Stay awake
Screenshot
+ NFC
Color Picker
diff --git a/src/com/ceco/gm2/gravitybox/ModQuickSettings.java b/src/com/ceco/gm2/gravitybox/ModQuickSettings.java
index a60648192b..1d5ed7f201 100644
--- a/src/com/ceco/gm2/gravitybox/ModQuickSettings.java
+++ b/src/com/ceco/gm2/gravitybox/ModQuickSettings.java
@@ -31,6 +31,7 @@
import com.ceco.gm2.gravitybox.quicksettings.ExpandedDesktopTile;
import com.ceco.gm2.gravitybox.quicksettings.GpsTile;
import com.ceco.gm2.gravitybox.quicksettings.NetworkModeTile;
+import com.ceco.gm2.gravitybox.quicksettings.NfcTile;
import com.ceco.gm2.gravitybox.quicksettings.QuickAppTile;
import com.ceco.gm2.gravitybox.quicksettings.QuickRecordTile;
import com.ceco.gm2.gravitybox.quicksettings.RingerModeTile;
@@ -152,7 +153,8 @@ public class ModQuickSettings {
R.id.stay_awake_tileview,
R.id.screenshot_tileview,
R.id.gps_tileview,
- R.id.ringer_mode_tileview
+ R.id.ringer_mode_tileview,
+ R.id.nfc_tileview
));
if (Utils.isMtkDevice()) {
mCustomGbTileKeys.add(R.id.wifi_tileview);
@@ -594,6 +596,12 @@ protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
gpsTile.setupQuickSettingsTile(mContainerView, inflater, mPrefs);
mTiles.add(gpsTile);
}
+
+ if (Utils.hasNFC(mContext)) {
+ NfcTile nfcTile = new NfcTile(mContext, mGbContext, mStatusBar, mPanelBar);
+ nfcTile.setupQuickSettingsTile(mContainerView, inflater);
+ mTiles.add(nfcTile);
+ }
RingerModeTile rmTile = new RingerModeTile(mContext, mGbContext, mStatusBar, mPanelBar);
rmTile.setupQuickSettingsTile(mContainerView, inflater, mPrefs);
diff --git a/src/com/ceco/gm2/gravitybox/Utils.java b/src/com/ceco/gm2/gravitybox/Utils.java
index e1ba819b88..84da6a5edd 100644
--- a/src/com/ceco/gm2/gravitybox/Utils.java
+++ b/src/com/ceco/gm2/gravitybox/Utils.java
@@ -52,6 +52,7 @@ public class Utils {
private static Boolean mHasVibrator = null;
private static Boolean mHasFlash = null;
private static Boolean mHasGPS = null;
+ private static Boolean mHasNFC = null;
// Supported MTK devices
private static final Set MTK_DEVICES = new HashSet(Arrays.asList(
@@ -214,6 +215,20 @@ public static boolean hasGPS(Context con) {
}
}
+ public static boolean hasNFC(Context con) {
+ if (mHasNFC != null) return mHasNFC;
+ PackageManager pm = con.getPackageManager();
+ if (pm == null) {
+ if (DEBUG) log("Cannot get package manager, assuming no NFC feature");
+ mHasNFC = null;
+ return false;
+ }
+
+ mHasNFC = pm.hasSystemFeature(PackageManager.FEATURE_NFC);
+
+ return mHasNFC;
+ }
+
public static String getDeviceCharacteristics() {
if (mDeviceCharacteristics != null) return mDeviceCharacteristics;
diff --git a/src/com/ceco/gm2/gravitybox/quicksettings/NfcTile.java b/src/com/ceco/gm2/gravitybox/quicksettings/NfcTile.java
new file mode 100644
index 0000000000..257f2e4f02
--- /dev/null
+++ b/src/com/ceco/gm2/gravitybox/quicksettings/NfcTile.java
@@ -0,0 +1,160 @@
+package com.ceco.gm2.gravitybox.quicksettings;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.nfc.NfcAdapter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import com.ceco.gm2.gravitybox.R;
+
+import de.robv.android.xposed.XposedHelpers;
+
+public class NfcTile extends AQuickSettingsTile {
+
+ private static final String INTENT_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
+ private static final String INTENT_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
+
+ private static final int STATE_TURNING_ON = XposedHelpers.getStaticIntField(NfcAdapter.class, "STATE_TURNING_ON");
+ private static final int STATE_ON = XposedHelpers.getStaticIntField(NfcAdapter.class, "STATE_ON");
+ @SuppressWarnings("unused")
+ private static final int STATE_TURNING_OFF = XposedHelpers.getStaticIntField(NfcAdapter.class, "STATE_TURNING_OFF");
+ private static final int STATE_OFF = XposedHelpers.getStaticIntField(NfcAdapter.class, "STATE_OFF");
+ private static final int NFC_ADAPTER_UNKNOWN = -100;
+
+ @SuppressWarnings("unused")
+ private static final String TAG = "GB:NfcTile";
+
+ private static NfcAdapter mNfcAdapter = null;
+
+ private BroadcastReceiver mNfcStateChangedReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (INTENT_ADAPTER_STATE_CHANGED.equals(intent.getAction())) {
+ if (mNfcAdapter == null)
+ getNfcAdapter(true);
+ updateTile(getNfcState());
+ }
+ }
+ };
+
+ private TextView mTextView;
+
+ public NfcTile(Context context, Context gbContext, Object statusBar, Object panelBar) {
+ super(context, gbContext, statusBar, panelBar);
+
+ mOnClick = new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ toggleState();
+ }
+ };
+
+ mOnLongClick = new View.OnLongClickListener() {
+
+ @Override
+ public boolean onLongClick(View v) {
+ Intent intent = new Intent(INTENT_NFC_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ return true;
+ }
+ };
+ }
+
+ private void toggleState() {
+ int state = getNfcState();
+ /* For some reason, a switch-case way of handling this didn't work */
+
+ if (mNfcAdapter == null)
+ getNfcAdapter(true);
+
+ if (mNfcAdapter == null) {
+ return;
+ }
+
+ if (state == STATE_TURNING_ON || state == STATE_ON)
+ XposedHelpers.callMethod(mNfcAdapter, "disable");
+ else
+ XposedHelpers.callMethod(mNfcAdapter, "enable");
+
+ updateTile();
+ }
+
+ @Override
+ protected void onTileCreate() {
+ LayoutInflater inflater = LayoutInflater.from(mGbContext);
+ inflater.inflate(R.layout.quick_settings_tile_nfc, mTile);
+ mTextView = (TextView) mTile.findViewById(R.id.nfc_tileview);
+
+ mTextView.setText(mLabel);
+ mTextView.setCompoundDrawablesWithIntrinsicBounds(0, mDrawableId, 0, 0);
+ }
+
+ @Override
+ protected void updateTile() {
+ updateTile(getNfcState());
+ }
+
+ private void updateTile(int state) {
+ if (state == STATE_TURNING_ON || state == STATE_ON) {
+ mDrawableId = R.drawable.ic_qs_nfc_on;
+ mLabel = mGbContext.getString(R.string.quick_settings_nfc);
+ } else {
+ mDrawableId = R.drawable.ic_qs_nfc_off;
+ mLabel = mGbContext.getString(R.string.quick_settings_nfc_off);
+ }
+
+ if (mTextView != null) {
+ mTextView.setText(mLabel);
+ mTextView.setCompoundDrawablesWithIntrinsicBounds(0, mDrawableId, 0, 0);
+ }
+ }
+
+ private int getNfcState() {
+ int state = STATE_OFF;
+ try {
+ getNfcAdapter(false);
+ } catch (UnsupportedOperationException e) {
+ state = NFC_ADAPTER_UNKNOWN;
+ }
+
+ if (mNfcAdapter != null)
+ state = (Integer) XposedHelpers.callMethod(mNfcAdapter, "getAdapterState");
+
+ return state;
+ }
+
+ @Override
+ protected void onTilePostCreate() {
+ mContext.registerReceiver(mNfcStateChangedReceiver,
+ new IntentFilter(INTENT_ADAPTER_STATE_CHANGED));
+
+ super.onTilePostCreate();
+ }
+
+ private void getNfcAdapter(boolean suppressThrow) throws UnsupportedOperationException {
+ Class> ServiceManager;
+ try {
+ ServiceManager = Class.forName("android.os.ServiceManager");
+ } catch (ClassNotFoundException e1) {
+ e1.printStackTrace();
+ return;
+ }
+
+ if (mNfcAdapter == null && XposedHelpers.callStaticMethod(ServiceManager, "getService", "nfc") != null) {
+ try {
+ mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext);
+ } catch (UnsupportedOperationException e) {
+ if (!suppressThrow)
+ throw e;
+ }
+ }
+ }
+}