diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 6912bb45f86..3c272fc094b 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -235,6 +235,22 @@ @string/wifi_security_psk_generic + + + + @string/wifi_security_wpa2 + + @string/wifi_security_none + + + + + + 4 + + 0 + + diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml index f9d9596ea24..f07944eebd3 100644 --- a/res/xml/wifi_tether_settings.xml +++ b/res/xml/wifi_tether_settings.xml @@ -19,13 +19,20 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/wifi_hotspot_checkbox_text" - settings:initialExpandedChildrenCount="2"> + settings:initialExpandedChildrenCount="3"> + + @@ -33,7 +40,7 @@ + android:summary="@string/wifi_hotspot_auto_off_summary" /> + android:positiveButtonText="@string/apply" /> \ No newline at end of file diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java index 3e797d77b47..99b77d9e36b 100644 --- a/src/com/android/settings/wifi/WifiUtils.java +++ b/src/com/android/settings/wifi/WifiUtils.java @@ -52,7 +52,7 @@ public class WifiUtils { public static boolean isHotspotPasswordValid(String password) { if (TextUtils.isEmpty(password)) { - return true; + return false; } final int length = password.length(); diff --git a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java index 5ba0583b6ab..055e9781aea 100644 --- a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java +++ b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java @@ -31,7 +31,6 @@ import java.util.UUID; public class WifiTetherPasswordPreferenceController extends WifiTetherBasePreferenceController implements ValidatedEditTextPreference.Validator { - private static final String TAG = "WifiTetherPswdPref"; private static final String PREF_KEY = "wifi_tether_network_password"; private String mPassword; @@ -49,10 +48,11 @@ public class WifiTetherPasswordPreferenceController extends WifiTetherBasePrefer @Override public void updateDisplay() { final WifiConfiguration config = mWifiManager.getWifiApConfiguration(); - if (config != null) { - mPassword = config.preSharedKey; - } else { + if (config == null || (config.getAuthType() == WifiConfiguration.KeyMgmt.WPA2_PSK + && TextUtils.isEmpty(config.preSharedKey))) { mPassword = generateRandomPassword(); + } else { + mPassword = config.preSharedKey; } ((ValidatedEditTextPreference) mPreference).setValidator(this); ((ValidatedEditTextPreference) mPreference).setIsPassword(true); @@ -68,17 +68,27 @@ public class WifiTetherPasswordPreferenceController extends WifiTetherBasePrefer return true; } - public String getPassword() { + /** + * This method returns the current password if it is valid for the indicated security type. If + * the password currently set is invalid it will forcefully set a random password that is valid. + * + * @param securityType The security type for the password. + * @return The current password if it is valid for the indicated security type. A new randomly + * generated password if it is not. + */ + public String getPasswordValidated(int securityType) { + // don't actually overwrite unless we get a new config in case it was accidentally toggled. + if (securityType == WifiConfiguration.KeyMgmt.NONE) { + return ""; + } else if (!isTextValid(mPassword)) { + mPassword = generateRandomPassword(); + updatePasswordDisplay((EditTextPreference) mPreference); + } return mPassword; } - public int getSecuritySettingForPassword() { - // We should return NONE when no password is set - if (TextUtils.isEmpty(mPassword)) { - return WifiConfiguration.KeyMgmt.NONE; - } - // Only other currently supported type is WPA2 so we'll try that - return WifiConfiguration.KeyMgmt.WPA2_PSK; + public void updateVisibility(int securityType) { + mPreference.setVisible(securityType != WifiConfiguration.KeyMgmt.NONE); } @Override @@ -98,9 +108,11 @@ public class WifiTetherPasswordPreferenceController extends WifiTetherBasePrefer if (!TextUtils.isEmpty(mPassword)) { pref.setIsSummaryPassword(true); pref.setSummary(mPassword); + pref.setVisible(true); } else { pref.setIsSummaryPassword(false); pref.setSummary(R.string.wifi_hotspot_no_password_subtext); + pref.setVisible(false); } } } diff --git a/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java new file mode 100644 index 00000000000..08a956bb07d --- /dev/null +++ b/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java @@ -0,0 +1,63 @@ +package com.android.settings.wifi.tether; + +import android.content.Context; +import android.content.res.Resources; +import android.net.wifi.WifiConfiguration; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.Preference; + +import com.android.settings.R; + +public class WifiTetherSecurityPreferenceController extends WifiTetherBasePreferenceController { + + private static final String PREF_KEY = "wifi_tether_security"; + + private final String[] mSecurityEntries; + private int mSecurityValue; + + public WifiTetherSecurityPreferenceController(Context context, + OnTetherConfigUpdateListener listener) { + super(context, listener); + mSecurityEntries = mContext.getResources().getStringArray(R.array.wifi_tether_security); + } + + @Override + public String getPreferenceKey() { + return PREF_KEY; + } + + @Override + public void updateDisplay() { + final WifiConfiguration config = mWifiManager.getWifiApConfiguration(); + if (config != null && config.getAuthType() == WifiConfiguration.KeyMgmt.NONE) { + mSecurityValue = WifiConfiguration.KeyMgmt.NONE; + + } else { + mSecurityValue = WifiConfiguration.KeyMgmt.WPA2_PSK; + } + + final ListPreference preference = (ListPreference) mPreference; + preference.setSummary(getSummaryForSecurityType(mSecurityValue)); + preference.setValue(String.valueOf(mSecurityValue)); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + mSecurityValue = Integer.parseInt((String) newValue); + preference.setSummary(getSummaryForSecurityType(mSecurityValue)); + mListener.onTetherConfigUpdated(); + return true; + } + + public int getSecurityType() { + return mSecurityValue; + } + + private String getSummaryForSecurityType(int securityType) { + if (securityType == WifiConfiguration.KeyMgmt.NONE) { + return mSecurityEntries[1]; + } + // WPA2 PSK + return mSecurityEntries[0]; + } +} diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java index de6243c2f31..b2b60e044f7 100644 --- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java +++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java @@ -28,7 +28,6 @@ import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.UserManager; import android.support.annotation.VisibleForTesting; -import android.text.TextUtils; import android.util.Log; import com.android.internal.logging.nano.MetricsProto; @@ -41,7 +40,6 @@ import com.android.settingslib.core.AbstractPreferenceController; import java.util.ArrayList; import java.util.List; -import java.util.UUID; public class WifiTetherSettings extends RestrictedDashboardFragment implements WifiTetherBasePreferenceController.OnTetherConfigUpdateListener { @@ -54,6 +52,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment private WifiTetherSSIDPreferenceController mSSIDPreferenceController; private WifiTetherPasswordPreferenceController mPasswordPreferenceController; private WifiTetherApBandPreferenceController mApBandPreferenceController; + private WifiTetherSecurityPreferenceController mSecurityPreferenceController; private WifiManager mWifiManager; private boolean mRestartWifiApAfterConfigChange; @@ -128,10 +127,12 @@ public class WifiTetherSettings extends RestrictedDashboardFragment protected List createPreferenceControllers(Context context) { final List controllers = new ArrayList<>(); mSSIDPreferenceController = new WifiTetherSSIDPreferenceController(context, this); + mSecurityPreferenceController = new WifiTetherSecurityPreferenceController(context, this); mPasswordPreferenceController = new WifiTetherPasswordPreferenceController(context, this); mApBandPreferenceController = new WifiTetherApBandPreferenceController(context, this); controllers.add(mSSIDPreferenceController); + controllers.add(mSecurityPreferenceController); controllers.add(mPasswordPreferenceController); controllers.add(mApBandPreferenceController); controllers.add( @@ -142,6 +143,8 @@ public class WifiTetherSettings extends RestrictedDashboardFragment @Override public void onTetherConfigUpdated() { final WifiConfiguration config = buildNewConfig(); + mPasswordPreferenceController.updateVisibility(config.getAuthType()); + /** * if soft AP is stopped, bring up * else restart with new config @@ -158,11 +161,11 @@ public class WifiTetherSettings extends RestrictedDashboardFragment private WifiConfiguration buildNewConfig() { final WifiConfiguration config = new WifiConfiguration(); + final int securityType = mSecurityPreferenceController.getSecurityType(); config.SSID = mSSIDPreferenceController.getSSID(); - config.preSharedKey = mPasswordPreferenceController.getPassword(); - config.allowedKeyManagement.set( - mPasswordPreferenceController.getSecuritySettingForPassword()); + config.allowedKeyManagement.set(securityType); + config.preSharedKey = mPasswordPreferenceController.getPasswordValidated(securityType); config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); config.apBand = mApBandPreferenceController.getBandIndex(); return config; @@ -176,6 +179,8 @@ public class WifiTetherSettings extends RestrictedDashboardFragment private void updateDisplayWithNewConfig() { use(WifiTetherSSIDPreferenceController.class) .updateDisplay(); + use(WifiTetherSecurityPreferenceController.class) + .updateDisplay(); use(WifiTetherPasswordPreferenceController.class) .updateDisplay(); use(WifiTetherApBandPreferenceController.class) diff --git a/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java b/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java index 198517a297f..1f49654c402 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java @@ -43,6 +43,6 @@ public class WifiUtilsTest { assertThat(WifiUtils.isHotspotPasswordValid("12345678")).isTrue(); assertThat(WifiUtils.isHotspotPasswordValid("1234567890")).isTrue(); assertThat(WifiUtils.isHotspotPasswordValid(longPassword)).isFalse(); - assertThat(WifiUtils.isHotspotPasswordValid("")).isTrue(); + assertThat(WifiUtils.isHotspotPasswordValid("")).isFalse(); } } diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java index 7e757ad5f84..2de98d96e7a 100644 --- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java @@ -42,6 +42,8 @@ import org.robolectric.RuntimeEnvironment; @RunWith(SettingsRobolectricTestRunner.class) public class WifiTetherPasswordPreferenceControllerTest { + private static final String VALID_PASS = "12345678"; + private static final String VALID_PASS2 = "23456789"; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock @@ -87,11 +89,13 @@ public class WifiTetherPasswordPreferenceControllerTest { @Test public void changePreference_shouldUpdateValue() { mController.displayPreference(mScreen); - mController.onPreferenceChange(mPreference, "1"); - assertThat(mController.getPassword()).isEqualTo("1"); + mController.onPreferenceChange(mPreference, VALID_PASS); + assertThat(mController.getPasswordValidated(WifiConfiguration.KeyMgmt.WPA2_PSK)) + .isEqualTo(VALID_PASS); - mController.onPreferenceChange(mPreference, "0"); - assertThat(mController.getPassword()).isEqualTo("0"); + mController.onPreferenceChange(mPreference, VALID_PASS2); + assertThat(mController.getPasswordValidated(WifiConfiguration.KeyMgmt.WPA2_PSK)) + .isEqualTo(VALID_PASS2); verify(mListener, times(2)).onTetherConfigUpdated(); } @@ -100,62 +104,33 @@ public class WifiTetherPasswordPreferenceControllerTest { public void updateDisplay_shouldUpdateValue() { // Set controller password to anything and verify is set. mController.displayPreference(mScreen); - mController.onPreferenceChange(mPreference, "1"); - assertThat(mController.getPassword()).isEqualTo("1"); + mController.onPreferenceChange(mPreference, VALID_PASS); + assertThat(mController.getPasswordValidated(WifiConfiguration.KeyMgmt.WPA2_PSK)) + .isEqualTo(VALID_PASS); // Create a new config using different password final WifiConfiguration config = new WifiConfiguration(); - config.preSharedKey = "test_1234"; + config.preSharedKey = VALID_PASS2; when(mWifiManager.getWifiApConfiguration()).thenReturn(config); // Call updateDisplay and verify it's changed. mController.updateDisplay(); - assertThat(mController.getPassword()).isEqualTo(config.preSharedKey); + assertThat(mController.getPasswordValidated(WifiConfiguration.KeyMgmt.WPA2_PSK)) + .isEqualTo(config.preSharedKey); assertThat(mPreference.getSummary()).isEqualTo(config.preSharedKey); } - @Test - public void getSecuritySettingForPassword_returnCorrectType() { - // valid wpa2 password - mController.displayPreference(mScreen); - assertThat(mController.getSecuritySettingForPassword()) - .isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); - - // password which is empty returns NONE - mConfig = new WifiConfiguration(); - mConfig.SSID = "test_1234"; - mConfig.preSharedKey = ""; - when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager); - when(mWifiManager.getWifiApConfiguration()).thenReturn(mConfig); - mController = new WifiTetherPasswordPreferenceController(mContext, mListener); - - mController.displayPreference(mScreen); - assertThat(mController.getSecuritySettingForPassword()) - .isEqualTo(WifiConfiguration.KeyMgmt.NONE); - - // default for unsupported types is wpa2 - mConfig = new WifiConfiguration(); - mConfig.SSID = "test_1234"; - mConfig.preSharedKey = "short"; - when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager); - when(mWifiManager.getWifiApConfiguration()).thenReturn(mConfig); - mController = new WifiTetherPasswordPreferenceController(mContext, mListener); - - mController.displayPreference(mScreen); - assertThat(mController.getSecuritySettingForPassword()) - .isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); - } - @Test public void updateDisplay_shouldSetInputType() { // Set controller password to anything and verify is set. mController.displayPreference(mScreen); - mController.onPreferenceChange(mPreference, "1"); - assertThat(mController.getPassword()).isEqualTo("1"); + mController.onPreferenceChange(mPreference, VALID_PASS); + assertThat(mController.getPasswordValidated(WifiConfiguration.KeyMgmt.WPA2_PSK)) + .isEqualTo(VALID_PASS); // Create a new config using different password final WifiConfiguration config = new WifiConfiguration(); - config.preSharedKey = "test_1234"; + config.preSharedKey = VALID_PASS2; when(mWifiManager.getWifiApConfiguration()).thenReturn(config); // Call updateDisplay and verify it's changed. diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java new file mode 100644 index 00000000000..4108df448de --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java @@ -0,0 +1,99 @@ +package com.android.settings.wifi.tether; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class WifiTetherSecurityPreferenceControllerTest { + + private static final String WPA2_PSK = String.valueOf(WifiConfiguration.KeyMgmt.WPA2_PSK); + private static final String NONE = String.valueOf(WifiConfiguration.KeyMgmt.NONE); + @Mock + private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener; + private Context mContext; + @Mock + private ConnectivityManager mConnectivityManager; + @Mock + private WifiManager mWifiManager; + @Mock + private PreferenceScreen mScreen; + private WifiTetherSecurityPreferenceController mController; + private ListPreference mPreference; + private WifiConfiguration mConfig; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mConfig = new WifiConfiguration(); + mConfig.SSID = "test_1234"; + mConfig.preSharedKey = "test_password"; + mConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK); + mContext = spy(RuntimeEnvironment.application); + + when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager); + when(mWifiManager.getWifiApConfiguration()).thenReturn(mConfig); + when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) + .thenReturn(mConnectivityManager); + when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"1", "2"}); + when(mScreen.findPreference(anyString())).thenReturn(mPreference); + + mController = new WifiTetherSecurityPreferenceController(mContext, mListener); + mPreference = new ListPreference(RuntimeEnvironment.application); + mController.mPreference = mPreference; + } + + @Test + public void onPreferenceChange_securityValueUpdated() { + mController.onPreferenceChange(mPreference, WPA2_PSK); + assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); + assertThat(mPreference.getSummary()).isEqualTo("WPA2 PSK"); + + mController.onPreferenceChange(mPreference, NONE); + assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.NONE); + assertThat(mPreference.getSummary()).isEqualTo("None"); + } + + @Test + public void updateDisplay_preferenceUpdated() { + // test defaulting to WPA2 PSK on new config + when(mWifiManager.getWifiApConfiguration()).thenReturn(null); + mController.updateDisplay(); + assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); + assertThat(mPreference.getSummary()).isEqualTo("WPA2 PSK"); + + // test open tether network + when(mWifiManager.getWifiApConfiguration()).thenReturn(mConfig); + mConfig.allowedKeyManagement.clear(); + mConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + mController.updateDisplay(); + assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.NONE); + assertThat(mPreference.getSummary()).isEqualTo("None"); + + // test WPA2 PSK tether network + mConfig.allowedKeyManagement.clear(); + mConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK); + mController.updateDisplay(); + assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); + assertThat(mPreference.getSummary()).isEqualTo("WPA2 PSK"); + } +}