From e668924149eff9949d636be18629f2c8ba1e1074 Mon Sep 17 00:00:00 2001 From: tmfang Date: Mon, 25 Mar 2019 11:55:19 +0800 Subject: [PATCH 01/12] Disallow Package Installer to be disabled Test: visual, robotest Fixes: 128950485 Change-Id: Id50a62fe3288761f68a3588b154db24573418068 --- res/values/config.xml | 5 ++ .../ApplicationFeatureProviderImpl.java | 20 ++++++-- .../ApplicationFeatureProviderImplTest.java | 50 +++++++++++++++++-- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index 805469a63e5..eaa2b3ee94d 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -156,6 +156,11 @@ com.android.settings.intelligence + + + com.android.packageinstaller + + diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index 55e85f93f2c..7027239f52e 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -140,9 +140,9 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide if (defaultSms != null) { keepEnabledPackages.add(defaultSms.getPackageName()); } - // Keep Settings intelligence enabled, otherwise search feature will be disabled. - keepEnabledPackages.add( - mContext.getString(R.string.config_settingsintelligence_package_name)); + + keepEnabledPackages.addAll(getEnabledPackageWhitelist()); + final LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); final String locationHistoryPackage = locationManager.getExtraLocationControllerPackage(); @@ -152,6 +152,19 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide return keepEnabledPackages; } + private Set getEnabledPackageWhitelist() { + final Set keepEnabledPackages = new ArraySet<>(); + + // Keep Settings intelligence enabled, otherwise search feature will be disabled. + keepEnabledPackages.add( + mContext.getString(R.string.config_settingsintelligence_package_name)); + + // Keep Package Installer enabled. + keepEnabledPackages.add(mContext.getString(R.string.config_package_installer_package_name)); + + return keepEnabledPackages; + } + private static class CurrentUserAndManagedProfilePolicyInstalledAppCounter extends InstalledAppCounter { private NumberOfAppsCallback mCallback; @@ -219,5 +232,4 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide mCallback.onListOfAppsResult(list); } } - } diff --git a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java index e22b29bcd0f..fcb7518c270 100644 --- a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java @@ -265,8 +265,6 @@ public final class ApplicationFeatureProviderImplTest { final String testSms = "com.android.test.defaultsms"; final String testLocationHistory = "com.android.test.location.history"; - final String settingsIntelligence = RuntimeEnvironment.application.getString( - R.string.config_settingsintelligence_package_name); ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); @@ -280,8 +278,52 @@ public final class ApplicationFeatureProviderImplTest { final Set keepEnabledPackages = mProvider.getKeepEnabledPackages(); final List expectedPackages = Arrays.asList(testDialer, testSms, - settingsIntelligence, testLocationHistory); - assertThat(keepEnabledPackages).containsExactlyElementsIn(expectedPackages); + testLocationHistory); + assertThat(keepEnabledPackages).containsAllIn(expectedPackages); + } + + @Test + @Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class}) + public void getKeepEnabledPackages_shouldContainSettingsIntelligence() { + final String testDialer = "com.android.test.defaultdialer"; + final String testSms = "com.android.test.defaultsms"; + final String testLocationHistory = "com.android.test.location.history"; + + ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); + ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); + + // Spy the real context to mock LocationManager. + Context spyContext = spy(RuntimeEnvironment.application); + when(mLocationManager.getExtraLocationControllerPackage()).thenReturn(testLocationHistory); + when(spyContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); + + ReflectionHelpers.setField(mProvider, "mContext", spyContext); + + final Set whitelist = mProvider.getKeepEnabledPackages(); + + assertThat(whitelist).contains("com.android.settings.intelligence"); + } + + @Test + @Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class}) + public void getKeepEnabledPackages_shouldContainPackageInstaller() { + final String testDialer = "com.android.test.defaultdialer"; + final String testSms = "com.android.test.defaultsms"; + final String testLocationHistory = "com.android.test.location.history"; + + ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); + ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); + + // Spy the real context to mock LocationManager. + Context spyContext = spy(RuntimeEnvironment.application); + when(mLocationManager.getExtraLocationControllerPackage()).thenReturn(testLocationHistory); + when(spyContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); + + ReflectionHelpers.setField(mProvider, "mContext", spyContext); + + final Set whitelist = mProvider.getKeepEnabledPackages(); + + assertThat(whitelist).contains("com.android.packageinstaller"); } private void setUpUsersAndInstalledApps() { From 83b814742a00f67e770ca284347272c8c47cea12 Mon Sep 17 00:00:00 2001 From: Quang Luong Date: Fri, 29 Mar 2019 15:05:21 -0700 Subject: [PATCH 02/12] Removed Write to NFC dialog Write to NFC dialog should be removed since WPS isn't supported anymore Test: atest WifiSettingsTests Bug: 112745354 Change-Id: I2bccf0b234c5f3138c48700904c2d578072e8cd6 --- res/values/strings.xml | 22 -- .../android/settings/wifi/WifiSettings.java | 41 --- .../wifi/WriteWifiConfigToNfcDialog.java | 287 ------------------ .../wifi/WriteWifiConfigToNfcDialogTest.java | 90 ------ 4 files changed, 440 deletions(-) delete mode 100644 src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java delete mode 100644 tests/robotests/src/com/android/settings/wifi/WriteWifiConfigToNfcDialogTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index b27e9d0e24d..323edd1dd6e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2023,8 +2023,6 @@ Forget network Modify network - - Write to NFC tag To see available networks, turn Wi\u2011Fi on. @@ -2210,8 +2208,6 @@ \u0020(WPS available) - - Enter your network password Carrier Wi\u2011Fi network @@ -7283,24 +7279,6 @@ battery saver, sticky, persist, power saver, battery - - - - - Set up Wi-Fi NFC Tag - - Write - - Tap a tag to write... - - Invalid password, try again. - - Success! - - Unable to write data to NFC tag. If the problem persists, try a different tag - - NFC tag is not writable. Please use a different tag. - Default sound diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 91672104e45..4e5b13894c0 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -35,7 +35,6 @@ import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; -import android.nfc.NfcAdapter; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -100,10 +99,8 @@ 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; public static final int WIFI_DIALOG_ID = 1; - private static final int WRITE_NFC_DIALOG_ID = 6; @VisibleForTesting static final int ADD_NETWORK_REQUEST = 2; @@ -111,7 +108,6 @@ public class WifiSettings extends RestrictedSettingsFragment // Instance state keys private static final String SAVE_DIALOG_MODE = "dialog_mode"; private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state"; - private static final String SAVED_WIFI_NFC_DIALOG_STATE = "wifi_nfc_dlg_state"; private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list"; private static final String PREF_KEY_CONNECTED_ACCESS_POINTS = "connected_access_point"; @@ -152,7 +148,6 @@ public class WifiSettings extends RestrictedSettingsFragment private AccessPoint mSelectedAccessPoint; private WifiDialog mDialog; - private WriteWifiConfigToNfcDialog mWifiToNfcDialog; private View mProgressHeader; @@ -171,7 +166,6 @@ public class WifiSettings extends RestrictedSettingsFragment private int mDialogMode; private AccessPoint mDlgAccessPoint; private Bundle mAccessPointSavedState; - private Bundle mWifiNfcDialogSavedState; @VisibleForTesting WifiTracker mWifiTracker; @@ -312,11 +306,6 @@ public class WifiSettings extends RestrictedSettingsFragment mAccessPointSavedState = savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE); } - - if (savedInstanceState.containsKey(SAVED_WIFI_NFC_DIALOG_STATE)) { - mWifiNfcDialogSavedState = - savedInstanceState.getBundle(SAVED_WIFI_NFC_DIALOG_STATE); - } } // if we're supposed to enable/disable the Next button based on our current connection @@ -461,12 +450,6 @@ public class WifiSettings extends RestrictedSettingsFragment outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState); } } - - if (mWifiToNfcDialog != null) { - Bundle savedState = new Bundle(); - mWifiToNfcDialog.saveState(savedState); - outState.putBundle(SAVED_WIFI_NFC_DIALOG_STATE, savedState); - } } @Override @@ -495,13 +478,6 @@ public class WifiSettings extends RestrictedSettingsFragment } if (mSelectedAccessPoint.isSaved()) { menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify); - NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity()); - if (nfcAdapter != null && nfcAdapter.isEnabled() && - (!(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) || - (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE))) { - // Only allow writing of NFC tags for password-protected networks. - menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc); - } } } } @@ -534,10 +510,6 @@ public class WifiSettings extends RestrictedSettingsFragment showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_MODIFY); return true; } - case MENU_ID_WRITE_NFC: - showDialog(WRITE_NFC_DIALOG_ID); - return true; - } return super.onContextItemSelected(item); } @@ -626,16 +598,6 @@ public class WifiSettings extends RestrictedSettingsFragment .createModal(getActivity(), this, mDlgAccessPoint, mDialogMode); mSelectedAccessPoint = mDlgAccessPoint; return mDialog; - case WRITE_NFC_DIALOG_ID: - if (mSelectedAccessPoint != null) { - mWifiToNfcDialog = new WriteWifiConfigToNfcDialog( - getActivity(), - mSelectedAccessPoint.getSecurity()); - } else if (mWifiNfcDialogSavedState != null) { - mWifiToNfcDialog = new WriteWifiConfigToNfcDialog(getActivity(), - mWifiNfcDialogSavedState); - } - return mWifiToNfcDialog; } return super.onCreateDialog(dialogId); } @@ -650,7 +612,6 @@ public class WifiSettings extends RestrictedSettingsFragment public void onDismiss(DialogInterface dialog) { // We don't keep any dialog object when dialog was dismissed. mDialog = null; - mWifiToNfcDialog = null; } @Override @@ -658,8 +619,6 @@ public class WifiSettings extends RestrictedSettingsFragment switch (dialogId) { case WIFI_DIALOG_ID: return SettingsEnums.DIALOG_WIFI_AP_EDIT; - case WRITE_NFC_DIALOG_ID: - return SettingsEnums.DIALOG_WIFI_WRITE_NFC; default: return 0; } diff --git a/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java b/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java deleted file mode 100644 index b56eca60307..00000000000 --- a/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.wifi; - -import android.app.Activity; -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.PowerManager; -import android.text.Editable; -import android.text.InputType; -import android.text.TextWatcher; -import android.util.Log; -import android.view.View; -import android.view.inputmethod.InputMethodManager; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.ProgressBar; -import android.widget.TextView; - -import androidx.appcompat.app.AlertDialog; - -import com.android.settings.R; -import com.android.settingslib.wifi.AccessPoint; - -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 static final int HEX_RADIX = 16; - private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); - private static final String SECURITY = "security"; - - private final PowerManager.WakeLock mWakeLock; - - private View mView; - private Button mSubmitButton; - private Button mCancelButton; - private TextView mPasswordView; - private TextView mLabelView; - private CheckBox mPasswordCheckBox; - private ProgressBar mProgressBar; - private WifiManager mWifiManager; - private String mWpsNfcConfigurationToken; - private Context mContext; - private int mSecurity; - - WriteWifiConfigToNfcDialog(Context context, int security) { - super(context); - - mContext = context; - mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)) - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WriteWifiConfigToNfcDialog:wakeLock"); - mSecurity = security; - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - } - - WriteWifiConfigToNfcDialog(Context context, Bundle savedState) { - super(context); - - mContext = context; - mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)) - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WriteWifiConfigToNfcDialog:wakeLock"); - mSecurity = savedState.getInt(SECURITY); - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - mView = getLayoutInflater().inflate(R.layout.write_wifi_config_to_nfc, null); - - setView(mView); - 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 = mView.findViewById(R.id.password); - mLabelView = mView.findViewById(R.id.password_label); - mPasswordView.addTextChangedListener(this); - mPasswordCheckBox = mView.findViewById(R.id.show_password); - mPasswordCheckBox.setOnCheckedChangeListener(this); - mProgressBar = 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.getCurrentNetworkWpsNfcConfigurationToken(); - String passwordHex = byteArrayToHexString(password.getBytes()); - - String passwordLength = password.length() >= HEX_RADIX - ? Integer.toString(password.length(), HEX_RADIX) - : "0" + Character.forDigit(password.length(), HEX_RADIX); - - passwordHex = String.format(PASSWORD_FORMAT, passwordLength, passwordHex).toLowerCase(); - - if (wpsNfcConfigurationToken != null && 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); - } - } - - public void saveState(Bundle state) { - state.putInt(SECURITY, mSecurity); - } - - 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 Wi-Fi config to NFC tag.", e); - return; - } catch (FormatException e) { - setViewText(mLabelView, R.string.status_failed_to_write); - Log.e(TAG, "Unable to write Wi-Fi 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) { - enableSubmitIfAppropriate(); - } - - private void enableSubmitIfAppropriate() { - - if (mPasswordView != null) { - if (mSecurity == AccessPoint.SECURITY_WEP) { - mSubmitButton.setEnabled(mPasswordView.length() > 0); - } else if (mSecurity == 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), HEX_RADIX) << 4) - + Character.digit(s.charAt(i + 1), HEX_RADIX)); - } - - return data; - } - - 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) {} -} diff --git a/tests/robotests/src/com/android/settings/wifi/WriteWifiConfigToNfcDialogTest.java b/tests/robotests/src/com/android/settings/wifi/WriteWifiConfigToNfcDialogTest.java deleted file mode 100644 index ea306d0c055..00000000000 --- a/tests/robotests/src/com/android/settings/wifi/WriteWifiConfigToNfcDialogTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.settings.wifi; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; - -import android.app.Activity; -import android.net.wifi.WifiManager; - -import com.android.settings.testutils.shadow.ShadowNfcAdapter; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.util.ReflectionHelpers; - -@RunWith(RobolectricTestRunner.class) -@Config(shadows = ShadowNfcAdapter.class) -public class WriteWifiConfigToNfcDialogTest { - - @Mock - private WifiManager mWifiManager; - - private WriteWifiConfigToNfcDialog mWriteWifiConfigToNfcDialog; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - final Activity activity = Robolectric.setupActivity(Activity.class); - mWriteWifiConfigToNfcDialog = new WriteWifiConfigToNfcDialog(activity, 0 /* security */); - ReflectionHelpers.setField(mWriteWifiConfigToNfcDialog, "mWifiManager", mWifiManager); - mWriteWifiConfigToNfcDialog.setOwnerActivity(activity); - mWriteWifiConfigToNfcDialog.onCreate(null /* savedInstanceState */); - } - - @After - public void tearDown() { - ShadowNfcAdapter.reset(); - } - - @Test - public void testOnClick_nfcConfigurationTokenDoesNotContainPasswordHex() { - when(mWifiManager.getCurrentNetworkWpsNfcConfigurationToken()).thenReturn("blah"); - - mWriteWifiConfigToNfcDialog.onClick(null); - - assertThat(ShadowNfcAdapter.isReaderModeEnabled()).isFalse(); - } - - @Test - public void testOnClick_nfcConfigurationTokenIsNull() { - when(mWifiManager.getCurrentNetworkWpsNfcConfigurationToken()).thenReturn(null); - - mWriteWifiConfigToNfcDialog.onClick(null); - - assertThat(ShadowNfcAdapter.isReaderModeEnabled()).isFalse(); - } - - @Test - public void testOnClick_nfcConfigurationTokenContainsPasswordHex() { - // This is the corresponding passwordHex for an empty string password. - when(mWifiManager.getCurrentNetworkWpsNfcConfigurationToken()).thenReturn("10270000"); - - mWriteWifiConfigToNfcDialog.onClick(null); - - assertThat(ShadowNfcAdapter.isReaderModeEnabled()).isTrue(); - } -} From 24827d35b1af3523a98f1d24e09945e623ca8f16 Mon Sep 17 00:00:00 2001 From: clownshen Date: Fri, 29 Mar 2019 20:22:02 +0800 Subject: [PATCH 03/12] Enlarge wifi signal icon from 24dp to 32dp for header view Bug: 129413562 Test: manual test Change-Id: I50a27ac25e5ae42530736bb7c019485a51d707ba --- res/values/dimens.xml | 1 + src/com/android/settings/Utils.java | 5 +++- .../WifiDetailPreferenceController.java | 25 +++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 60724c31fbb..7d5ca662e1d 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -176,6 +176,7 @@ 1px 16dp + 32dp 16dp diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 36230d17dca..0938c0978e3 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -977,7 +977,10 @@ public final class Utils extends com.android.settingslib.Utils { return IconCompat.createWithBitmap(bitmap); } - private static Bitmap createBitmap(Drawable drawable, int width, int height) { + /** + * Creates a drawable with specified width and height. + */ + public static Bitmap createBitmap(Drawable drawable, int width, int height) { final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index 92132e82d7c..eb67870d6e1 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -27,7 +27,10 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.VectorDrawable; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.LinkAddress; @@ -595,8 +598,9 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController wifiIcon.setTintList(Utils.getColorAccent(mContext)); if (mEntityHeaderController != null) { - mEntityHeaderController.setIcon(wifiIcon).done(mFragment.getActivity(), - true /* rebind */); + mEntityHeaderController + .setIcon(rescaleIconForHeader(wifiIcon)).done(mFragment.getActivity(), + true /* rebind */); } Drawable wifiIconDark = wifiIcon.getConstantState().newDrawable().mutate(); @@ -607,6 +611,23 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController mSignalStrengthPref.setVisible(true); } + private Drawable rescaleIconForHeader(Drawable original) { + final int iconSize = mContext.getResources().getDimensionPixelSize( + R.dimen.wifi_detail_page_header_image_size); + final int actualWidth = original.getMinimumWidth(); + final int actualHeight = original.getMinimumHeight(); + + if ((actualWidth == iconSize && actualHeight == iconSize) + || !VectorDrawable.class.isInstance(original)) { + return original; + } + + final Bitmap bitmap = Utils.createBitmap(original, + iconSize /*width*/, + iconSize /*height*/); + return new BitmapDrawable(null /*resource*/, bitmap); + } + private void refreshFrequency() { if (mWifiInfo == null) { mFrequencyPref.setVisible(false); From 36948cefe9ee5991a261e31fe77dfc47696bd39c Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Fri, 29 Mar 2019 15:00:07 -0700 Subject: [PATCH 04/12] Remove unnecessary notify in BT preference notifyHierarchyChanged() is used before when we have connected/disconnect deivce in same list. So only use it in DevicePickerFragment.java, not other normal fragments. Also that call will rebuild whole preference list, which is heavy. Bug: 119479725 Test: Manual Change-Id: I06cf221588001b38634fec9f02dee8bc1e561ea8 --- .../settings/bluetooth/BluetoothDevicePreference.java | 11 ++++++++--- .../bluetooth/DeviceListPreferenceFragment.java | 11 ++++------- .../settings/bluetooth/DevicePickerFragment.java | 6 ++++++ .../bluetooth/BluetoothDevicePreferenceTest.java | 11 +++++++++-- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java index 4a7ca27c178..85075fd5335 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java @@ -31,6 +31,7 @@ import android.util.Pair; import android.util.TypedValue; import android.widget.ImageView; +import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.AlertDialog; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; @@ -58,6 +59,8 @@ public final class BluetoothDevicePreference extends GearPreference implements private AlertDialog mDisconnectDialog; private String contentDescription = null; private boolean mHideSecondTarget = false; + @VisibleForTesting + boolean mNeedNotifyHierarchyChanged = false; /* Talk-back descriptions for various BT icons */ Resources mResources; @@ -80,8 +83,8 @@ public final class BluetoothDevicePreference extends GearPreference implements onDeviceAttributesChanged(); } - void rebind() { - notifyChanged(); + public void setNeedNotifyHierarchyChanged(boolean needNotifyHierarchyChanged) { + mNeedNotifyHierarchyChanged = needNotifyHierarchyChanged; } @Override @@ -144,7 +147,9 @@ public final class BluetoothDevicePreference extends GearPreference implements setVisible(mShowDevicesWithoutNames || mCachedDevice.hasHumanReadableName()); // This could affect ordering, so notify that - notifyHierarchyChanged(); + if (mNeedNotifyHierarchyChanged) { + notifyHierarchyChanged(); + } } @Override diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java index 385b5d9716c..4f27a39f9c0 100644 --- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java @@ -36,6 +36,7 @@ import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.util.Collection; +import java.util.HashMap; import java.util.WeakHashMap; /** @@ -69,8 +70,8 @@ public abstract class DeviceListPreferenceFragment extends @VisibleForTesting PreferenceGroup mDeviceListGroup; - final WeakHashMap mDevicePreferenceMap = - new WeakHashMap(); + final HashMap mDevicePreferenceMap = + new HashMap<>(); boolean mShowDevicesWithoutNames; @@ -195,17 +196,13 @@ public abstract class DeviceListPreferenceFragment extends //Set hideSecondTarget is true if it's bonded device. preference.hideSecondTarget(true); mDeviceListGroup.addPreference(preference); - } else { - // Tell the preference it is being re-used in case there is new info in the - // cached device. - preference.rebind(); } initDevicePreference(preference); mDevicePreferenceMap.put(cachedDevice, preference); } - void initDevicePreference(BluetoothDevicePreference preference) { + protected void initDevicePreference(BluetoothDevicePreference preference) { // Does nothing by default } diff --git a/src/com/android/settings/bluetooth/DevicePickerFragment.java b/src/com/android/settings/bluetooth/DevicePickerFragment.java index 207b375cd36..02625bbad2b 100644 --- a/src/com/android/settings/bluetooth/DevicePickerFragment.java +++ b/src/com/android/settings/bluetooth/DevicePickerFragment.java @@ -151,6 +151,12 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment { } } + @Override + protected void initDevicePreference(BluetoothDevicePreference preference) { + super.initDevicePreference(preference); + preference.setNeedNotifyHierarchyChanged(true); + } + @Override public void onBluetoothStateChanged(int bluetoothState) { super.onBluetoothStateChanged(bluetoothState); diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java index 56d17f490e8..92f2354f5fd 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java @@ -166,7 +166,7 @@ public class BluetoothDevicePreferenceTest { } @Test - public void testVisible_showDeviceWithoutNames_visible() { + public void isVisible_showDeviceWithoutNames_visible() { doReturn(false).when(mCachedBluetoothDevice).hasHumanReadableName(); BluetoothDevicePreference preference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, @@ -176,11 +176,18 @@ public class BluetoothDevicePreferenceTest { } @Test - public void testVisible_hideDeviceWithoutNames_invisible() { + public void isVisible_hideDeviceWithoutNames_invisible() { doReturn(false).when(mCachedBluetoothDevice).hasHumanReadableName(); BluetoothDevicePreference preference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, false); assertThat(preference.isVisible()).isFalse(); } + + @Test + public void setNeedNotifyHierarchyChanged_updateValue() { + mPreference.setNeedNotifyHierarchyChanged(true); + + assertThat(mPreference.mNeedNotifyHierarchyChanged).isTrue(); + } } From ec20de3ebae1df855356fd3d2f8d8b53bc4dbc55 Mon Sep 17 00:00:00 2001 From: Hao Zhang Date: Tue, 28 Aug 2018 19:20:21 +0900 Subject: [PATCH 05/12] Show the disclaimer for WFC emergency call limitation The emergency calls might not work properly via wifi calling, especially in areas with no 2G/3G coverage. Display the disclaimer for the this limitation when a user enabled the wifi calling setting. Test: manual - Checked that the disclaimer for emergency call limitation is shown when changing wifi calling setting to turned on. Test: auto - Passed EmergencyCallLimitationDisclaimerTest. Bug: 68115846 Change-Id: I881d479c1e02525ac614c66594637a5e0347d70c --- res/values/strings.xml | 6 + .../wifi/calling/DisclaimerItemFactory.java | 1 + .../EmergencyCallLimitationDisclaimer.java | 86 +++++++++++++ ...EmergencyCallLimitationDisclaimerTest.java | 118 ++++++++++++++++++ 4 files changed, 211 insertions(+) create mode 100644 src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimer.java create mode 100644 tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index b27e9d0e24d..41f5f960c5a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11035,4 +11035,10 @@ Disconnect + + + Emergency calls + + + Emergency calls over Wi\u2011Fi Calling are not supported by your carrier.\nThe device switches automatically to a cellular network to place an emergency call.\nEmergency calls are only possible in areas with cellular coverage. diff --git a/src/com/android/settings/wifi/calling/DisclaimerItemFactory.java b/src/com/android/settings/wifi/calling/DisclaimerItemFactory.java index e3994aa0e44..8559636aa7a 100644 --- a/src/com/android/settings/wifi/calling/DisclaimerItemFactory.java +++ b/src/com/android/settings/wifi/calling/DisclaimerItemFactory.java @@ -52,6 +52,7 @@ public final class DisclaimerItemFactory { private static List getDisclaimerItemList(Context context, int subId) { List itemList = new ArrayList(); itemList.add(new LocationPolicyDisclaimer(context, subId)); + itemList.add(new EmergencyCallLimitationDisclaimer(context, subId)); return itemList; } diff --git a/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimer.java b/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimer.java new file mode 100644 index 00000000000..c044275ff52 --- /dev/null +++ b/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimer.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.wifi.calling; + +import android.content.Context; +import android.telephony.CarrierConfigManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.R; + +/** + * Disclaimer item class for displaying emergency call limitation UI on + * {@link WifiCallingDisclaimerFragment}. + */ +public class EmergencyCallLimitationDisclaimer extends DisclaimerItem { + private static final String DISCLAIMER_ITEM_NAME = "EmergencyCallLimitationDisclaimer"; + @VisibleForTesting + static final String KEY_HAS_AGREED_EMERGENCY_LIMITATION_DISCLAIMER = + "key_has_agreed_emergency_limitation_disclaimer"; + private static final int UNINITIALIZED_DELAY_VALUE = -1; + + public EmergencyCallLimitationDisclaimer(Context context, int subId) { + super(context, subId); + } + + /** + * {@inheritDoc} + */ + @Override + boolean shouldShow() { + final int notificationDelay = getCarrierConfig().getInt( + CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT); + if (notificationDelay == UNINITIALIZED_DELAY_VALUE) { + logd("shouldShow: false due to carrier config is default(-1)."); + return false; + } + + return super.shouldShow(); + } + + /** + * {@inheritDoc} + */ + @Override + protected String getName() { + return DISCLAIMER_ITEM_NAME; + } + + /** + * {@inheritDoc} + */ + @Override + protected int getTitleId() { + return R.string.wfc_disclaimer_emergency_limitation_title_text; + } + + /** + * {@inheritDoc} + */ + @Override + protected int getMessageId() { + return R.string.wfc_disclaimer_emergency_limitation_desc_text; + } + + /** + * {@inheritDoc} + */ + @Override + protected String getPrefKey() { + return KEY_HAS_AGREED_EMERGENCY_LIMITATION_DISCLAIMER; + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java b/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java new file mode 100644 index 00000000000..ce803245ab2 --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.wifi.calling; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; + +import com.android.settings.R; + +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class EmergencyCallLimitationDisclaimerTest { + private static final String TEST_SHARED_PREFERENCE = "test_wfc_disclaimer_prefs"; + private static final int TEST_SUB_ID = 0; + + @Mock + private CarrierConfigManager mCarrierConfigManager; + + private final PersistableBundle mBundle = new PersistableBundle(); + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + + doReturn(mCarrierConfigManager).when(mContext).getSystemService( + Context.CARRIER_CONFIG_SERVICE); + when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle); + + doReturn(getSharedPreferences()).when(mContext).getSharedPreferences(anyString(), anyInt()); + } + + @Test + public void sholdShow_delay1000msec_shouldShowEmergencyCallLimitationDisclaimer() { + EmergencyCallLimitationDisclaimer disclaimerItem = + spy(new EmergencyCallLimitationDisclaimer(mContext, TEST_SUB_ID)); + mBundle.putInt(CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT, 1000); + getSharedPreferences().edit().putBoolean( + EmergencyCallLimitationDisclaimer.KEY_HAS_AGREED_EMERGENCY_LIMITATION_DISCLAIMER + + TEST_SUB_ID, false).commit(); + + // Check the WFC disclaimer item is should be shown. + assertThat(disclaimerItem.shouldShow()).isTrue(); + } + + @Test + public void sholdShow_delayDefault_shouldNotShowEmergencyCallLimitationDisclaimer() { + EmergencyCallLimitationDisclaimer disclaimerItem = new EmergencyCallLimitationDisclaimer( + mContext, TEST_SUB_ID); + mBundle.putInt(CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT, -1); + + // Check the WFC disclaimer item is should not be shown due to the + // KEY_EMERGENCY_NOTIFICATION_DELAY_INT on carrier config is default(-1). + assertThat(disclaimerItem.shouldShow()).isFalse(); + } + + @Test + public void sholdShow_alreadyAgreed_shouldNotShowEmergencyCallLimitationDisclaimer() { + EmergencyCallLimitationDisclaimer disclaimerItem = + spy(new EmergencyCallLimitationDisclaimer(mContext, TEST_SUB_ID)); + mBundle.putInt(CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT, 10); + getSharedPreferences().edit().putBoolean( + EmergencyCallLimitationDisclaimer.KEY_HAS_AGREED_EMERGENCY_LIMITATION_DISCLAIMER + + TEST_SUB_ID, true).commit(); + + // Check the WFC disclaimer item is should not be shown due to an item is already agreed. + assertThat(disclaimerItem.shouldShow()).isFalse(); + } + + @Test + public void onAgreed_shouldSetSharedPreferencesToAgreed() { + EmergencyCallLimitationDisclaimer disclaimerItem = + spy(new EmergencyCallLimitationDisclaimer(mContext, TEST_SUB_ID)); + + disclaimerItem.onAgreed(); + + // Check the SharedPreferences key is changed to agreed. + assertThat(getSharedPreferences().getBoolean( + EmergencyCallLimitationDisclaimer.KEY_HAS_AGREED_EMERGENCY_LIMITATION_DISCLAIMER + + TEST_SUB_ID, false)).isTrue(); + } + + private SharedPreferences getSharedPreferences() { + return mContext.getSharedPreferences(TEST_SHARED_PREFERENCE, Context.MODE_PRIVATE); + } +} From 2dceec7661b0dbbcfac5f06689876146be8981b1 Mon Sep 17 00:00:00 2001 From: tonyzhu Date: Thu, 28 Mar 2019 20:07:18 +0800 Subject: [PATCH 06/12] Control VoLTE toggle names by "show_4g_for_lte_data_icon_bool". Using "show_4g_for_lte_data_icon_bool" to control VoLTE toggle names, making sure strings can be correspond to the icon. Bug: 128325427 Test: Use commands to override carrier config to observe the UI as expected. Test: atest pass. Change-Id: I41dd28eb2c14d385a8396c551bf5ef2cf9258997 --- .../Enhanced4gLtePreferenceController.java | 26 ++++++------ ...Enhanced4gLtePreferenceControllerTest.java | 41 +++++++++++++++++-- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceController.java b/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceController.java index 161c2187a28..ca45a328bad 100644 --- a/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceController.java +++ b/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceController.java @@ -17,7 +17,6 @@ package com.android.settings.network.telephony; import android.content.Context; -import android.content.res.Resources; import android.os.Looper; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -56,6 +55,10 @@ public class Enhanced4gLtePreferenceController extends TelephonyTogglePreference private final CharSequence[] mVariantTitles; private final CharSequence[] mVariantSumaries; + private final int VARIANT_TITLE_VOLTE = 0; + private final int VARIANT_TITLE_ADVANCED_CALL = 1; + private final int VARIANT_TITLE_4G_CALLING = 2; + public Enhanced4gLtePreferenceController(Context context, String key) { super(context, key); mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); @@ -101,20 +104,17 @@ public class Enhanced4gLtePreferenceController extends TelephonyTogglePreference public void updateState(Preference preference) { super.updateState(preference); final SwitchPreference switchPreference = (SwitchPreference) preference; - final int variant4glteTitleIndex = mCarrierConfig.getInt( - CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT); + final boolean show4GForLTE = mCarrierConfig.getBoolean( + CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL); + int variant4glteTitleIndex = mCarrierConfig.getInt( + CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT); - // Default index 0 indicates the default title/sumary string - CharSequence enhanced4glteModeTitle = mVariantTitles[0]; - CharSequence enhanced4glteModeSummary = mVariantSumaries[0]; - if (variant4glteTitleIndex >= 0 && variant4glteTitleIndex < mVariantTitles.length) { - enhanced4glteModeTitle = mVariantTitles[variant4glteTitleIndex]; + if (variant4glteTitleIndex != VARIANT_TITLE_ADVANCED_CALL) { + variant4glteTitleIndex = show4GForLTE ? VARIANT_TITLE_4G_CALLING : VARIANT_TITLE_VOLTE; } - if (variant4glteTitleIndex >= 0 && variant4glteTitleIndex < mVariantSumaries.length) { - enhanced4glteModeSummary = mVariantSumaries[variant4glteTitleIndex]; - } - switchPreference.setTitle(enhanced4glteModeTitle); - switchPreference.setSummary(enhanced4glteModeSummary); + + switchPreference.setTitle(mVariantTitles[variant4glteTitleIndex]); + switchPreference.setSummary(mVariantSumaries[variant4glteTitleIndex]); switchPreference.setEnabled(is4gLtePrefEnabled()); switchPreference.setChecked(mImsManager.isEnhanced4gLteModeSettingEnabledByUser() && mImsManager.isNonTtyOrTtyOnVolteEnabled()); diff --git a/tests/robotests/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceControllerTest.java index 9957cde89ed..bea8f679604 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceControllerTest.java @@ -102,20 +102,34 @@ public class Enhanced4gLtePreferenceControllerTest { } @Test - public void updateState_variant4gLte_useVariantTitleAndSummary() { + public void updateState_doNotShow4GForLTE_showVolteTitleAndSummary() { + mCarrierConfig.putBoolean(CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false); + mCarrierConfig.putInt(CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, 0); mController.updateState(mPreference); assertThat(mPreference.getTitle()).isEqualTo( - mContext.getString(R.string.enhanced_4g_lte_mode_title)); + mContext.getString(R.string.enhanced_4g_lte_mode_title)); assertThat(mPreference.getSummary()).isEqualTo( mContext.getString(R.string.enhanced_4g_lte_mode_summary)); - mCarrierConfig.putInt(CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, 1); + mCarrierConfig.putInt(CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, 2); mController.updateState(mPreference); assertThat(mPreference.getTitle()).isEqualTo( - mContext.getString(R.string.enhanced_4g_lte_mode_title_advanced_calling)); + mContext.getString(R.string.enhanced_4g_lte_mode_title)); assertThat(mPreference.getSummary()).isEqualTo( mContext.getString(R.string.enhanced_4g_lte_mode_summary)); + } + + @Test + public void updateState_show4GForLTE_show4GTitleAndSummary() { + mCarrierConfig.putBoolean(CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, true); + + mCarrierConfig.putInt(CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, 0); + mController.updateState(mPreference); + assertThat(mPreference.getTitle()).isEqualTo( + mContext.getString(R.string.enhanced_4g_lte_mode_title_4g_calling)); + assertThat(mPreference.getSummary()).isEqualTo( + mContext.getString(R.string.enhanced_4g_lte_mode_summary_4g_calling)); mCarrierConfig.putInt(CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, 2); mController.updateState(mPreference); @@ -125,6 +139,25 @@ public class Enhanced4gLtePreferenceControllerTest { mContext.getString(R.string.enhanced_4g_lte_mode_summary_4g_calling)); } + @Test + public void updateState_variantAdvancedCalling_showAdvancedCallingTitleAndSummary() { + mCarrierConfig.putInt(CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, 1); + + mCarrierConfig.putBoolean(CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false); + mController.updateState(mPreference); + assertThat(mPreference.getTitle()).isEqualTo( + mContext.getString(R.string.enhanced_4g_lte_mode_title_advanced_calling)); + assertThat(mPreference.getSummary()).isEqualTo( + mContext.getString(R.string.enhanced_4g_lte_mode_summary)); + + mCarrierConfig.putBoolean(CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, true); + mController.updateState(mPreference); + assertThat(mPreference.getTitle()).isEqualTo( + mContext.getString(R.string.enhanced_4g_lte_mode_title_advanced_calling)); + assertThat(mPreference.getSummary()).isEqualTo( + mContext.getString(R.string.enhanced_4g_lte_mode_summary)); + } + @Test public void updateState_configEnabled_prefEnabled() { mPreference.setEnabled(false); From b5ab562c128d3899456f3ba0dee1918f0eccc964 Mon Sep 17 00:00:00 2001 From: clownshen Date: Fri, 29 Mar 2019 14:20:32 +0800 Subject: [PATCH 07/12] Update state as disconnected when Wi-Fi disabled Connect button display wrong string "Connecting..." and be disabled when Wi-Fi turned off at quick setting. Update state as disconnected when Wi-Fi disabled to fix this issue. Bug: 129514552 Test: manual test Change-Id: I76a247ce0ed951357172e67221281b004df386d8 --- .../settings/wifi/details/WifiDetailPreferenceController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index 92132e82d7c..8d90470ce10 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -271,6 +271,10 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController Log.d(TAG, "onWifiStateChanged(" + state + ")"); if (mConnectingState == STATE_ENABLE_WIFI && state == WifiManager.WIFI_STATE_ENABLED) { updateConnectingState(STATE_CONNECTING); + } else if (mConnectingState != STATE_NONE && state == WifiManager.WIFI_STATE_DISABLED) { + // update as disconnected once Wi-Fi disabled since may not received + // onConnectedChanged for this case. + updateConnectingState(STATE_DISCONNECTED); } } From 38f4acf77f3854e8a0cddb48648c1acbbd90e779 Mon Sep 17 00:00:00 2001 From: clownshen Date: Fri, 29 Mar 2019 15:27:03 +0800 Subject: [PATCH 08/12] Add test cases for disconnected/not in range network Since detail page support to display for saved network which connection state may be disconnected or not in range, add more test cases for this new change. Bug: 124707751 Test: atest WifiDetailPreferenceControllerTest passed Change-Id: Ia6426ed6336c09f387317c5597f8deb14c1a9502 --- .../WifiDetailPreferenceController.java | 4 +- .../WifiDetailPreferenceControllerTest.java | 458 +++++++++++++++++- 2 files changed, 460 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index 92132e82d7c..44fb3216504 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -103,6 +103,8 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController @VisibleForTesting static final String KEY_HEADER = "connection_header"; @VisibleForTesting + static final String KEY_DATA_USAGE_HEADER = "status_header"; + @VisibleForTesting static final String KEY_BUTTONS_PREF = "buttons"; @VisibleForTesting static final String KEY_SIGNAL_STRENGTH_PREF = "signal_strength"; @@ -426,7 +428,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController if (usingDataUsageHeader(mContext)) { headerPref.setVisible(false); - mDataUsageSummaryPref = screen.findPreference("status_header"); + mDataUsageSummaryPref = screen.findPreference(KEY_DATA_USAGE_HEADER); mDataUsageSummaryPref.setVisible(true); mSummaryHeaderController = new WifiDataUsageSummaryPreferenceController(mFragment.getActivity(), 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 f177b5ea87a..307712e686b 100644 --- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java @@ -43,6 +43,7 @@ import android.net.ConnectivityManager.NetworkCallback; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.MacAddress; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; @@ -76,6 +77,8 @@ import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.widget.ActionButtonsPreference; import com.android.settingslib.widget.LayoutPreference; import com.android.settingslib.wifi.AccessPoint; +import com.android.settingslib.wifi.WifiTracker; +import com.android.settingslib.wifi.WifiTrackerFactory; import org.junit.Before; import org.junit.Test; @@ -95,6 +98,7 @@ import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; +import java.util.ArrayList; import java.util.stream.Collectors; @RunWith(RobolectricTestRunner.class) @@ -107,6 +111,8 @@ public class WifiDetailPreferenceControllerTest { private static final int RX_LINK_SPEED = 54; private static final String SSID = "ssid"; private static final String MAC_ADDRESS = WifiInfo.DEFAULT_MAC_ADDRESS; + 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"; @Mock(answer = Answers.RETURNS_DEEP_STUBS) @@ -131,9 +137,13 @@ public class WifiDetailPreferenceControllerTest { @Mock private WifiManager mockWifiManager; @Mock + private WifiTracker mockWifiTracker; + @Mock private MetricsFeatureProvider mockMetricsFeatureProvider; @Mock private WifiDetailPreferenceController.IconInjector mockIconInjector; + @Mock + private MacAddress mockMacAddress; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private EntityHeaderController mockHeaderController; @@ -285,6 +295,48 @@ public class WifiDetailPreferenceControllerTest { mController = newWifiDetailPreferenceController(); } + private void setUpForConnectedNetwork() { + // Enable saved network detail page feature for this test + FeatureFlagUtils.setEnabled(mContext, FeatureFlags.WIFI_DETAILS_SAVED_SCREEN, true); + when(mockAccessPoint.isActive()).thenReturn(true); + ArrayList list = new ArrayList<>(); + list.add(mockAccessPoint); + when(mockWifiTracker.getAccessPoints()).thenReturn(list); + WifiTrackerFactory.setTestingWifiTracker(mockWifiTracker); + when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(true); + when(mockAccessPoint.isReachable()).thenReturn(true); + + mController = newWifiDetailPreferenceController(); + } + + private void setUpForDisconnectedNetwork() { + // Enable saved network detail page feature for this test + FeatureFlagUtils.setEnabled(mContext, FeatureFlags.WIFI_DETAILS_SAVED_SCREEN, true); + when(mockAccessPoint.isActive()).thenReturn(false); + ArrayList list = new ArrayList<>(); + list.add(mockAccessPoint); + when(mockWifiTracker.getAccessPoints()).thenReturn(list); + WifiTrackerFactory.setTestingWifiTracker(mockWifiTracker); + when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(true); + when(mockAccessPoint.isReachable()).thenReturn(true); + + mController = newWifiDetailPreferenceController(); + } + + private void setUpForNotInRangeNetwork() { + // Enable saved network detail page feature for this test + FeatureFlagUtils.setEnabled(mContext, FeatureFlags.WIFI_DETAILS_SAVED_SCREEN, true); + when(mockAccessPoint.isActive()).thenReturn(false); + ArrayList list = new ArrayList<>(); + list.add(mockAccessPoint); + when(mockWifiTracker.getAccessPoints()).thenReturn(list); + WifiTrackerFactory.setTestingWifiTracker(mockWifiTracker); + when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(false); + when(mockAccessPoint.isReachable()).thenReturn(false); + + mController = newWifiDetailPreferenceController(); + } + private WifiDetailPreferenceController newWifiDetailPreferenceController() { return new WifiDetailPreferenceController( mockAccessPoint, @@ -362,6 +414,33 @@ public class WifiDetailPreferenceControllerTest { verify(mockWifiManager, times(1)).getConnectionInfo(); } + @Test + public void latestWifiInfo_shouldBeFetchedInDisplayPreferenceForConnectedNetwork() { + setUpForConnectedNetwork(); + + displayAndResume(); + + verify(mockWifiManager, times(1)).getConnectionInfo(); + } + + @Test + public void latestWifiInfo_shouldNotBeFetchedInDisplayPreferenceForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + verify(mockWifiManager, never()).getConnectionInfo(); + } + + @Test + public void latestWifiInfo_shouldNotBeFetchedInDisplayPreferenceForNotInRangeNetwork() { + setUpForNotInRangeNetwork(); + + displayAndResume(); + + verify(mockWifiManager, never()).getConnectionInfo(); + } + @Test public void latestNetworkInfo_shouldBeFetchedInDisplayPreference() { displayAndResume(); @@ -369,6 +448,33 @@ public class WifiDetailPreferenceControllerTest { verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class)); } + @Test + public void latestNetworkInfo_shouldBeFetchedInDisplayPreferenceForConnectedNetwork() { + setUpForConnectedNetwork(); + + displayAndResume(); + + verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class)); + } + + @Test + public void latestNetworkInfo_shouldNotBeFetchedInDisplayPreferenceForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + verify(mockConnectivityManager, never()).getNetworkInfo(any(Network.class)); + } + + @Test + public void latestNetworkInfo_shouldNotBeFetchedInDisplayPreferenceForNotInRangeNetwork() { + setUpForNotInRangeNetwork(); + + displayAndResume(); + + verify(mockConnectivityManager, never()).getNetworkInfo(any(Network.class)); + } + @Test public void networkCallback_shouldBeRegisteredOnResume() { displayAndResume(); @@ -395,6 +501,35 @@ public class WifiDetailPreferenceControllerTest { verify(mockHeaderController).setIcon(expectedIcon); } + @Test + public void entityHeader_shouldHaveIconSetForConnectedNetwork() { + setUpForConnectedNetwork(); + Drawable expectedIcon = mockIconInjector.getIcon(LEVEL); + + displayAndResume(); + + verify(mockHeaderController).setIcon(expectedIcon); + } + + @Test + public void entityHeader_shouldHaveIconSetForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + Drawable expectedIcon = mockIconInjector.getIcon(LEVEL); + + displayAndResume(); + + verify(mockHeaderController).setIcon(expectedIcon); + } + + @Test + public void entityHeader_shouldNotHaveIconSetForNotInRangeNetwork() { + setUpForNotInRangeNetwork(); + + displayAndResume(); + + verify(mockHeaderController, never()).setIcon(any(Drawable.class)); + } + @Test public void entityHeader_shouldHaveLabelSetToTitle() { String label = "title"; @@ -422,6 +557,33 @@ public class WifiDetailPreferenceControllerTest { verify(mockSignalStrengthPref).setIcon(any(Drawable.class)); } + @Test + public void signalStrengthPref_shouldHaveIconSetForConnectedNetwork() { + setUpForConnectedNetwork(); + + displayAndResume(); + + verify(mockSignalStrengthPref).setIcon(any(Drawable.class)); + } + + @Test + public void signalStrengthPref_shouldHaveIconSetForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + verify(mockSignalStrengthPref).setIcon(any(Drawable.class)); + } + + @Test + public void signalStrengthPref_shouldNotHaveIconSetForOutOfRangeNetwork() { + setUpForNotInRangeNetwork(); + + displayAndResume(); + + verify(mockSignalStrengthPref, never()).setIcon(any(Drawable.class)); + } + @Test public void signalStrengthPref_shouldHaveDetailTextSet() { String expectedStrength = @@ -432,6 +594,37 @@ public class WifiDetailPreferenceControllerTest { verify(mockSignalStrengthPref).setSummary(expectedStrength); } + @Test + public void signalStrengthPref_shouldHaveDetailTextSetForConnectedNetwork() { + setUpForConnectedNetwork(); + String expectedStrength = + mContext.getResources().getStringArray(R.array.wifi_signal)[LEVEL]; + + displayAndResume(); + + verify(mockSignalStrengthPref).setSummary(expectedStrength); + } + + @Test + public void signalStrengthPref_shouldHaveDetailTextSetForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + String expectedStrength = + mContext.getResources().getStringArray(R.array.wifi_signal)[LEVEL]; + + displayAndResume(); + + verify(mockSignalStrengthPref).setSummary(expectedStrength); + } + + @Test + public void signalStrengthPref_shouldNotHaveDetailTextSetForNotInRangeNetwork() { + setUpForNotInRangeNetwork(); + + displayAndResume(); + + verify(mockSignalStrengthPref, never()).setSummary(any(String.class)); + } + @Test public void linkSpeedPref_shouldHaveDetailTextSet() { String expectedLinkSpeed = mContext.getString(R.string.tx_link_speed, TX_LINK_SPEED); @@ -450,6 +643,37 @@ public class WifiDetailPreferenceControllerTest { verify(mockTxLinkSpeedPref).setVisible(false); } + @Test + public void linkSpeedPref_shouldVisibleForConnectedNetwork() { + setUpForConnectedNetwork(); + String expectedLinkSpeed = mContext.getString(R.string.tx_link_speed, TX_LINK_SPEED); + + displayAndResume(); + + verify(mockTxLinkSpeedPref).setVisible(true); + verify(mockTxLinkSpeedPref).setSummary(expectedLinkSpeed); + } + + @Test + public void linkSpeedPref_shouldInvisibleForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + verify(mockTxLinkSpeedPref).setVisible(false); + verify(mockTxLinkSpeedPref, never()).setSummary(any(String.class)); + } + + @Test + public void linkSpeedPref_shouldInvisibleForNotInRangeNetwork() { + setUpForNotInRangeNetwork(); + + displayAndResume(); + + verify(mockTxLinkSpeedPref).setVisible(false); + verify(mockTxLinkSpeedPref, never()).setSummary(any(String.class)); + } + @Test public void rxLinkSpeedPref_shouldHaveDetailTextSet() { String expectedLinkSpeed = mContext.getString(R.string.rx_link_speed, RX_LINK_SPEED); @@ -468,6 +692,37 @@ public class WifiDetailPreferenceControllerTest { verify(mockRxLinkSpeedPref).setVisible(false); } + @Test + public void rxLinkSpeedPref_shouldVisibleForConnectedNetwork() { + setUpForConnectedNetwork(); + String expectedLinkSpeed = mContext.getString(R.string.rx_link_speed, RX_LINK_SPEED); + + displayAndResume(); + + verify(mockRxLinkSpeedPref).setVisible(true); + verify(mockRxLinkSpeedPref).setSummary(expectedLinkSpeed); + } + + @Test + public void rxLinkSpeedPref_shouldInvisibleForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + verify(mockRxLinkSpeedPref).setVisible(false); + verify(mockRxLinkSpeedPref, never()).setSummary(any(String.class)); + } + + @Test + public void rxLinkSpeedPref_shouldInvisibleForNotInRangeNetwork() { + setUpForNotInRangeNetwork(); + + displayAndResume(); + + verify(mockRxLinkSpeedPref).setVisible(false); + verify(mockRxLinkSpeedPref, never()).setSummary(any(String.class)); + } + @Test public void ssidPref_shouldHaveDetailTextSet() { when(mockAccessPoint.isPasspoint()).thenReturn(true); @@ -519,6 +774,42 @@ public class WifiDetailPreferenceControllerTest { verify(mockMacAddressPref).setSummary(MAC_ADDRESS); } + @Test + public void macAddressPref_shouldVisibleForConnectedNetwork() { + setUpForConnectedNetwork(); + + displayAndResume(); + + verify(mockMacAddressPref).setVisible(true); + verify(mockMacAddressPref).setSummary(MAC_ADDRESS); + } + + @Test + public void macAddressPref_shouldVisibleAsRandomizedForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + mockWifiConfig.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_PERSISTENT; + when(mockWifiConfig.getRandomizedMacAddress()).thenReturn(mockMacAddress); + when(mockMacAddress.toString()).thenReturn(RANDOMIZED_MAC_ADDRESS); + + displayAndResume(); + + verify(mockMacAddressPref).setVisible(true); + verify(mockMacAddressPref).setSummary(RANDOMIZED_MAC_ADDRESS); + } + + @Test + public void macAddressPref_shouldVisibleAsFactoryForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + mockWifiConfig.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE; + when(mockWifiManager.getFactoryMacAddresses()) + .thenReturn(new String[]{FACTORY_MAC_ADDRESS}); + + displayAndResume(); + + verify(mockMacAddressPref).setVisible(true); + verify(mockMacAddressPref).setSummary(FACTORY_MAC_ADDRESS); + } + @Test public void ipAddressPref_shouldHaveDetailTextSet() { mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); @@ -528,6 +819,26 @@ public class WifiDetailPreferenceControllerTest { verify(mockIpAddressPref).setSummary(Constants.IPV4_ADDR.getAddress().getHostAddress()); } + @Test + public void ipAddressPref_shouldHaveDetailTextSetForConnectedNetwork() { + setUpForConnectedNetwork(); + mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); + + displayAndResume(); + + verify(mockIpAddressPref).setSummary(Constants.IPV4_ADDR.getAddress().getHostAddress()); + verify(mockIpAddressPref).setVisible(true); + } + + @Test + public void ipAddressPref_shouldInvisibleForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + verify(mockIpAddressPref).setVisible(false); + } + @Test public void gatewayAndSubnet_shouldHaveDetailTextSet() { mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); @@ -540,6 +851,29 @@ public class WifiDetailPreferenceControllerTest { verify(mockGatewayPref).setSummary("192.0.2.127"); } + @Test + public void gatewayAndSubnet_shouldHaveDetailTextSetForConnectedNetwork() { + setUpForConnectedNetwork(); + mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); + mLinkProperties.addRoute(Constants.IPV4_DEFAULT); + mLinkProperties.addRoute(Constants.IPV4_SUBNET); + + displayAndResume(); + + verify(mockSubnetPref).setSummary("255.255.255.128"); + verify(mockGatewayPref).setSummary("192.0.2.127"); + verify(mockSubnetPref).setVisible(true); + } + + @Test + public void gatewayAndSubnet_shouldInvisibleSetForDisconnectedNetwork() { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + verify(mockSubnetPref).setVisible(false); + } + @Test public void dnsServersPref_shouldHaveDetailTextSet() throws UnknownHostException { mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[] {8, 8, 4, 4})); @@ -554,6 +888,33 @@ public class WifiDetailPreferenceControllerTest { Constants.IPV6_DNS.getHostAddress()); } + @Test + public void dnsServersPref_shouldHaveDetailTextSetForConnectedNetwork() + throws UnknownHostException { + setUpForConnectedNetwork(); + mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[] {8, 8, 4, 4})); + mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[] {8, 8, 8, 8})); + mLinkProperties.addDnsServer(Constants.IPV6_DNS); + + displayAndResume(); + + verify(mockDnsPref).setSummary( + "8.8.4.4\n" + + "8.8.8.8\n" + + Constants.IPV6_DNS.getHostAddress()); + verify(mockDnsPref).setVisible(true); + } + + @Test + public void dnsServersPref_shouldInvisibleSetForDisconnectedNetwork() + throws UnknownHostException { + setUpForDisconnectedNetwork(); + + displayAndResume(); + + verify(mockDnsPref).setVisible(false); + } + @Test public void noCurrentNetwork_shouldFinishActivity() { // If WifiManager#getCurrentNetwork() returns null, then the network is neither connected @@ -565,6 +926,18 @@ public class WifiDetailPreferenceControllerTest { verify(mockActivity).finish(); } + @Test + public void noCurrentNetwork_shouldNotFinishActivityForConnectedNetwork() { + // For new feature for display detail page for saved network for disconnected network, + // mNetwork may be null, do finish activity + setUpForConnectedNetwork(); + when(mockWifiManager.getCurrentNetwork()).thenReturn(null); + + displayAndResume(); + + verify(mockActivity, never()).finish(); + } + @Test public void noLinkProperties_allIpDetailsHidden() { when(mockConnectivityManager.getLinkProperties(mockNetwork)).thenReturn(null); @@ -584,6 +957,25 @@ public class WifiDetailPreferenceControllerTest { verify(mockDnsPref, never()).setVisible(true); } + @Test + public void disconnectedNetwork_allIpDetailsHidden() { + setUpForDisconnectedNetwork(); + reset(mockIpv6Category, mockIpAddressPref, mockSubnetPref, mockGatewayPref, mockDnsPref); + + displayAndResume(); + + verify(mockIpv6Category).setVisible(false); + verify(mockIpAddressPref).setVisible(false); + verify(mockSubnetPref).setVisible(false); + verify(mockGatewayPref).setVisible(false); + verify(mockDnsPref).setVisible(false); + verify(mockIpv6Category, never()).setVisible(true); + verify(mockIpAddressPref, never()).setVisible(true); + verify(mockSubnetPref, never()).setVisible(true); + verify(mockGatewayPref, never()).setVisible(true); + verify(mockDnsPref, never()).setVisible(true); + } + // Convenience method to convert a LinkAddress to a string without a prefix length. private String asString(LinkAddress l) { return l.getAddress().getHostAddress(); @@ -762,7 +1154,7 @@ public class WifiDetailPreferenceControllerTest { displayAndResume(); - verify(mockButtonsPref).setButton3Visible(false); + verify(mockButtonsPref).setButton4Visible(false); } @Test @@ -871,6 +1263,20 @@ public class WifiDetailPreferenceControllerTest { verify(mockWifiManager, times(2)).getConnectionInfo(); } + @Test + public void networkStateChangedIntent_shouldRefetchInfoForConnectedNetwork() { + setUpForConnectedNetwork(); + displayAndResume(); + + verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class)); + verify(mockWifiManager, times(1)).getConnectionInfo(); + + mContext.sendBroadcast(new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION)); + + verify(mockConnectivityManager, times(2)).getNetworkInfo(any(Network.class)); + verify(mockWifiManager, times(2)).getConnectionInfo(); + } + @Test public void rssiChangedIntent_shouldRefetchInfo() { displayAndResume(); @@ -884,6 +1290,20 @@ public class WifiDetailPreferenceControllerTest { verify(mockWifiManager, times(2)).getConnectionInfo(); } + @Test + public void rssiChangedIntent_shouldRefetchInfoForConnectedNetwork() { + setUpForConnectedNetwork(); + displayAndResume(); + + verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class)); + verify(mockWifiManager, times(1)).getConnectionInfo(); + + mContext.sendBroadcast(new Intent(WifiManager.RSSI_CHANGED_ACTION)); + + verify(mockConnectivityManager, times(2)).getNetworkInfo(any(Network.class)); + verify(mockWifiManager, times(2)).getConnectionInfo(); + } + @Test public void networkDisconnectedState_shouldFinishActivity() { displayAndResume(); @@ -894,6 +1314,18 @@ public class WifiDetailPreferenceControllerTest { verify(mockActivity).finish(); } + @Test + public void networkDisconnectedState_shouldNotFinishActivityForConnectedNetwork() { + setUpForConnectedNetwork(); + + displayAndResume(); + + when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(null); + mContext.sendBroadcast(new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION)); + + verify(mockActivity, never()).finish(); + } + @Test public void networkOnLost_shouldFinishActivity() { displayAndResume(); @@ -903,6 +1335,17 @@ public class WifiDetailPreferenceControllerTest { verify(mockActivity).finish(); } + @Test + public void networkOnLost_shouldNotFinishActivityForConnectedNetwork() { + setUpForConnectedNetwork(); + + displayAndResume(); + + mCallbackCaptor.getValue().onLost(mockNetwork); + + verify(mockActivity, never()).finish(); + } + @Test public void ipv6AddressPref_shouldHaveHostAddressTextSet() { mLinkProperties.addLinkAddress(Constants.IPV6_LINKLOCAL); @@ -982,6 +1425,19 @@ public class WifiDetailPreferenceControllerTest { verify(mockIconInjector, times(2)).getIcon(anyInt()); } + @Test + public void testRefreshRssiViews_shouldNotUpdateForNotInRangeNetwork() { + setUpForNotInRangeNetwork(); + + displayAndResume(); + + when(mockAccessPoint.getLevel()).thenReturn(0); + mContext.sendBroadcast(new Intent(WifiManager.RSSI_CHANGED_ACTION)); + + verify(mockSignalStrengthPref, times(2)).setVisible(false); + } + + private ActionButtonsPreference createMock() { final ActionButtonsPreference pref = mock(ActionButtonsPreference.class); when(pref.setButton1Text(anyInt())).thenReturn(pref); From c0754b35badaa4fbb47597ece034aa7cb0d2614a Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Thu, 28 Mar 2019 19:14:25 -0700 Subject: [PATCH 09/12] Settings unexpectedly open after turning work profile on ConfirmDeviceCredentialActivity doesn't set a taskAffinity, so the default taskAffinity is the package name. That's why Settings unexpectedly open after users turn work profile on. We specified an unique name to taskAffinity to avoid launching Settings activity. Fixes: 129330530 Test: turn work profile off then turn it on, repeat Change-Id: I1f71c3d1bb37a09a6393fae4c01bc9b18cab49a8 --- AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c13068fb29c..3027c064641 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1474,6 +1474,7 @@ @@ -1491,6 +1492,7 @@ android:exported="false" android:permission="android.permission.MANAGE_USERS" android:resizeableActivity="false" + android:taskAffinity=".password.ConfirmDeviceCredentialActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"> From 1b5f5ef510ac85e613304b0dd8e332606def46da Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Thu, 28 Mar 2019 15:56:21 +0800 Subject: [PATCH 10/12] Add Wi-Fi connect listener in ConnectToWifiHandler - Extract the connect listener from WifiSettings - Add a listener to display a toast on failure to connect in ConnectToWifiHandler - Also for the new AccessPoint.startOsuProvisioning() which accepts a connect listener Bug: 123697580 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.wifi Change-Id: I29b2c1e2c58312d692675ecabf2818b4bbed3b51 --- .../settings/wifi/WifiConnectListener.java | 48 +++++++++++++++++++ .../android/settings/wifi/WifiSettings.java | 16 +------ .../wifi/slice/ConnectToWifiHandler.java | 6 ++- .../wifi/slice/ConnectToWifiHandlerTest.java | 4 +- 4 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 src/com/android/settings/wifi/WifiConnectListener.java diff --git a/src/com/android/settings/wifi/WifiConnectListener.java b/src/com/android/settings/wifi/WifiConnectListener.java new file mode 100644 index 00000000000..b97fbc5e6e4 --- /dev/null +++ b/src/com/android/settings/wifi/WifiConnectListener.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.wifi; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.widget.Toast; + +import com.android.settings.R; + +/** + * A listener to display a toast on failure to connect + */ +public class WifiConnectListener implements WifiManager.ActionListener { + + private final Context mContext; + + public WifiConnectListener(Context context) { + mContext = context; + } + + @Override + public void onSuccess() { + } + + @Override + public void onFailure(int reason) { + if (mContext != null) { + Toast.makeText(mContext, + R.string.wifi_failed_connect_message, + Toast.LENGTH_SHORT).show(); + } + } +} diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 8e7b53a8388..e8d1b201c12 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -258,21 +258,7 @@ public class WifiSettings extends RestrictedSettingsFragment mConnectivityManager = getActivity().getSystemService(ConnectivityManager.class); } - mConnectListener = new WifiManager.ActionListener() { - @Override - public void onSuccess() { - } - - @Override - public void onFailure(int reason) { - Activity activity = getActivity(); - if (activity != null) { - Toast.makeText(activity, - R.string.wifi_failed_connect_message, - Toast.LENGTH_SHORT).show(); - } - } - }; + mConnectListener = new WifiConnectListener(getActivity()); mSaveListener = new WifiManager.ActionListener() { @Override diff --git a/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java b/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java index 064037e2e5d..6cf55d27b7e 100644 --- a/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java +++ b/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java @@ -22,6 +22,7 @@ import android.os.Bundle; import androidx.annotation.VisibleForTesting; +import com.android.settings.wifi.WifiConnectListener; import com.android.settings.wifi.WifiDialogActivity; import com.android.settings.wifi.WifiUtils; import com.android.settingslib.wifi.AccessPoint; @@ -46,9 +47,10 @@ public class ConnectToWifiHandler extends Activity { @VisibleForTesting void connect(AccessPoint accessPoint) { + final WifiConnectListener connectListener = new WifiConnectListener(this); switch (WifiUtils.getConnectingType(accessPoint)) { case WifiUtils.CONNECT_TYPE_OSU_PROVISION: - accessPoint.startOsuProvisioning(null /* listener */); + accessPoint.startOsuProvisioning(connectListener); break; case WifiUtils.CONNECT_TYPE_OPEN_NETWORK: @@ -56,7 +58,7 @@ public class ConnectToWifiHandler extends Activity { case WifiUtils.CONNECT_TYPE_SAVED_NETWORK: final WifiManager wifiManager = getSystemService(WifiManager.class); - wifiManager.connect(accessPoint.getConfig(), null /* listener */); + wifiManager.connect(accessPoint.getConfig(), connectListener); break; } } diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java index 24b0b380434..b18102d226d 100644 --- a/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java @@ -18,12 +18,14 @@ package com.android.settings.wifi.slice; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; +import android.net.wifi.WifiManager; import com.android.settings.testutils.shadow.ShadowConnectivityManager; import com.android.settings.testutils.shadow.ShadowWifiManager; @@ -78,7 +80,7 @@ public class ConnectToWifiHandlerTest { mHandler.connect(mAccessPoint); - verify(mAccessPoint).startOsuProvisioning(null /* listener */); + verify(mAccessPoint).startOsuProvisioning(any(WifiManager.ActionListener.class)); } From c11875c0c6f2825a6fb724ee499dbaa4f67b877e Mon Sep 17 00:00:00 2001 From: hughchen Date: Tue, 2 Apr 2019 14:22:39 +0800 Subject: [PATCH 11/12] Add FLAG_RECEIVER_FOREGROUND flag Bug: 129726026 Test: make -j42 RunSettingsRoboTests Change-Id: Idf994396a5dcf78e520ff3cf7c928d4dd19b606e --- src/com/android/settings/media/MediaOutputSlice.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/settings/media/MediaOutputSlice.java b/src/com/android/settings/media/MediaOutputSlice.java index 53324e93120..30551a9ae8f 100644 --- a/src/com/android/settings/media/MediaOutputSlice.java +++ b/src/com/android/settings/media/MediaOutputSlice.java @@ -162,6 +162,7 @@ public class MediaOutputSlice implements CustomSliceable { final Intent intent = new Intent(getUri().toString()); intent.setClass(context, SliceBroadcastReceiver.class); intent.putExtra(MEDIA_DEVICE_ID, id); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); return PendingIntent.getBroadcast(context, requestCode /* requestCode */, intent, PendingIntent.FLAG_CANCEL_CURRENT); } From 9071506902ebb6d6e9323f0d09a51a79b8a111b7 Mon Sep 17 00:00:00 2001 From: Chandan Nath Date: Mon, 1 Apr 2019 21:05:15 +0100 Subject: [PATCH 12/12] Show "Backup service isn't active" if backup isnt active for work profile Bug: 127821779 Test: 1) Set up work profile. 2) adb shell bmgr --user 19 activate true 3) Settings -> System -> Backup -> Work -> Shows google backup settings 4) adb shell bmgr --user 19 activate false 5) Settings -> System -> Backup -> Work -> "Backup service isn't active" Change-Id: Ifc16cf3e69fd9db87d519cbad68f0f8e9d8ef6f3 --- src/com/android/settings/SettingsActivity.java | 10 +++++++--- .../BackupInactivePreferenceController.java | 3 --- .../BackupInactivePreferenceControllerTest.java | 16 ++-------------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 001e65be8be..e704076c5e7 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -632,10 +632,14 @@ public class SettingsActivity extends SettingsBaseActivity showDev, isAdmin) || somethingChanged; - // Enable/disable backup settings depending on whether backup is activated for the user. - boolean isBackupActive = new BackupSettingsHelper(this).isBackupServiceActive(); + // For profiles, we want them to be included in the profile select dialog even if + // backup is not activated. + // For other users, enable/disable backup settings depending on whether backup is activated + // for the user. + boolean enableBackupTile = um.isManagedProfile() + || new BackupSettingsHelper(this).isBackupServiceActive(); somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, - UserBackupSettingsActivity.class.getName()), isBackupActive, isAdmin) + UserBackupSettingsActivity.class.getName()), enableBackupTile, isAdmin) || somethingChanged; somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, diff --git a/src/com/android/settings/backup/BackupInactivePreferenceController.java b/src/com/android/settings/backup/BackupInactivePreferenceController.java index 8bd278c2e13..83a03185e15 100644 --- a/src/com/android/settings/backup/BackupInactivePreferenceController.java +++ b/src/com/android/settings/backup/BackupInactivePreferenceController.java @@ -28,9 +28,6 @@ public class BackupInactivePreferenceController extends BasePreferenceController @Override public int getAvailabilityStatus() { - if (!PrivacySettingsUtils.isAdminUser(mContext)) { - return DISABLED_FOR_USER; - } if (PrivacySettingsUtils.isInvisibleKey(mContext, PrivacySettingsUtils.BACKUP_INACTIVE)) { return UNSUPPORTED_ON_DEVICE; } diff --git a/tests/robotests/src/com/android/settings/backup/BackupInactivePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/backup/BackupInactivePreferenceControllerTest.java index f8b3578d0d5..1d8d0283c2f 100644 --- a/tests/robotests/src/com/android/settings/backup/BackupInactivePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/backup/BackupInactivePreferenceControllerTest.java @@ -20,8 +20,6 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import androidx.preference.Preference; - import com.android.settings.core.BasePreferenceController; import org.junit.After; @@ -38,7 +36,6 @@ import org.robolectric.annotation.Config; public class BackupInactivePreferenceControllerTest { private Context mContext; private BackupInactivePreferenceController mController; - private Preference mPreference; @Before public void setUp() { @@ -54,23 +51,14 @@ public class BackupInactivePreferenceControllerTest { } @Test - public void getAvailabilityStatus_isAdmiUser_isnotInvisibleKey_shouldBeAvailable() { - ShadowPrivacySettingsUtils.setIsAdminUser(true); + public void getAvailabilityStatus_isnotInvisibleKey_shouldBeAvailable() { ShadowPrivacySettingsUtils.setIsInvisibleKey(false); assertThat(mController.getAvailabilityStatus()) .isEqualTo(BasePreferenceController.AVAILABLE); } @Test - public void getAvailabilityStatus_isnotAdmiUser_shouldBeDisabledForUser() { - ShadowPrivacySettingsUtils.setIsAdminUser(false); - assertThat(mController.getAvailabilityStatus()) - .isEqualTo(BasePreferenceController.DISABLED_FOR_USER); - } - - @Test - public void getAvailabilityStatus_isAdmiUser_isInvisibleKey_shouldBeDisabledUnsupported() { - ShadowPrivacySettingsUtils.setIsAdminUser(true); + public void getAvailabilityStatus_isInvisibleKey_shouldBeDisabledUnsupported() { ShadowPrivacySettingsUtils.setIsInvisibleKey(true); assertThat(mController.getAvailabilityStatus()) .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);