From 3940c331df2747084972d51fc095bb8e5a58ffea Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Mon, 15 Apr 2019 18:19:30 +0800 Subject: [PATCH 01/17] Add action metrics for Wi-Fi provision features // ACTION: Share a Wi-Fi network by generating a QR code ACTION_SETTINGS_SHARE_WIFI_QR_CODE // ACTION: Connect to a Wi-Fi network by scanning a QR code ACTION_SETTINGS_ENROLL_WIFI_QR_CODE // ACTION: Share Wi-Fi hotspot by generating a QR code ACTION_SETTINGS_SHARE_WIFI_HOTSPOT_QR_CODE Bug: 130521826 Test: manual Change-Id: I4204307dd5318eb7c47e4136dc7d8700d43e4da1 --- .../WifiDetailPreferenceController.java | 8 +++++++- .../wifi/dpp/WifiDppQrCodeScannerFragment.java | 7 +++++++ .../WifiTetherSSIDPreferenceController.java | 18 +++++++++++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index 5706e9be1cf..ed9c550ab96 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -889,13 +889,19 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController /** * Show QR code to share the network represented by this preference. */ - public void launchWifiDppConfiguratorActivity() { + private void launchWifiDppConfiguratorActivity() { final Intent intent = WifiDppUtils.getConfiguratorQrCodeGeneratorIntentOrNull(mContext, mWifiManager, mAccessPoint); if (intent == null) { Log.e(TAG, "Launch Wi-Fi DPP QR code generator with a wrong Wi-Fi network!"); } else { + mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN, + SettingsEnums.ACTION_SETTINGS_SHARE_WIFI_QR_CODE, + SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR, + /* key */ null, + /* value */ Integer.MIN_VALUE); + mContext.startActivity(intent); } } diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java index d0322b7f4c8..0cd7f09c2ff 100644 --- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java +++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java @@ -193,6 +193,13 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl return; } + mMetricsFeatureProvider.action( + mMetricsFeatureProvider.getAttribution(getActivity()), + SettingsEnums.ACTION_SETTINGS_ENROLL_WIFI_QR_CODE, + SettingsEnums.SETTINGS_WIFI_DPP_ENROLLEE, + /* key */ null, + /* value */ Integer.MIN_VALUE); + notifyUserForQrCodeRecognition(); break; diff --git a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java index b7ddcae8985..1197db436cd 100644 --- a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java +++ b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.wifi.tether; +import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; import android.net.wifi.WifiConfiguration; @@ -27,9 +28,12 @@ import androidx.preference.EditTextPreference; import androidx.preference.Preference; import com.android.settings.R; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.ValidatedEditTextPreference; import com.android.settings.wifi.dpp.WifiDppUtils; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; + public class WifiTetherSSIDPreferenceController extends WifiTetherBasePreferenceController implements ValidatedEditTextPreference.Validator { @@ -41,10 +45,14 @@ public class WifiTetherSSIDPreferenceController extends WifiTetherBasePreference private String mSSID; private WifiDeviceNameTextValidator mWifiDeviceNameTextValidator; + private final MetricsFeatureProvider mMetricsFeatureProvider; + public WifiTetherSSIDPreferenceController(Context context, OnTetherConfigUpdateListener listener) { super(context, listener); + mWifiDeviceNameTextValidator = new WifiDeviceNameTextValidator(); + mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); } @Override @@ -104,7 +112,15 @@ public class WifiTetherSSIDPreferenceController extends WifiTetherBasePreference } private void shareHotspotNetwork(Intent intent) { - WifiDppUtils.showLockScreen(mContext, () -> mContext.startActivity(intent)); + WifiDppUtils.showLockScreen(mContext, () -> { + mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN, + SettingsEnums.ACTION_SETTINGS_SHARE_WIFI_HOTSPOT_QR_CODE, + SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR, + /* key */ null, + /* value */ Integer.MIN_VALUE); + + mContext.startActivity(intent); + }); } @VisibleForTesting From bf627839d7ee7280b839b23947a5064138b177da Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Mon, 22 Apr 2019 11:06:16 +0800 Subject: [PATCH 02/17] Change description string of Wi-Fi add device Bug: 130825364 Test: manual Change-Id: Ic633cfa80475a438be94fabb0527c24ec9df39a9 --- res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 9c24dd34a9e..caaa6bc210c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2203,10 +2203,10 @@ Wi\u2011Fi password: %1$s Hotspot password: %1$s - + Add device - Connect to this network using a QR code + Use a QR code to add a device to this network Retry From 60013de198d928eef3682c8ba8787f880d0eb0c9 Mon Sep 17 00:00:00 2001 From: clownshen Date: Wed, 17 Apr 2019 19:33:37 +0800 Subject: [PATCH 03/17] Correct detail page UI once user change MAC randomized setting Changing MAC randomized setting will disconnect and reconnect Wi-Fi in the background automatically. UI display as disconnect even AP reconnected. Fix this problem and also remove some obsolete code. Another problem is connect button display as disabled with "Connecting..." wording after user click connect then change the MAC randomized setting. Bug: 130370187 Test: Manual test with test case in go/wifi_connnection_btn_design Test: make RunSettingsRoboTests -j32 ROBOTEST_FILTER=com.android.settings.wifi.details.WifiDetailPreferenceControllerTest Change-Id: Id87c3db0cc785a9ceb3a71c7cbb78ffd87ffb0a1 --- .../WifiDetailPreferenceController.java | 78 ++-- .../WifiDetailPreferenceControllerTest.java | 402 ++++++++++++++++++ 2 files changed, 436 insertions(+), 44 deletions(-) diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index 5706e9be1cf..7a0ad46c972 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -146,7 +146,8 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController private static final long TIMEOUT = Duration.ofSeconds(10).toMillis(); // Be static to avoid too much object not be reset. - private static CountDownTimer mTimer; + @VisibleForTesting + static CountDownTimer mTimer; private AccessPoint mAccessPoint; private final ConnectivityManager mConnectivityManager; @@ -256,20 +257,15 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController @Override public void onLost(Network network) { - final boolean lostCurrentNetwork = network.equals(mNetwork); - if (lostCurrentNetwork) { - // Should update as disconnect but not exit. Except for ephemeral network which - // should not show on saved network list. - if (!mIsEphemeral) { - return; - } - + // Ephemeral network not a saved network, leave detail page once disconnected + if (mIsEphemeral && network.equals(mNetwork)) { exitActivity(); } } }; - private final WifiTracker.WifiListener mWifiListener = new WifiTracker.WifiListener() { + @VisibleForTesting + final WifiTracker.WifiListener mWifiListener = new WifiTracker.WifiListener() { /** Called when the state of Wifi has changed. */ public void onWifiStateChanged(int state) { Log.d(TAG, "onWifiStateChanged(" + state + ")"); @@ -284,16 +280,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController /** Called when the connection state of wifi has changed. */ public void onConnectedChanged() { - updateAccessPointFromScannedList(); - if (mConnected != mAccessPoint.isActive()) { - Log.d(TAG, "Connection state changed!"); - mConnected = mAccessPoint.isActive(); - if (mAccessPoint.isActive()) { - updateConnectingState(STATE_CONNECTED); - } else { - updateConnectingState(STATE_DISCONNECTED); - } - } + refreshPage(); } /** @@ -518,42 +505,41 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController refreshMacAddress(); } - private boolean updateAccessPoint() { + @VisibleForTesting + boolean updateAccessPoint() { boolean changed = false; - if (mWifiTracker != null) { - // remember mIsOutOfRange as old before updated - boolean oldState = mIsOutOfRange; - updateAccessPointFromScannedList(); - // refresh UI if signal level changed for disconnect network. - changed = mRssiSignalLevel != mAccessPoint.getLevel(); - changed |= oldState != mIsOutOfRange; - } + // remember mIsOutOfRange as old before updated + boolean oldState = mIsOutOfRange; + updateAccessPointFromScannedList(); if (mAccessPoint.isActive()) { - // Sometimes {@link WifiManager#getCurrentNetwork()} return null after connected, - // refresh it if needed. - if (mNetwork == null) { - updateNetworkInfo(); - } + updateNetworkInfo(); mNetworkInfo = mConnectivityManager.getNetworkInfo(mNetwork); mWifiInfo = mWifiManager.getConnectionInfo(); if (mNetwork == null || mNetworkInfo == null || mWifiInfo == null) { - // Once connected, can't get mNetworkInfo immediately, return false and wait for - // next time to update UI. + // Once connected, can't get mNetwork immediately, return false and wait for + // next time to update UI. also reset {@code mIsOutOfRange} + mIsOutOfRange = oldState; return false; } - changed |= mAccessPoint.update(mWifiConfig, mWifiInfo, mNetworkInfo); - // If feature for saved network not enabled, always return true. - return mWifiTracker == null || changed; + } + + // signal level changed + changed |= mRssiSignalLevel != mAccessPoint.getLevel(); + // In/Out of range changed + changed |= oldState != mIsOutOfRange; + // connect state changed + if (mConnected != mAccessPoint.isActive()) { + mConnected = mAccessPoint.isActive(); + changed = true; + updateConnectingState(mAccessPoint.isActive() ? STATE_CONNECTED : STATE_DISCONNECTED); } return changed; } private void updateAccessPointFromScannedList() { - if (mWifiTracker == null) return; - mIsOutOfRange = true; if (mAccessPoint.getConfig() == null) { @@ -957,7 +943,8 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController return FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_DATAUSAGE_HEADER); } - private void connectNetwork() { + @VisibleForTesting + void connectNetwork() { final Activity activity = mFragment.getActivity(); // error handling, connected/saved network should have mWifiConfig. if (mWifiConfig == null) { @@ -1031,7 +1018,6 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController mAccessPoint.getTitle()), Toast.LENGTH_SHORT).show(); - updateNetworkInfo(); refreshPage(); } else if (state == STATE_NOT_IN_RANGE) { Log.d(TAG, "AP not in range"); @@ -1070,7 +1056,11 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController .setButton3Enabled(false); break; case STATE_CONNECTED: - mButtonsPref.setButton3Visible(false); + // init button state and set as invisible + mButtonsPref.setButton3Text(R.string.wifi_connect) + .setButton3Icon(R.drawable.ic_settings_wireless) + .setButton3Enabled(true) + .setButton3Visible(false); break; case STATE_DISCONNECTED: case STATE_NOT_IN_RANGE: diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java index 2acfc4a3a97..77218047de0 100644 --- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.content.pm.PackageManager; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; @@ -95,6 +96,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowToast; import java.net.Inet4Address; import java.net.InetAddress; @@ -1307,6 +1309,406 @@ public class WifiDetailPreferenceControllerTest { verify(mockButtonsPref).setButton2Visible(false); } + @Test + public void testConnectButton_shouldInvisibleForConnectNetwork() { + setUpForConnectedNetwork(); + + displayAndResume(); + + verify(mockButtonsPref, times(1)).setButton3Visible(false); + } + + @Test + public void testConnectButton_shouldVisibleForDisconnectNetwork() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + verify(mockButtonsPref, times(1)).setButton3Visible(true); + verify(mockButtonsPref, times(1)).setButton3Text(R.string.wifi_connect); + } + + private void setUpForToast() { + Resources res = mContext.getResources(); + when(mockActivity.getResources()).thenReturn(res); + } + + @Test + public void testConnectButton_clickConnect_displayAsSuccess() { + setUpForDisconnectedNetwork(); + when(mockWifiManager.isWifiEnabled()).thenReturn(true); + InOrder inOrder = inOrder(mockButtonsPref); + String label = "title"; + when(mockAccessPoint.getTitle()).thenReturn(label); + setUpForToast(); + + displayAndResume(); + + // check connect button exist + verifyConnectBtnSetUpAsVisible(inOrder); + + // click connect button + mController.connectNetwork(); + + // check display button as connecting + verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class)); + verifyConnectBtnSetUpAsConnecting(inOrder); + + // update as connected + when(mockAccessPoint.isActive()).thenReturn(true); + mController.updateAccessPoint(); + + // check connect button invisible, be init as default state and toast success message + verifyConnectBtnBeInitAsDefault(inOrder); + inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(false); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_connected_to_message, label)); + } + + @Test + public void testConnectButton_clickConnectButFailed_displayFailMessage() { + setUpForDisconnectedNetwork(); + ArgumentCaptor connectListenerCaptor = + ArgumentCaptor.forClass(WifiManager.ActionListener.class); + when(mockWifiManager.isWifiEnabled()).thenReturn(true); + InOrder inOrder = inOrder(mockButtonsPref); + setUpForToast(); + + displayAndResume(); + + // check connect button exist + verifyConnectBtnSetUpAsVisible(inOrder); + + // click connect button + mController.connectNetwork(); + + // check display button as connecting + verify(mockWifiManager, times(1)).connect(anyInt(), connectListenerCaptor.capture()); + verifyConnectBtnSetUpAsConnecting(inOrder); + + // update as failed + connectListenerCaptor.getValue().onFailure(-1); + + // check connect button visible, be init as default and toast failed message + verifyConnectBtnBeInitAsDefault(inOrder); + inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_failed_connect_message)); + } + + private void verifyConnectBtnSetUpAsVisible(InOrder inOrder) { + inOrder.verify(mockButtonsPref, times(1)).setButton3Text(R.string.wifi_connect); + inOrder.verify(mockButtonsPref, times(1)).setButton3Icon(R.drawable.ic_settings_wireless); + inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true); + } + + private void verifyConnectBtnSetUpAsConnecting(InOrder inOrder) { + inOrder.verify(mockButtonsPref, times(1)).setButton3Text(R.string.wifi_connecting); + inOrder.verify(mockButtonsPref, times(1)).setButton3Enabled(false); + } + + private void verifyConnectBtnBeInitAsDefault(InOrder inOrder) { + inOrder.verify(mockButtonsPref, times(1)).setButton3Text(R.string.wifi_connect); + inOrder.verify(mockButtonsPref, times(1)).setButton3Icon(R.drawable.ic_settings_wireless); + inOrder.verify(mockButtonsPref, times(1)).setButton3Enabled(true); + } + + @Test + public void testConnectButton_clickConnectButTimeout_displayFailMessage() { + setUpForDisconnectedNetwork(); + when(mockWifiManager.isWifiEnabled()).thenReturn(true); + InOrder inOrder = inOrder(mockButtonsPref); + setUpForToast(); + + displayAndResume(); + + // check connect button exist + verifyConnectBtnSetUpAsVisible(inOrder); + + // click connect button + mController.connectNetwork(); + + // check display button as connecting + verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class)); + verifyConnectBtnSetUpAsConnecting(inOrder); + + // update as failed + mController.mTimer.onFinish(); + + // check connect button visible, be init as default and toast failed message + verifyConnectBtnBeInitAsDefault(inOrder); + inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_failed_connect_message)); + } + + @Test + public void testConnectButton_clickConnectButTimeout_displayNotInRangeMessage() { + setUpForNotInRangeNetwork(); + when(mockWifiManager.isWifiEnabled()).thenReturn(true); + InOrder inOrder = inOrder(mockButtonsPref); + setUpForToast(); + + displayAndResume(); + + // check connect button exist + verifyConnectBtnSetUpAsVisible(inOrder); + + // click connect button + mController.connectNetwork(); + + // check display button as connecting + verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class)); + verifyConnectBtnSetUpAsConnecting(inOrder); + + // update as failed + mController.mTimer.onFinish(); + + // check connect button visible, be init as default and toast failed message + verifyConnectBtnBeInitAsDefault(inOrder); + inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_not_in_range_message)); + } + + @Test + public void testConnectButton_clickConnectWhenWiFiDisabled_displaySuccessMessage() { + setUpForDisconnectedNetwork(); + when(mockWifiManager.isWifiEnabled()).thenReturn(false); // wifi disabled + InOrder inOrder = inOrder(mockButtonsPref); + String label = "title"; + when(mockAccessPoint.getTitle()).thenReturn(label); + setUpForToast(); + + displayAndResume(); + + // check connect button exist + verifyConnectBtnSetUpAsVisible(inOrder); + + // click connect button + mController.connectNetwork(); + + // check turn on Wi-Fi, display button as connecting and toast turn on Wi-Fi message + verify(mockWifiManager, times(1)).setWifiEnabled(true); + verifyConnectBtnSetUpAsConnecting(inOrder); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_turned_on_message)); + + // notify Wi-Fi enabled + mController.mWifiListener.onWifiStateChanged(WifiManager.WIFI_STATE_ENABLED); + + // check had connect network and icon display as expected + verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class)); + verifyConnectBtnSetUpAsConnecting(inOrder); + + // update as connected + when(mockAccessPoint.isActive()).thenReturn(true); + mController.updateAccessPoint(); + + // check connect button invisible, be init as default state and toast success message + verifyConnectBtnBeInitAsDefault(inOrder); + inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(false); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_connected_to_message, label)); + } + + @Test + public void testConnectButton_clickConnectWhenWiFiDisabled_failedToConnectWiFi() { + setUpForDisconnectedNetwork(); + when(mockWifiManager.isWifiEnabled()).thenReturn(false); // wifi disabled + InOrder inOrder = inOrder(mockButtonsPref); + setUpForToast(); + + displayAndResume(); + + // check connect button exist + verifyConnectBtnSetUpAsVisible(inOrder); + + // click connect button + mController.connectNetwork(); + + // check turn on Wi-Fi, display button as connecting and toast turn on Wi-Fi message + verify(mockWifiManager, times(1)).setWifiEnabled(true); + verifyConnectBtnSetUpAsConnecting(inOrder); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_turned_on_message)); + + // notify Wi-Fi enabled + mController.mWifiListener.onWifiStateChanged(WifiManager.WIFI_STATE_ENABLED); + + // check had connect network and icon display as expected + verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class)); + verifyConnectBtnSetUpAsConnecting(inOrder); + + // update as failed + mController.mTimer.onFinish(); + + // check connect button visible, be init as default and toast failed message + verifyConnectBtnBeInitAsDefault(inOrder); + inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_failed_connect_message)); + } + + @Test + public void + testConnectButton_clickConnectWhenWiFiDisabled_failedToConnectWifiBecauseNotInRange() { + setUpForNotInRangeNetwork(); + when(mockWifiManager.isWifiEnabled()).thenReturn(false); // wifi disabled + InOrder inOrder = inOrder(mockButtonsPref); + setUpForToast(); + + displayAndResume(); + + // check connect button exist + verifyConnectBtnSetUpAsVisible(inOrder); + + // click connect button + mController.connectNetwork(); + + // check turn on Wi-Fi, display button as connecting and toast turn on Wi-Fi message + verify(mockWifiManager, times(1)).setWifiEnabled(true); + verifyConnectBtnSetUpAsConnecting(inOrder); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_turned_on_message)); + + // notify Wi-Fi enabled + mController.mWifiListener.onWifiStateChanged(WifiManager.WIFI_STATE_ENABLED); + + // check had connect network and icon display as expected + verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class)); + verifyConnectBtnSetUpAsConnecting(inOrder); + + // update as failed + mController.mTimer.onFinish(); + + // check connect button visible, be init as default and toast failed message + verifyConnectBtnBeInitAsDefault(inOrder); + inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_not_in_range_message)); + } + + @Test + public void testConnectButton_clickConnectWhenWiFiDisabled_failedToEnableWifi() { + setUpForDisconnectedNetwork(); + when(mockWifiManager.isWifiEnabled()).thenReturn(false); // wifi disabled + InOrder inOrder = inOrder(mockButtonsPref); + setUpForToast(); + + displayAndResume(); + + // check connect button exist + verifyConnectBtnSetUpAsVisible(inOrder); + + // click connect button + mController.connectNetwork(); + + // check turn on Wi-Fi, display button as connecting and toast turn on Wi-Fi message + verify(mockWifiManager, times(1)).setWifiEnabled(true); + verifyConnectBtnSetUpAsConnecting(inOrder); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_turned_on_message)); + + // notify turn on Wi-Fi failed + mController.mTimer.onFinish(); + + // check connect button visible, be init as default and toast failed message + verifyConnectBtnBeInitAsDefault(inOrder); + inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true); + assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo( + mContext.getString(R.string.wifi_failed_connect_message)); + } + + @Test + public void updateAccessPoint_returnFalseForNothingChanged() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + boolean changed = mController.updateAccessPoint(); + + assertThat(changed).isFalse(); + } + + @Test + public void updateAccessPoint_returnTrueForSignalLevelChanged() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + // Level changed + when(mockAccessPoint.getLevel()).thenReturn(LEVEL + 1); + boolean changed = mController.updateAccessPoint(); + + assertThat(changed).isTrue(); + } + + @Test + public void updateAccessPoint_returnTrueForChangeAsNotInRange() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + // change as not in range + when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(false); + boolean changed = mController.updateAccessPoint(); + + assertThat(changed).isTrue(); + } + + @Test + public void updateAccessPoint_returnTrueForChangeAsInRange() { + setUpForNotInRangeNetwork(); + + displayAndResume(); + + // change as in range + when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(true); + boolean changed = mController.updateAccessPoint(); + + assertThat(changed).isTrue(); + } + + @Test + public void updateAccessPoint_returnTrueForChangeAsConnected() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + // change as connected + when(mockAccessPoint.isActive()).thenReturn(true); + boolean changed = mController.updateAccessPoint(); + + assertThat(changed).isTrue(); + } + + @Test + public void updateAccessPoint_returnTrueForChangeAsDisconnected() { + setUpForConnectedNetwork(); + + displayAndResume(); + + // change as disconnected + when(mockAccessPoint.isActive()).thenReturn(false); + boolean changed = mController.updateAccessPoint(); + + assertThat(changed).isTrue(); + } + + @Test + public void updateAccessPoint_returnTrueForAccessPointUpdated() { + setUpForConnectedNetwork(); + + displayAndResume(); + + // change as disconnected + when(mockAccessPoint.update(mockWifiConfig, mockWifiInfo, mockNetworkInfo)) + .thenReturn(true); + boolean changed = mController.updateAccessPoint(); + + assertThat(changed).isTrue(); + } + @Test public void testRefreshRssiViews_shouldNotUpdateIfLevelIsSameForConnectedNetwork() { setUpForConnectedNetwork(); From 8b2e0a5768e6d891e36ac5b24c5f567c85594b58 Mon Sep 17 00:00:00 2001 From: Yi-Ling Chuang Date: Fri, 19 Apr 2019 19:03:46 +0800 Subject: [PATCH 04/17] Expand advanced button by default in Notifications. When users search for a certain preference hidden in advanced group in Notifications page, we should expand the advanced button so users can see the highlighted preference. Fixes: 130655529 Test: visual Change-Id: I6a166ddd1e741651d3a3a76ccfc37c58eafdf7e1 --- .../ConfigureNotificationSettings.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java index 73f6e0618e7..d9d2b9be182 100644 --- a/src/com/android/settings/notification/ConfigureNotificationSettings.java +++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java @@ -16,6 +16,8 @@ package com.android.settings.notification; +import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY; + import android.app.Activity; import android.app.Application; import android.app.settings.SettingsEnums; @@ -24,10 +26,13 @@ import android.content.Intent; import android.os.Bundle; import android.os.UserHandle; import android.provider.SearchIndexableResource; +import android.text.TextUtils; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.RingtonePreference; @@ -62,10 +67,11 @@ public class ConfigureNotificationSettings extends DashboardFragment implements static final String KEY_NOTIFICATION_ASSISTANT = "notification_assistant"; private static final String KEY_NOTI_DEFAULT_RINGTONE = "notification_default_ringtone"; - - private RingtonePreference mRequestPreference; private static final int REQUEST_CODE = 200; private static final String SELECTED_PREFERENCE_KEY = "selected_preference"; + private static final String KEY_ADVANCED_CATEGORY = "configure_notifications_advanced"; + + private RingtonePreference mRequestPreference; @Override public int getMetricsCategory() { @@ -118,6 +124,27 @@ public class ConfigureNotificationSettings extends DashboardFragment implements return controllers; } + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + final PreferenceScreen screen = getPreferenceScreen(); + final Bundle arguments = getArguments(); + + if (screen == null) { + return; + } + if (arguments != null) { + final String highlightKey = arguments.getString(EXTRA_FRAGMENT_ARG_KEY); + if (!TextUtils.isEmpty(highlightKey)) { + final PreferenceCategory advancedCategory = + screen.findPreference(KEY_ADVANCED_CATEGORY); + // Has highlight row - expand everything + advancedCategory.setInitialExpandedChildrenCount(Integer.MAX_VALUE); + scrollToPreference(advancedCategory); + } + } + } + @Override public boolean onPreferenceTreeClick(Preference preference) { if (preference instanceof RingtonePreference) { From 922b555dfbd461770930c6b766635dbdf5c5aecc Mon Sep 17 00:00:00 2001 From: clownshen Date: Mon, 22 Apr 2019 18:33:46 +0800 Subject: [PATCH 05/17] Fix WifiDetailPreferenceControllerTest failure Bug: 130896210 Test: make RunSettingsRoboTests -j32 ROBOTEST_FILTER=com.android.settings.wifi.details.WifiDetailPreferenceControllerTest Change-Id: I994fbc4a67f4c58afebb38316555f8e1442b96c0 --- .../WifiDetailPreferenceControllerTest.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java index 906c55c39f2..de23f185c26 100644 --- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java @@ -83,7 +83,6 @@ import com.android.settingslib.wifi.WifiTracker; import com.android.settingslib.wifi.WifiTrackerFactory; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -106,7 +105,6 @@ import java.util.stream.Collectors; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowDevicePolicyManager.class, ShadowEntityHeaderController.class}) -@Ignore("b/130896210") public class WifiDetailPreferenceControllerTest { private static final int LEVEL = 1; @@ -118,6 +116,7 @@ public class WifiDetailPreferenceControllerTest { private static final String RANDOMIZED_MAC_ADDRESS = "RANDOMIZED_MAC_ADDRESS"; private static final String FACTORY_MAC_ADDRESS = "FACTORY_MAC_ADDRESS"; private static final String SECURITY = "None"; + private static final String FQDN = "fqdn"; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private PreferenceScreen mockScreen; @@ -299,7 +298,7 @@ public class WifiDetailPreferenceControllerTest { list.add(mockAccessPoint); when(mockWifiTracker.getAccessPoints()).thenReturn(list); WifiTrackerFactory.setTestingWifiTracker(mockWifiTracker); - when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(true); + when(mockAccessPoint.matches(any(AccessPoint.class))).thenReturn(true); when(mockAccessPoint.isReachable()).thenReturn(true); mController = newWifiDetailPreferenceController(); @@ -311,7 +310,7 @@ public class WifiDetailPreferenceControllerTest { list.add(mockAccessPoint); when(mockWifiTracker.getAccessPoints()).thenReturn(list); WifiTrackerFactory.setTestingWifiTracker(mockWifiTracker); - when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(true); + when(mockAccessPoint.matches(any(AccessPoint.class))).thenReturn(true); when(mockAccessPoint.isReachable()).thenReturn(true); mController = newWifiDetailPreferenceController(); @@ -323,7 +322,7 @@ public class WifiDetailPreferenceControllerTest { list.add(mockAccessPoint); when(mockWifiTracker.getAccessPoints()).thenReturn(list); WifiTrackerFactory.setTestingWifiTracker(mockWifiTracker); - when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(false); + when(mockAccessPoint.matches(any(AccessPoint.class))).thenReturn(false); when(mockAccessPoint.isReachable()).thenReturn(false); mController = newWifiDetailPreferenceController(); @@ -1114,12 +1113,13 @@ public class WifiDetailPreferenceControllerTest { FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, false); mockWifiConfig.networkId = 5; - when(mockWifiConfig.isPasspoint()).thenReturn(true); + when(mockAccessPoint.isPasspoint()).thenReturn(true); + when(mockAccessPoint.getPasspointFqdn()).thenReturn(FQDN); mController.displayPreference(mockScreen); mForgetClickListener.getValue().onClick(null); - verify(mockWifiManager).removePasspointConfiguration(mockWifiConfig.FQDN); + verify(mockWifiManager).removePasspointConfiguration(FQDN); verify(mockMetricsFeatureProvider) .action(mockActivity, MetricsProto.MetricsEvent.ACTION_WIFI_FORGET); } @@ -1130,13 +1130,14 @@ public class WifiDetailPreferenceControllerTest { final WifiDetailPreferenceController spyController = spy(mController); mockWifiConfig.networkId = 5; - when(mockWifiConfig.isPasspoint()).thenReturn(true); + when(mockAccessPoint.isPasspoint()).thenReturn(true); + when(mockAccessPoint.getPasspointFqdn()).thenReturn(FQDN); spyController.displayPreference(mockScreen); FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, true); mForgetClickListener.getValue().onClick(null); - verify(mockWifiManager, times(0)).removePasspointConfiguration(mockWifiConfig.FQDN); + verify(mockWifiManager, times(0)).removePasspointConfiguration(FQDN); verify(mockMetricsFeatureProvider, times(0)) .action(mockActivity, MetricsProto.MetricsEvent.ACTION_WIFI_FORGET); verify(spyController).showConfirmForgetDialog(); From 1db16a7d4b9f9118e22fb08eaccfb540b9dd0699 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Mon, 22 Apr 2019 14:52:21 -0700 Subject: [PATCH 06/17] Using explicit Looper in Handler initialization. Bug: 130639146 Test: flash device and toggle settings Change-Id: I40d0578487c94da9fc9d940089bacbddf3a43751 --- .../development/SystemServerHeapDumpPreferenceController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/development/SystemServerHeapDumpPreferenceController.java b/src/com/android/settings/development/SystemServerHeapDumpPreferenceController.java index 599162e13f4..e6701ce248c 100644 --- a/src/com/android/settings/development/SystemServerHeapDumpPreferenceController.java +++ b/src/com/android/settings/development/SystemServerHeapDumpPreferenceController.java @@ -20,6 +20,7 @@ import android.app.ActivityManager; import android.content.Context; import android.os.Build; import android.os.Handler; +import android.os.Looper; import android.os.RemoteException; import android.os.UserManager; import android.util.Log; @@ -47,7 +48,7 @@ public class SystemServerHeapDumpPreferenceController extends DeveloperOptionsPr super(context); mUserManager = context.getSystemService(UserManager.class); - mHandler = new Handler(); + mHandler = new Handler(Looper.getMainLooper()); } @Override From 205bac7c267b9e7f68a02502a383cd87654f6e17 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Mon, 22 Apr 2019 16:27:50 -0700 Subject: [PATCH 07/17] Reduce binder call to OverlayManager (3->1) Bug: 131112014 Test: builds, manually tested Change-Id: I1f0fba30a55713be92b8755c0793ee84928f9d5e --- .../SystemNavigationPreferenceController.java | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/com/android/settings/gestures/SystemNavigationPreferenceController.java b/src/com/android/settings/gestures/SystemNavigationPreferenceController.java index 5f58fcfa559..f2c8252be39 100644 --- a/src/com/android/settings/gestures/SystemNavigationPreferenceController.java +++ b/src/com/android/settings/gestures/SystemNavigationPreferenceController.java @@ -139,12 +139,11 @@ public abstract class SystemNavigationPreferenceController extends GesturePrefer * Enables the specified overlay package. */ static void setNavBarInteractionMode(IOverlayManager overlayManager, String overlayPackage) { - setOverlayEnabled(overlayManager, NAV_BAR_MODE_3BUTTON_OVERLAY, - overlayPackage == NAV_BAR_MODE_3BUTTON_OVERLAY); - setOverlayEnabled(overlayManager, NAV_BAR_MODE_2BUTTON_OVERLAY, - overlayPackage == NAV_BAR_MODE_2BUTTON_OVERLAY); - setOverlayEnabled(overlayManager, NAV_BAR_MODE_GESTURAL_OVERLAY, - overlayPackage == NAV_BAR_MODE_GESTURAL_OVERLAY); + try { + overlayManager.setEnabledExclusiveInCategory(overlayPackage, USER_CURRENT); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } static boolean isSwipeUpEnabled(Context context) { @@ -159,12 +158,4 @@ public abstract class SystemNavigationPreferenceController extends GesturePrefer return NAV_BAR_MODE_GESTURAL == context.getResources().getInteger( com.android.internal.R.integer.config_navBarInteractionMode); } - - static void setOverlayEnabled(IOverlayManager overlayManager, String pkg, boolean enabled) { - try { - overlayManager.setEnabled(pkg, enabled, USER_CURRENT); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } } From 5c2842c1c8fc5622539710160842f4e1856eda81 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Mon, 22 Apr 2019 18:17:11 -0700 Subject: [PATCH 08/17] Update toggle layout and always show footer text Fixes: 130740123 Test: Builds Change-Id: I5f64e22ca8123c6f2825d4341d94581a301551f7 --- .../face_enroll_accessibility_toggle.xml | 71 ++++++++++++++----- res/layout/face_enroll_introduction.xml | 5 +- res/values/strings.xml | 2 + .../face/FaceEnrollIntroduction.java | 2 - 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/res/layout/face_enroll_accessibility_toggle.xml b/res/layout/face_enroll_accessibility_toggle.xml index 4dda2a76920..d37175be31f 100644 --- a/res/layout/face_enroll_accessibility_toggle.xml +++ b/res/layout/face_enroll_accessibility_toggle.xml @@ -14,33 +14,68 @@ limitations under the License. --> - - - - - + android:layout_height="wrap_content" + style="?attr/face_layout_theme"> + + + + + + + + + + + - + + + + diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml index 5107bd8b48d..3115bb4ca2f 100644 --- a/res/layout/face_enroll_introduction.xml +++ b/res/layout/face_enroll_introduction.xml @@ -77,6 +77,7 @@ +