diff options
author | Andres Morales <anmorales@google.com> | 2014-04-16 17:19:05 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-04-16 17:19:05 +0000 |
commit | a298f077c8e1a73e1c17c444845da7dd650443bc (patch) | |
tree | 173a1103cbccd5b09c933d640137c18131532833 /src/com/android/settings/wifi | |
parent | d7adb25e8757ce072c470889f31b4f6bc361b3b4 (diff) | |
parent | ef7a40a0d65a4d3e43d454273c6334448158e555 (diff) | |
download | packages_apps_Settings-a298f077c8e1a73e1c17c444845da7dd650443bc.tar.gz packages_apps_Settings-a298f077c8e1a73e1c17c444845da7dd650443bc.tar.bz2 packages_apps_Settings-a298f077c8e1a73e1c17c444845da7dd650443bc.zip |
Merge "Write wifi config to NFC tag"
Diffstat (limited to 'src/com/android/settings/wifi')
-rw-r--r-- | src/com/android/settings/wifi/WifiSettings.java | 25 | ||||
-rw-r--r-- | src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java | 264 |
2 files changed, 285 insertions, 4 deletions
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 21efc39d5..15a184c97 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -94,6 +94,7 @@ import java.util.concurrent.atomic.AtomicBoolean; */ public class WifiSettings extends RestrictedSettingsFragment implements DialogInterface.OnClickListener, Indexable { + private static final String TAG = "WifiSettings"; private static final int MENU_ID_WPS_PBC = Menu.FIRST; private static final int MENU_ID_WPS_PIN = Menu.FIRST + 1; @@ -104,12 +105,14 @@ public class WifiSettings extends RestrictedSettingsFragment private static final int MENU_ID_CONNECT = Menu.FIRST + 6; private static final int MENU_ID_FORGET = Menu.FIRST + 7; private static final int MENU_ID_MODIFY = Menu.FIRST + 8; + private static final int MENU_ID_WRITE_NFC = Menu.FIRST + 9; private static final int WIFI_DIALOG_ID = 1; private static final int WPS_PBC_DIALOG_ID = 2; private static final int WPS_PIN_DIALOG_ID = 3; private static final int WIFI_SKIPPED_DIALOG_ID = 4; private static final int WIFI_AND_MOBILE_SKIPPED_DIALOG_ID = 5; + private static final int WRITE_NFC_DIALOG_ID = 6; // Combo scans can take 5-6s to complete - set to 10s. private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000; @@ -141,6 +144,7 @@ public class WifiSettings extends RestrictedSettingsFragment private final AtomicBoolean mConnected = new AtomicBoolean(false); private WifiDialog mDialog; + private WriteWifiConfigToNfcDialog mWifiToNfcDialog; private TextView mEmptyView; @@ -205,13 +209,13 @@ public class WifiSettings extends RestrictedSettingsFragment public void onCreate(Bundle icicle) { // Set this flag early, as it's needed by getHelpResource(), which is called by super mSetupWizardMode = getActivity().getIntent().getBooleanExtra(EXTRA_IS_FIRST_RUN, false); - super.onCreate(icicle); } @Override public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (mSetupWizardMode) { View view = inflater.inflate(R.layout.setup_preference, container, false); View other = view.findViewById(R.id.other_network); @@ -471,6 +475,7 @@ public class WifiSettings extends RestrictedSettingsFragment if (mWifiEnabler != null) { mWifiEnabler.pause(); } + getActivity().unregisterReceiver(mReceiver); mScanner.pause(); } @@ -599,6 +604,11 @@ public class WifiSettings extends RestrictedSettingsFragment if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) { menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget); menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify); + + if (mSelectedAccessPoint.security != AccessPoint.SECURITY_NONE) { + // Only allow writing of NFC tags for password-protected networks. + menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, "Write to NFC Tag"); + } } } } @@ -632,6 +642,10 @@ public class WifiSettings extends RestrictedSettingsFragment showDialog(mSelectedAccessPoint, true); return true; } + case MENU_ID_WRITE_NFC: + showDialog(WRITE_NFC_DIALOG_ID); + return true; + } return super.onContextItemSelected(item); } @@ -681,7 +695,7 @@ public class WifiSettings extends RestrictedSettingsFragment mAccessPointSavedState = null; } } - // If it's still null, fine, it's for Add Network + // If it's null, fine, it's for Add Network mSelectedAccessPoint = ap; mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit); return mDialog; @@ -727,6 +741,10 @@ public class WifiSettings extends RestrictedSettingsFragment } }) .create(); + case WRITE_NFC_DIALOG_ID: + mWifiToNfcDialog =new WriteWifiConfigToNfcDialog( + getActivity(), mSelectedAccessPoint, mWifiManager); + return mWifiToNfcDialog; } return super.onCreateDialog(dialogId); @@ -991,8 +1009,7 @@ public class WifiSettings extends RestrictedSettingsFragment mRetry = 0; Activity activity = getActivity(); if (activity != null) { - Toast.makeText(activity, R.string.wifi_fail_to_scan, - Toast.LENGTH_LONG).show(); + Toast.makeText(activity, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show(); } return; } diff --git a/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java b/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java new file mode 100644 index 000000000..7515f5c5a --- /dev/null +++ b/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java @@ -0,0 +1,264 @@ +package com.android.settings.wifi; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.net.wifi.WifiManager; +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.Ndef; +import android.os.Bundle; +import android.os.Handler; +import android.os.PowerManager; +import android.text.Editable; +import android.text.InputType; +import android.text.TextWatcher; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.android.settings.R; + +import java.io.IOException; + +class WriteWifiConfigToNfcDialog extends AlertDialog + implements TextWatcher, View.OnClickListener, CompoundButton.OnCheckedChangeListener { + + private static final String NFC_TOKEN_MIME_TYPE = "application/vnd.wfa.wsc"; + + private static final String TAG = WriteWifiConfigToNfcDialog.class.getName().toString(); + private static final String PASSWORD_FORMAT = "102700%s%s"; + + private final PowerManager.WakeLock mWakeLock; + + private AccessPoint mAccessPoint; + private View mView; + private Button mSubmitButton; + private Button mCancelButton; + private Handler mOnTextChangedHandler; + private TextView mPasswordView; + private TextView mLabelView; + private CheckBox mPasswordCheckBox; + private ProgressBar mProgressBar; + private WifiManager mWifiManager; + private String mWpsNfcConfigurationToken; + private Context mContext; + + WriteWifiConfigToNfcDialog(Context context, AccessPoint accessPoint, + WifiManager wifiManager) { + super(context); + this.mContext = context; + this.mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)) + .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WriteWifiConfigToNfcDialog:wakeLock"); + this.mAccessPoint = accessPoint; + this.mOnTextChangedHandler = new Handler(); + this.mWifiManager = wifiManager; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + mView = getLayoutInflater().inflate(R.layout.write_wifi_config_to_nfc, null); + + setView(mView); + setInverseBackgroundForced(true); + setTitle(R.string.setup_wifi_nfc_tag); + setCancelable(true); + setButton(DialogInterface.BUTTON_NEUTRAL, + mContext.getResources().getString(R.string.write_tag), (OnClickListener) null); + setButton(DialogInterface.BUTTON_NEGATIVE, + mContext.getResources().getString(com.android.internal.R.string.cancel), + (OnClickListener) null); + + mPasswordView = (TextView) mView.findViewById(R.id.password); + mLabelView = (TextView) mView.findViewById(R.id.password_label); + mPasswordView.addTextChangedListener(this); + mPasswordCheckBox = (CheckBox) mView.findViewById(R.id.show_password); + mPasswordCheckBox.setOnCheckedChangeListener(this); + mProgressBar = (ProgressBar) mView.findViewById(R.id.progress_bar); + + super.onCreate(savedInstanceState); + + mSubmitButton = getButton(DialogInterface.BUTTON_NEUTRAL); + mSubmitButton.setOnClickListener(this); + mSubmitButton.setEnabled(false); + + mCancelButton = getButton(DialogInterface.BUTTON_NEGATIVE); + } + + @Override + public void onClick(View v) { + mWakeLock.acquire(); + + String password = mPasswordView.getText().toString(); + String wpsNfcConfigurationToken + = mWifiManager.getWpsNfcConfigurationToken(mAccessPoint.networkId); + String passwordHex = byteArrayToHexString(password.getBytes()); + + String passwordLength = password.length() >= 16 + ? "" + Character.forDigit(password.length(), 16) + : "0" + Character.forDigit(password.length(), 16); + + passwordHex = String.format(PASSWORD_FORMAT, passwordLength, passwordHex).toUpperCase(); + + if (wpsNfcConfigurationToken.contains(passwordHex)) { + mWpsNfcConfigurationToken = wpsNfcConfigurationToken; + + Activity activity = getOwnerActivity(); + NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(activity); + + nfcAdapter.enableReaderMode(activity, new NfcAdapter.ReaderCallback() { + @Override + public void onTagDiscovered(Tag tag) { + handleWriteNfcEvent(tag); + } + }, NfcAdapter.FLAG_READER_NFC_A | + NfcAdapter.FLAG_READER_NFC_B | + NfcAdapter.FLAG_READER_NFC_BARCODE | + NfcAdapter.FLAG_READER_NFC_F | + NfcAdapter.FLAG_READER_NFC_V, + null); + + mPasswordView.setVisibility(View.GONE); + mPasswordCheckBox.setVisibility(View.GONE); + mSubmitButton.setVisibility(View.GONE); + InputMethodManager imm = (InputMethodManager) + getOwnerActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mPasswordView.getWindowToken(), 0); + + mLabelView.setText(R.string.status_awaiting_tap); + + mView.findViewById(R.id.password_layout).setTextAlignment(View.TEXT_ALIGNMENT_CENTER); + mProgressBar.setVisibility(View.VISIBLE); + } else { + mLabelView.setText(R.string.status_invalid_password); + } + } + + private void handleWriteNfcEvent(Tag tag) { + Ndef ndef = Ndef.get(tag); + + if (ndef != null) { + if (ndef.isWritable()) { + NdefRecord record = NdefRecord.createMime( + NFC_TOKEN_MIME_TYPE, + hexStringToByteArray(mWpsNfcConfigurationToken)); + try { + ndef.connect(); + ndef.writeNdefMessage(new NdefMessage(record)); + getOwnerActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mProgressBar.setVisibility(View.GONE); + } + }); + setViewText(mLabelView, R.string.status_write_success); + setViewText(mCancelButton, com.android.internal.R.string.done_label); + } catch (IOException e) { + setViewText(mLabelView, R.string.status_failed_to_write); + Log.e(TAG, "Unable to write WiFi config to NFC tag.", e); + return; + } catch (FormatException e) { + setViewText(mLabelView, R.string.status_failed_to_write); + Log.e(TAG, "Unable to write WiFi config to NFC tag.", e); + return; + } + } else { + setViewText(mLabelView, R.string.status_tag_not_writable); + Log.e(TAG, "Tag is not writable"); + } + } else { + setViewText(mLabelView, R.string.status_tag_not_writable); + Log.e(TAG, "Tag does not support NDEF"); + } + } + + @Override + public void dismiss() { + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } + + super.dismiss(); + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + mOnTextChangedHandler.post(new Runnable() { + @Override + public void run() { + enableSubmitIfAppropriate(); + } + }); + } + + private void enableSubmitIfAppropriate() { + + if (mPasswordView != null) { + if (mAccessPoint.security == AccessPoint.SECURITY_WEP) { + mSubmitButton.setEnabled(mPasswordView.length() > 0); + } else if (mAccessPoint.security == AccessPoint.SECURITY_PSK) { + mSubmitButton.setEnabled(mPasswordView.length() >= 8); + } + } else { + mSubmitButton.setEnabled(false); + } + + } + + private void setViewText(final TextView view, final int resid) { + getOwnerActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + view.setText(resid); + } + }); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mPasswordView.setInputType( + InputType.TYPE_CLASS_TEXT | + (isChecked + ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + : InputType.TYPE_TEXT_VARIATION_PASSWORD)); + } + + private static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + + return data; + } + + final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); + private static String byteArrayToHexString(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for ( int j = 0; j < bytes.length; j++ ) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + @Override + public void afterTextChanged(Editable s) {} +} |