From 25054ba36d573814f81bf5070eebf87c3f71ca9c Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Thu, 16 Apr 2020 15:53:03 +0100 Subject: [PATCH 01/16] Stop disabling wifi toggle when tethering is restricted When an admin disallows the user from configuring tethering, the user should still be able to configure wifi. When an admin disallows wifi configuration, the behavior is unchanged: the toggle stays enabled and allows the user to turn wifi on and off, but clicking on the text results in admin transparency dialog, so the user won't be able to change wifi config. Bug: 149481093 Test: manual with TestDPC as the device owner Change-Id: I6b33e43901454125c7f3f4dd3c70f050997e4e71 --- src/com/android/settings/wifi/WifiEnabler.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java index 536ea613b59..dc5be4209a8 100644 --- a/src/com/android/settings/wifi/WifiEnabler.java +++ b/src/com/android/settings/wifi/WifiEnabler.java @@ -26,8 +26,6 @@ import android.net.NetworkInfo; import android.net.wifi.SupplicantState; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.os.UserHandle; -import android.os.UserManager; import android.provider.Settings; import android.widget.Toast; @@ -35,8 +33,6 @@ import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settings.widget.SwitchWidgetController; -import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; -import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.WirelessUtils; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -76,9 +72,6 @@ public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListene } }; - private static final String EVENT_DATA_IS_WIFI_ON = "is_wifi_on"; - private static final int EVENT_UPDATE_INDEX = 0; - public WifiEnabler(Context context, SwitchWidgetController switchWidget, MetricsFeatureProvider metricsFeatureProvider) { this(context, switchWidget, metricsFeatureProvider, @@ -161,15 +154,6 @@ public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListene setSwitchBarChecked(false); mSwitchWidget.setEnabled(true); } - - if (RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext, - UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) { - mSwitchWidget.setEnabled(false); - } else { - final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( - mContext, UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId()); - mSwitchWidget.setDisabledByAdmin(admin); - } } private void setSwitchBarChecked(boolean checked) { From 8f677012949d775209f740cb1783dece898a4a06 Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Sun, 19 Apr 2020 21:19:18 +0800 Subject: [PATCH 02/16] [Settings] Support of DSDS API Replacing getDataEnabled() by isDataEnabledForApn(). Bug: 143996139 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=BillingCycleSettingsTest Change-Id: If36cfcd7c6b44fb89957ebf9f741936041761d9c --- .../android/settings/datausage/BillingCyclePreference.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java index 47ef56b2efd..116ed89b3c7 100644 --- a/src/com/android/settings/datausage/BillingCyclePreference.java +++ b/src/com/android/settings/datausage/BillingCyclePreference.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.net.NetworkTemplate; import android.os.Bundle; import android.os.RemoteException; +import android.telephony.data.ApnSetting; import android.util.AttributeSet; import androidx.preference.Preference; @@ -76,7 +77,8 @@ public class BillingCyclePreference extends Preference private void updateEnabled() { try { setEnabled(mServices.mNetworkService.isBandwidthControlEnabled() - && mServices.mTelephonyManager.getDataEnabled(mSubId) + && mServices.mTelephonyManager.createForSubscriptionId(mSubId) + .isDataEnabledForApn(ApnSetting.TYPE_DEFAULT) && mServices.mUserManager.isAdminUser()); } catch (RemoteException e) { setEnabled(false); From 23ed0b2c34475267931e6256b420d885b3014f48 Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Mon, 20 Apr 2020 14:38:23 +0800 Subject: [PATCH 03/16] [Settings] Avoid from EUICC access blocking main thread Avoid from EUICC accessing form main thread and timeout if API takes too much time. Bug: 143996139 Test: manual Change-Id: Ic1a2bd948b69d40632555d293df6ed56a6b7a712 --- .../network/telephony/MobileNetworkUtils.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java index 25cd2727a44..3b5e6e04726 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java +++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java @@ -42,6 +42,7 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.os.PersistableBundle; +import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; import android.telecom.PhoneAccountHandle; @@ -70,9 +71,12 @@ import com.android.settings.core.BasePreferenceController; import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants; import com.android.settingslib.development.DevelopmentSettingsEnabler; import com.android.settingslib.graph.SignalDrawable; +import com.android.settingslib.utils.ThreadUtils; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; public class MobileNetworkUtils { @@ -242,6 +246,18 @@ public class MobileNetworkUtils { * the user has enabled development mode. */ public static boolean showEuiccSettings(Context context) { + long timeForAccess = SystemClock.elapsedRealtime(); + try { + return ((Future) ThreadUtils.postOnBackgroundThread(() + -> showEuiccSettingsDetecting(context))).get(); + } catch (ExecutionException | InterruptedException exception) { + timeForAccess = SystemClock.elapsedRealtime() - timeForAccess; + Log.w(TAG, "Accessing Euicc takes too long: +" + timeForAccess + "ms"); + } + return false; + } + + private static Boolean showEuiccSettingsDetecting(Context context) { final EuiccManager euiccManager = (EuiccManager) context.getSystemService(EuiccManager.class); if (!euiccManager.isEnabled()) { From d1a31ab6b38cca191045e1451da9e49158bec421 Mon Sep 17 00:00:00 2001 From: Alex Johnston Date: Wed, 15 Apr 2020 11:57:26 +0100 Subject: [PATCH 04/16] Update Wi-Fi configs restrictions * Update isNetworkLockedDown in WifiUtils to check the profile owner if the device is an organization-owned managed profile device. * Update the logic to check if a Wi-Fi network can be forgotten (for both the device owner and profile owner of an organization-owned device). Bug: 150197944 Bug: 153605361 Test: manual testing make RunSettingsRoboTests -j ROBOTEST_FILTER=WifiDetailPreferenceController2Test make RunSettingsRoboTests -j ROBOTEST_FILTER=WifiUtilsTest Manual Testing Steps A. Provision TestDPC in 'Device Owner' mode. - Create a Wi-Fi config in TestDPC. - Enable 'DO created Wi-Fi configs are modifiable only by DO'. - Go to Settings and verify that the network created cannot be modified and the 'Forget' button is not displayed. B. Provision TestDPC in 'Profile Owner of an organization-owned managed profile' mode. - Create a Wi-Fi config in the work profile instance of TestDPC. - Enable 'DO created Wi-Fi configs are modifiable only by DO'. - Go to Settings and verify that the network created cannot be modified and the 'Forget' button is not displayed. C. Provision CtsVerifier in 'Device Owner' mode. - Go to 'Device owner tests' > 'Wifi configuration lockdown'. - Create a Wi-Fi config then follow the instructions. Change-Id: Ie3c71113441a3aca62563310ad0e53d89fa04226 --- .../android/settings/wifi/WifiSettings2.java | 7 ++++++- src/com/android/settings/wifi/WifiUtils.java | 16 ++++++++++++++++ .../WifiDetailPreferenceController2.java | 10 +++++++++- .../details2/WifiNetworkDetailsFragment2.java | 19 +++++++++++++++++-- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/wifi/WifiSettings2.java b/src/com/android/settings/wifi/WifiSettings2.java index 30d5ad08da4..ec8064843f7 100644 --- a/src/com/android/settings/wifi/WifiSettings2.java +++ b/src/com/android/settings/wifi/WifiSettings2.java @@ -491,7 +491,7 @@ public class WifiSettings2 extends RestrictedSettingsFragment // "forget" for normal saved network. And "disconnect" for ephemeral network because it // could only be disconnected and be put in blacklists so it won't be used again. - if (mSelectedWifiEntry.canForget()) { + if (canForgetNetwork()) { menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, R.string.forget); } @@ -507,6 +507,11 @@ public class WifiSettings2 extends RestrictedSettingsFragment } } + private boolean canForgetNetwork() { + return mSelectedWifiEntry.canForget() && !WifiUtils.isNetworkLockedDown(getActivity(), + mSelectedWifiEntry.getWifiConfiguration()); + } + @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java index c73e6a2dcf0..1333ab40741 100644 --- a/src/com/android/settings/wifi/WifiUtils.java +++ b/src/com/android/settings/wifi/WifiUtils.java @@ -24,9 +24,12 @@ import android.content.pm.PackageManager; import android.net.NetworkCapabilities; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; +import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; +import com.android.settings.Utils; import com.android.settingslib.wifi.AccessPoint; import java.nio.charset.StandardCharsets; @@ -77,6 +80,7 @@ public class WifiUtils { final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); final PackageManager pm = context.getPackageManager(); + final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); // Check if device has DPM capability. If it has and dpm is still null, then we // treat this case with suspicion and bail out. @@ -96,6 +100,18 @@ public class WifiUtils { } catch (PackageManager.NameNotFoundException e) { // don't care } + } else if (dpm.isOrganizationOwnedDeviceWithManagedProfile()) { + int profileOwnerUserId = Utils.getManagedProfileId(um, UserHandle.myUserId()); + final ComponentName profileOwner = dpm.getProfileOwnerAsUser(profileOwnerUserId); + if (profileOwner != null) { + try { + final int profileOwnerUid = pm.getPackageUidAsUser( + profileOwner.getPackageName(), profileOwnerUserId); + isConfigEligibleForLockdown = profileOwnerUid == config.creatorUid; + } catch (PackageManager.NameNotFoundException e) { + // don't care + } + } } } if (!isConfigEligibleForLockdown) { diff --git a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java index d55ab0b1927..2228f7b140a 100644 --- a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java +++ b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java @@ -660,7 +660,7 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle } private void refreshButtons() { - final boolean canForgetNetwork = mWifiEntry.canForget(); + final boolean canForgetNetwork = canForgetNetwork(); final boolean showCaptivePortalButton = updateCaptivePortalButton(); final boolean canConnectDisconnectNetwork = mWifiEntry.canConnect() || mWifiEntry.canDisconnect(); @@ -787,6 +787,14 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle && !WifiUtils.isNetworkLockedDown(mContext, mWifiEntry.getWifiConfiguration()); } + /** + * Returns whether the network represented by this preference can be forgotten. + */ + public boolean canForgetNetwork() { + return mWifiEntry.canForget() + && !WifiUtils.isNetworkLockedDown(mContext, mWifiEntry.getWifiConfiguration()); + } + /** * Returns whether the user can sign into the network represented by this preference. */ diff --git a/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2.java b/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2.java index 1b54e1a2f31..394bab65be0 100644 --- a/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2.java +++ b/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2.java @@ -18,6 +18,7 @@ package com.android.settings.wifi.details2; import static com.android.settings.wifi.WifiSettings.WIFI_DIALOG_ID; import android.app.Dialog; +import android.app.admin.DevicePolicyManager; import android.app.settings.SettingsEnums; import android.content.Context; import android.net.ConnectivityManager; @@ -29,6 +30,8 @@ import android.os.Looper; import android.os.Process; import android.os.SimpleClock; import android.os.SystemClock; +import android.os.UserHandle; +import android.os.UserManager; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -36,10 +39,12 @@ import android.view.MenuItem; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.wifi.WifiConfigUiBase2; import com.android.settings.wifi.WifiDialog2; import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.core.AbstractPreferenceController; import com.android.wifitrackerlib.NetworkDetailsTracker; @@ -129,8 +134,18 @@ public class WifiNetworkDetailsFragment2 extends DashboardFragment implements switch (menuItem.getItemId()) { case Menu.FIRST: if (!mWifiDetailPreferenceController2.canModifyNetwork()) { - RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), - RestrictedLockUtilsInternal.getDeviceOwner(getContext())); + EnforcedAdmin admin = RestrictedLockUtilsInternal.getDeviceOwner(getContext()); + if (admin == null) { + final DevicePolicyManager dpm = (DevicePolicyManager) + getContext().getSystemService(Context.DEVICE_POLICY_SERVICE); + final UserManager um = (UserManager) + getContext().getSystemService(Context.USER_SERVICE); + int profileOwnerUserId = Utils.getManagedProfileId( + um, UserHandle.myUserId()); + admin = new EnforcedAdmin(dpm.getProfileOwnerAsUser(profileOwnerUserId), + null, UserHandle.of(profileOwnerUserId)); + } + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), admin); } else { showDialog(WIFI_DIALOG_ID); } From 80be9de6d01dc1ecc6221112f084b3ab99e55611 Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Fri, 17 Apr 2020 21:54:53 -0700 Subject: [PATCH 05/16] Define a helper link for 5G limitation in DSDS footer. Bug: 152786064 Test: manual Change-Id: I5a02f847531988217cc6ab47e3b35ed319c1027c --- res/values/strings.xml | 10 ++++--- ...abledInDsdsFooterPreferenceController.java | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index f913b7abe64..0e3bf0eb2ae 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11918,9 +11918,11 @@ This also turns off your 5G connection.\nDuring a voice call, you can\u2019t use the internet and some apps may not work. - When using 2 SIMs, this phone will be limited to 4G. Learn more + When using 2 SIMs, this phone will be limited to 4G. Learn more. - When using 2 SIMs, this tablet will be limited to 4G. Learn more + When using 2 SIMs, this tablet will be limited to 4G. Learn more. - When using 2 SIMs, this device will be limited to 4G. Learn more - \ No newline at end of file + When using 2 SIMs, this device will be limited to 4G. Learn more. + + + diff --git a/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java b/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java index ca944daff46..4077e91ae8d 100644 --- a/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java +++ b/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java @@ -17,10 +17,17 @@ package com.android.settings.network.telephony; import android.content.Context; +import android.content.Intent; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import androidx.preference.Preference; + +import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settings.utils.AnnotationSpan; +import com.android.settingslib.HelpUtils; + /** * Class to show the footer that can't connect to 5G when device is in DSDS mode. @@ -43,6 +50,29 @@ public class NrDisabledInDsdsFooterPreferenceController extends BasePreferenceCo mSubId = subId; } + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + if (preference != null) { + preference.setTitle(getFooterText()); + } + } + + private CharSequence getFooterText() { + final Intent helpIntent = HelpUtils.getHelpIntent(mContext, + mContext.getString(R.string.help_uri_5g_dsds), + mContext.getClass().getName()); + final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(mContext, + "url", helpIntent); + + if (linkInfo.isActionable()) { + return AnnotationSpan.linkify(mContext.getText(R.string.no_5g_in_dsds_text), linkInfo); + } else { + return mContext.getText(R.string.no_5g_in_dsds_text); + } + } + @Override public int getAvailabilityStatus() { if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { From c10ec56e0fcfbde8655290b8aec6025118187100 Mon Sep 17 00:00:00 2001 From: Zhen Zhang Date: Mon, 13 Apr 2020 17:02:07 -0700 Subject: [PATCH 06/16] Add ethernet tether option into AllInOneTetherSettings Create controller for ethernet tether preference in AllInOneTetherSettings and corresponding test. Test: AllInOneTetherSettingsTest; UsbTetherPreferenceControllerTest; BluetoothTetherPreferenceControllerTest; EthernetTetherPreferenceControllerTest; WifiTetherDisablePreferenceControllerTest; TetherEnablerTest Bug: 153690620 Change-Id: I8918d5c8a82c521b00eb3c712af80c2041778595 --- res/values/strings.xml | 25 ++++ res/xml/all_tether_prefs.xml | 7 + .../settings/AllInOneTetherSettings.java | 43 ++++-- .../AllInOneTetherPreferenceController.java | 92 ++++++------ .../BluetoothTetherPreferenceController.java | 57 ++----- .../EthernetTetherPreferenceController.java | 86 +++++++++++ .../TetherBasePreferenceController.java | 92 +++++++++++- .../settings/network/TetherEnabler.java | 126 ++++++++-------- .../UsbTetherPreferenceController.java | 54 ++----- ...WifiTetherDisablePreferenceController.java | 94 ++++++------ .../settings/AllInOneTetherSettingsTest.java | 52 ++++--- ...llInOneTetherPreferenceControllerTest.java | 84 ++++++++++- ...uetoothTetherPreferenceControllerTest.java | 16 +- ...thernetTetherPreferenceControllerTest.java | 141 ++++++++++++++++++ .../settings/network/TetherEnablerTest.java | 83 ++++++++++- .../UsbTetherPreferenceControllerTest.java | 17 ++- ...TetherDisablePreferenceControllerTest.java | 71 +++++++-- 17 files changed, 823 insertions(+), 317 deletions(-) create mode 100644 src/com/android/settings/network/EthernetTetherPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 341ac9075bc..47db0bfc171 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3776,14 +3776,31 @@ USB only Bluetooth only + + Ethernet only Hotspot, USB Hotspot, Bluetooth + + Hotspot, Ethernet USB, Bluetooth + + USB, Ethernet + + Bluetooth, Ethernet Hotspot, USB, Bluetooth + + Hotspot, USB, Ethernet + + Hotspot, Bluetooth, Ethernet + + USB, Bluetooth, Ethernet + + Hotspot, USB, Bluetooth, Ethernet + Not sharing internet with other devices @@ -3797,8 +3814,16 @@ Only share internet via USB Only share internet via Bluetooth + + Only share internet via Ethernet Only share internet via USB and Bluetooth + + Only share internet via USB and Ethernet + + Only share internet via Bluetooth and Ethernet + + Only share internet via USB, Bluetooth and Ethernet USB diff --git a/res/xml/all_tether_prefs.xml b/res/xml/all_tether_prefs.xml index 294e9752312..84d5d2ac173 100644 --- a/res/xml/all_tether_prefs.xml +++ b/res/xml/all_tether_prefs.xml @@ -71,6 +71,13 @@ settings:controller="com.android.settings.network.BluetoothTetherPreferenceController" settings:keywords="@string/keywords_hotspot_tethering" /> + + { - mBluetoothTethering = TetherEnabler.isBluetoothTethering(state); - mUsbTethering = TetherEnabler.isUsbTethering(state); - mWifiTethering = TetherEnabler.isWifiTethering(state); - mWifiTetherGroup.setVisible(shouldShowWifiConfig()); + mShouldShowWifiConfig = TetherEnabler.isTethering(state, TETHERING_WIFI) + || state == TetherEnabler.TETHERING_OFF; + getPreferenceScreen().setInitialExpandedChildrenCount( + getInitialExpandedChildCount()); + mWifiTetherGroup.setVisible(mShouldShowWifiConfig); }; private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() { @@ -182,13 +189,13 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment mApBandPreferenceController = use(WifiTetherApBandPreferenceController.class); getSettingsLifecycle().addObserver(use(UsbTetherPreferenceController.class)); getSettingsLifecycle().addObserver(use(BluetoothTetherPreferenceController.class)); + getSettingsLifecycle().addObserver(use(EthernetTetherPreferenceController.class)); getSettingsLifecycle().addObserver(use(WifiTetherDisablePreferenceController.class)); } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - mDataSaverBackend = new DataSaverBackend(getContext()); mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); mDataSaverFooter = findPreference(KEY_DATA_SAVER_FOOTER); @@ -226,6 +233,7 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment getSettingsLifecycle().addObserver(mTetherEnabler); use(UsbTetherPreferenceController.class).setTetherEnabler(mTetherEnabler); use(BluetoothTetherPreferenceController.class).setTetherEnabler(mTetherEnabler); + use(EthernetTetherPreferenceController.class).setTetherEnabler(mTetherEnabler); use(WifiTetherDisablePreferenceController.class).setTetherEnabler(mTetherEnabler); switchBar.show(); } @@ -379,14 +387,11 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment mApBandPreferenceController.updateDisplay(); } - private boolean shouldShowWifiConfig() { - return mWifiTethering || (!mBluetoothTethering && !mUsbTethering); - } - @Override public int getInitialExpandedChildCount() { - if (!shouldShowWifiConfig()) { - return EXPANDED_CHILD_COUNT_WITHOUT_WIFI_CONFIG; + if (mHasShownAdvance || !mShouldShowWifiConfig) { + mHasShownAdvance = true; + return EXPANDED_CHILD_COUNT_MAX; } if (mSecurityPreferenceController == null) { @@ -398,6 +403,12 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment ? EXPANDED_CHILD_COUNT_WITH_SECURITY_NON : EXPANDED_CHILD_COUNT_DEFAULT; } + @Override + public void onExpandButtonClick() { + super.onExpandButtonClick(); + mHasShownAdvance = true; + } + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.all_tether_prefs) { diff --git a/src/com/android/settings/network/AllInOneTetherPreferenceController.java b/src/com/android/settings/network/AllInOneTetherPreferenceController.java index 50c3a6439ed..595e31bab09 100644 --- a/src/com/android/settings/network/AllInOneTetherPreferenceController.java +++ b/src/com/android/settings/network/AllInOneTetherPreferenceController.java @@ -17,6 +17,11 @@ package com.android.settings.network; import static android.os.UserManager.DISALLOW_CONFIG_TETHERING; +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_OFF; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_WIFI_ON; import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfRestrictionEnforced; import android.bluetooth.BluetoothAdapter; @@ -52,19 +57,7 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController LifecycleObserver, TetherEnabler.OnTetherStateUpdateListener { private static final String TAG = "AllInOneTetherPreferenceController"; - private static final byte TETHERING_TYPE_HOTSPOT_ONLY = 1; - private static final byte TETHERING_TYPE_USB_ONLY = 1 << 1; - private static final byte TETHERING_TYPE_BLUETOOTH_ONLY = 1 << 2; - private static final byte TETHERING_TYPE_HOTSPOT_AND_USB = - TETHERING_TYPE_HOTSPOT_ONLY | TETHERING_TYPE_USB_ONLY; - private static final byte TETHERING_TYPE_HOTSPOT_AND_BLUETOOTH = - TETHERING_TYPE_HOTSPOT_ONLY | TETHERING_TYPE_BLUETOOTH_ONLY; - private static final byte TETHERING_TYPE_USB_AND_BLUETOOTH = - TETHERING_TYPE_USB_ONLY | TETHERING_TYPE_BLUETOOTH_ONLY; - private static final byte TETHERING_TYPE_HOTSPOT_AND_USB_AND_BLUETOOTH = - TETHERING_TYPE_HOTSPOT_ONLY | TETHERING_TYPE_USB_ONLY | TETHERING_TYPE_BLUETOOTH_ONLY; - // A bitwise value that stands for the current tethering interface type. - private int mTetheringType; + private int mTetheringState; private final boolean mAdminDisallowedTetherConfig; private final AtomicReference mBluetoothPan; @@ -124,32 +117,49 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController @Override public CharSequence getSummary() { - if (mPreference != null && mPreference.isChecked()) { - switch (mTetheringType) { - case TETHERING_TYPE_HOTSPOT_ONLY: - return mContext.getString(R.string.tether_settings_summary_hotspot_only); - case TETHERING_TYPE_USB_ONLY: - return mContext.getString(R.string.tether_settings_summary_usb_tethering_only); - case TETHERING_TYPE_BLUETOOTH_ONLY: - return mContext.getString( - R.string.tether_settings_summary_bluetooth_tethering_only); - case TETHERING_TYPE_HOTSPOT_AND_USB: - return mContext.getString(R.string.tether_settings_summary_hotspot_and_usb); - case TETHERING_TYPE_HOTSPOT_AND_BLUETOOTH: - return mContext.getString( - R.string.tether_settings_summary_hotspot_and_bluetooth); - case TETHERING_TYPE_USB_AND_BLUETOOTH: - return mContext.getString(R.string.tether_settings_summary_usb_and_bluetooth); - case TETHERING_TYPE_HOTSPOT_AND_USB_AND_BLUETOOTH: - return mContext.getString( - R.string.tether_settings_summary_hotspot_and_usb_and_bluetooth); - default: - Log.e(TAG, "None of the tether interfaces is chosen"); - return mContext.getString(R.string.summary_placeholder); - } + switch (mTetheringState) { + case TETHERING_OFF: + return mContext.getString(R.string.tether_settings_summary_off); + case TETHERING_WIFI_ON: + return mContext.getString(R.string.tether_settings_summary_hotspot_only); + case TETHERING_USB_ON: + return mContext.getString(R.string.tether_settings_summary_usb_tethering_only); + case TETHERING_BLUETOOTH_ON: + return mContext.getString( + R.string.tether_settings_summary_bluetooth_tethering_only); + case TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_ethernet_tethering_only); + case TETHERING_WIFI_ON | TETHERING_USB_ON: + return mContext.getString(R.string.tether_settings_summary_hotspot_and_usb); + case TETHERING_WIFI_ON | TETHERING_BLUETOOTH_ON: + return mContext.getString(R.string.tether_settings_summary_hotspot_and_bluetooth); + case TETHERING_WIFI_ON | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_hotspot_and_ethernet); + case TETHERING_USB_ON | TETHERING_BLUETOOTH_ON: + return mContext.getString(R.string.tether_settings_summary_usb_and_bluetooth); + case TETHERING_USB_ON | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_usb_and_ethernet); + case TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_bluetooth_and_ethernet); + case TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_BLUETOOTH_ON: + return mContext.getString( + R.string.tether_settings_summary_hotspot_and_usb_and_bluetooth); + case TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.tether_settings_summary_hotspot_and_usb_and_ethernet); + case TETHERING_WIFI_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.tether_settings_summary_hotspot_and_bluetooth_and_ethernet); + case TETHERING_USB_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.tether_settings_summary_usb_and_bluetooth_and_ethernet); + case TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_BLUETOOTH_ON + | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_all); + default: + Log.e(TAG, "Unknown tethering state"); + return mContext.getString(R.string.summary_placeholder); } - - return mContext.getString(R.string.tether_settings_summary_off); } @OnLifecycleEvent(Event.ON_CREATE) @@ -197,11 +207,7 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController @Override public void onTetherStateUpdated(@TetherEnabler.TetheringState int state) { - mTetheringType = 0; - mTetheringType |= TetherEnabler.isBluetoothTethering(state) ? TETHERING_TYPE_BLUETOOTH_ONLY - : 0; - mTetheringType |= TetherEnabler.isWifiTethering(state) ? TETHERING_TYPE_HOTSPOT_ONLY : 0; - mTetheringType |= TetherEnabler.isUsbTethering(state) ? TETHERING_TYPE_USB_ONLY : 0; + mTetheringState = state; updateState(mPreference); } } diff --git a/src/com/android/settings/network/BluetoothTetherPreferenceController.java b/src/com/android/settings/network/BluetoothTetherPreferenceController.java index dc66254e126..ab507da2f9e 100644 --- a/src/com/android/settings/network/BluetoothTetherPreferenceController.java +++ b/src/com/android/settings/network/BluetoothTetherPreferenceController.java @@ -21,51 +21,25 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.net.TetheringManager; +import android.net.ConnectivityManager; import android.text.TextUtils; -import android.util.Log; import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; -import androidx.preference.Preference; import com.google.common.annotations.VisibleForTesting; /** * This controller helps to manage the switch state and visibility of bluetooth tether switch - * preference. It stores preference value when preference changed. + * preference. */ -public final class BluetoothTetherPreferenceController extends TetherBasePreferenceController - implements LifecycleObserver { - - private static final String TAG = "BluetoothTetherPreferenceController"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); +public final class BluetoothTetherPreferenceController extends TetherBasePreferenceController { private int mBluetoothState; - private boolean mBluetoothTethering; public BluetoothTetherPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); } - @Override - public boolean isChecked() { - return mBluetoothTethering; - } - - @Override - public boolean setChecked(boolean isChecked) { - if (mTetherEnabler == null) { - return false; - } - if (isChecked) { - mTetherEnabler.startTethering(TetheringManager.TETHERING_BLUETOOTH); - } else { - mTetherEnabler.stopTethering(TetheringManager.TETHERING_BLUETOOTH); - } - return true; - } - @OnLifecycleEvent(Lifecycle.Event.ON_START) public void onStart() { mBluetoothState = BluetoothAdapter.getDefaultAdapter().getState(); @@ -79,41 +53,30 @@ public final class BluetoothTetherPreferenceController extends TetherBasePrefere } @Override - public void updateState(Preference preference) { - super.updateState(preference); - if (preference == null) { - return; - } - + public boolean shouldEnable() { switch (mBluetoothState) { case BluetoothAdapter.STATE_ON: case BluetoothAdapter.STATE_OFF: // fall through. case BluetoothAdapter.ERROR: - preference.setEnabled(true); - break; + return true; case BluetoothAdapter.STATE_TURNING_OFF: case BluetoothAdapter.STATE_TURNING_ON: // fall through. default: - preference.setEnabled(false); + return false; } } @Override - public int getAvailabilityStatus() { + public boolean shouldShow() { final String[] bluetoothRegexs = mCm.getTetherableBluetoothRegexs(); - if (bluetoothRegexs == null || bluetoothRegexs.length == 0) { - return CONDITIONALLY_UNAVAILABLE; - } else { - return AVAILABLE; - } + return bluetoothRegexs != null && bluetoothRegexs.length != 0; } @Override - public void onTetherStateUpdated(int state) { - mBluetoothTethering = TetherEnabler.isBluetoothTethering(state); - updateState(mPreference); + public int getTetherType() { + return ConnectivityManager.TETHERING_BLUETOOTH; } @VisibleForTesting diff --git a/src/com/android/settings/network/EthernetTetherPreferenceController.java b/src/com/android/settings/network/EthernetTetherPreferenceController.java new file mode 100644 index 00000000000..19c410d8672 --- /dev/null +++ b/src/com/android/settings/network/EthernetTetherPreferenceController.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 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.network; + +import android.content.Context; +import android.net.EthernetManager; +import android.net.TetheringManager; +import android.os.Handler; +import android.os.Looper; +import android.text.TextUtils; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.OnLifecycleEvent; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * This controller helps to manage the switch state and visibility of ethernet tether switch + * preference. + */ +public final class EthernetTetherPreferenceController extends TetherBasePreferenceController { + + private final String mEthernetRegex; + private final EthernetManager mEthernetManager; + @VisibleForTesting + EthernetManager.Listener mEthernetListener; + + public EthernetTetherPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mEthernetRegex = context.getString( + com.android.internal.R.string.config_ethernet_iface_regex); + mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_START) + public void onStart() { + mEthernetListener = new EthernetManager.Listener() { + @Override + public void onAvailabilityChanged(String iface, boolean isAvailable) { + new Handler(Looper.getMainLooper()).post(() -> updateState(mPreference)); + } + }; + mEthernetManager.addListener(mEthernetListener); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + public void onStop() { + mEthernetManager.removeListener(mEthernetListener); + mEthernetListener = null; + } + + @Override + public boolean shouldEnable() { + String[] available = mCm.getTetherableIfaces(); + for (String s : available) { + if (s.matches(mEthernetRegex)) { + return true; + } + } + return false; + } + + @Override + public boolean shouldShow() { + return !TextUtils.isEmpty(mEthernetRegex); + } + + @Override + public int getTetherType() { + return TetheringManager.TETHERING_ETHERNET; + } +} diff --git a/src/com/android/settings/network/TetherBasePreferenceController.java b/src/com/android/settings/network/TetherBasePreferenceController.java index 71bf1166b2b..36ce2a47c93 100644 --- a/src/com/android/settings/network/TetherBasePreferenceController.java +++ b/src/com/android/settings/network/TetherBasePreferenceController.java @@ -18,7 +18,6 @@ package com.android.settings.network; import android.content.Context; import android.net.ConnectivityManager; -import android.util.Log; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; @@ -27,20 +26,26 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.core.TogglePreferenceController; +import com.android.settings.datausage.DataSaverBackend; public abstract class TetherBasePreferenceController extends TogglePreferenceController - implements LifecycleObserver, TetherEnabler.OnTetherStateUpdateListener { + implements LifecycleObserver, DataSaverBackend.Listener, + TetherEnabler.OnTetherStateUpdateListener { private static final String TAG = "TetherBasePreferenceController"; - static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); final ConnectivityManager mCm; + private final DataSaverBackend mDataSaverBackend; - TetherEnabler mTetherEnabler; + private TetherEnabler mTetherEnabler; Preference mPreference; + private boolean mDataSaverEnabled; + int mTetheringState; - public TetherBasePreferenceController(Context context, String preferenceKey) { + TetherBasePreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mDataSaverBackend = new DataSaverBackend(context); + mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); } /** @@ -57,6 +62,7 @@ public abstract class TetherBasePreferenceController extends TogglePreferenceCon if (mTetherEnabler != null) { mTetherEnabler.addListener(this); } + mDataSaverBackend.addListener(this); } @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) @@ -64,6 +70,25 @@ public abstract class TetherBasePreferenceController extends TogglePreferenceCon if (mTetherEnabler != null) { mTetherEnabler.removeListener(this); } + mDataSaverBackend.remListener(this); + } + + @Override + public boolean isChecked() { + return TetherEnabler.isTethering(mTetheringState, getTetherType()); + } + + @Override + public boolean setChecked(boolean isChecked) { + if (mTetherEnabler == null) { + return false; + } + if (isChecked) { + mTetherEnabler.startTethering(getTetherType()); + } else { + mTetherEnabler.stopTethering(getTetherType()); + } + return true; } @Override @@ -71,4 +96,61 @@ public abstract class TetherBasePreferenceController extends TogglePreferenceCon super.displayPreference(screen); mPreference = screen.findPreference(mPreferenceKey); } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (isAvailable()) { + preference.setEnabled(getAvailabilityStatus() != DISABLED_DEPENDENT_SETTING); + } + } + + @Override + public int getAvailabilityStatus() { + if (!shouldShow()) { + return CONDITIONALLY_UNAVAILABLE; + } + + if (mDataSaverEnabled || !shouldEnable()) { + return DISABLED_DEPENDENT_SETTING; + } + return AVAILABLE; + } + + @Override + public void onTetherStateUpdated(@TetherEnabler.TetheringState int state) { + mTetheringState = state; + updateState(mPreference); + } + + @Override + public void onDataSaverChanged(boolean isDataSaving) { + mDataSaverEnabled = isDataSaving; + } + + @Override + public void onWhitelistStatusChanged(int uid, boolean isWhitelisted) { + } + + @Override + public void onBlacklistStatusChanged(int uid, boolean isBlacklisted) { + } + + /** + * Used to enable or disable the preference. + * @return true if the preference should be enabled; false otherwise. + */ + public abstract boolean shouldEnable(); + + /** + * Used to determine visibility of the preference. + * @return true if the preference should be visible; false otherwise. + */ + public abstract boolean shouldShow(); + + /** + * Get the type of tether interface that is controlled by the preference. + * @return the tether interface, like {@link ConnectivityManager#TETHERING_WIFI} + */ + public abstract int getTetherType(); } diff --git a/src/com/android/settings/network/TetherEnabler.java b/src/com/android/settings/network/TetherEnabler.java index 87832d99817..b3c6d615002 100644 --- a/src/com/android/settings/network/TetherEnabler.java +++ b/src/com/android/settings/network/TetherEnabler.java @@ -19,8 +19,7 @@ package com.android.settings.network; import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; import static android.net.ConnectivityManager.TETHERING_USB; import static android.net.ConnectivityManager.TETHERING_WIFI; - -import static com.android.settings.AllInOneTetherSettings.DEDUP_POSTFIX; +import static android.net.TetheringManager.TETHERING_ETHERNET; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -32,8 +31,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; +import android.net.TetheringManager; import android.net.wifi.WifiManager; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; import android.os.UserManager; import android.text.TextUtils; @@ -84,38 +85,37 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe @Retention(SOURCE) @IntDef( flag = true, - value = {TETHERING_OFF, TETHERING_WIFI_ON, TETHERING_USB_ON, TETHERING_BLUETOOTH_ON} + value = { + TETHERING_OFF, + TETHERING_WIFI_ON, + TETHERING_USB_ON, + TETHERING_BLUETOOTH_ON, + TETHERING_ETHERNET_ON + } ) @interface TetheringState {} - @VisibleForTesting - static final int TETHERING_OFF = 0; - @VisibleForTesting - static final int TETHERING_WIFI_ON = 1; - @VisibleForTesting - static final int TETHERING_USB_ON = 1 << 1; - @VisibleForTesting - static final int TETHERING_BLUETOOTH_ON = 1 << 2; - - // This KEY is used for a shared preference value, not for any displayed preferences. - public static final String KEY_ENABLE_WIFI_TETHERING = "enable_wifi_tethering"; - public static final String WIFI_TETHER_DISABLE_KEY = "disable_wifi_tethering"; - public static final String USB_TETHER_KEY = "enable_usb_tethering"; - public static final String BLUETOOTH_TETHER_KEY = "enable_bluetooth_tethering" + DEDUP_POSTFIX; + public static final int TETHERING_OFF = 0; + public static final int TETHERING_WIFI_ON = 1 << TETHERING_WIFI; + public static final int TETHERING_USB_ON = 1 << TETHERING_USB; + public static final int TETHERING_BLUETOOTH_ON = 1 << TETHERING_BLUETOOTH; + public static final int TETHERING_ETHERNET_ON = 1 << TETHERING_ETHERNET; @VisibleForTesting final List mListeners; + private final Handler mMainThreadHandler; private final SwitchWidgetController mSwitchWidgetController; private final WifiManager mWifiManager; private final ConnectivityManager mConnectivityManager; + private final TetheringManager mTetheringManager; private final UserManager mUserManager; - + private final String mEthernetRegex; private final DataSaverBackend mDataSaverBackend; private boolean mDataSaverEnabled; @VisibleForTesting boolean mBluetoothTetheringStoppedByUser; - private final Context mContext; - + @VisibleForTesting + TetheringManager.TetheringEventCallback mTetheringEventCallback; @VisibleForTesting ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback; private final AtomicReference mBluetoothPan; @@ -129,12 +129,16 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mDataSaverBackend = new DataSaverBackend(context); mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mTetheringManager = (TetheringManager) context.getSystemService(Context.TETHERING_SERVICE); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothPan = bluetoothPan; + mEthernetRegex = + context.getString(com.android.internal.R.string.config_ethernet_iface_regex); mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); mListeners = new ArrayList<>(); + mMainThreadHandler = new Handler(Looper.getMainLooper()); } @OnLifecycleEvent(Lifecycle.Event.ON_START) @@ -142,12 +146,20 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mDataSaverBackend.addListener(this); mSwitchWidgetController.setListener(this); mSwitchWidgetController.startListening(); - final IntentFilter filter = new IntentFilter( ConnectivityManager.ACTION_TETHER_STATE_CHANGED); filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); mContext.registerReceiver(mTetherChangeReceiver, filter); + mTetheringEventCallback = + new TetheringManager.TetheringEventCallback() { + @Override + public void onTetheredInterfacesChanged(List interfaces) { + updateState(interfaces.toArray(new String[interfaces.size()])); + } + }; + mTetheringManager.registerTetheringEventCallback(new HandlerExecutor(mMainThreadHandler), + mTetheringEventCallback); mOnStartTetheringCallback = new OnStartTetheringCallback(this); updateState(null/*tethered*/); @@ -159,6 +171,8 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mDataSaverBackend.remListener(this); mSwitchWidgetController.stopListening(); mContext.unregisterReceiver(mTetherChangeReceiver); + mTetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback); + mTetheringEventCallback = null; } public void addListener(OnTetherStateUpdateListener listener) { @@ -193,13 +207,19 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } private void setSwitchCheckedInternal(boolean checked) { - mSwitchWidgetController.stopListening(); + try { + mSwitchWidgetController.stopListening(); + } catch (IllegalStateException e) { + Log.e(TAG, "failed to stop switch widget listener when set check internally"); + return; + } mSwitchWidgetController.setChecked(checked); mSwitchWidgetController.startListening(); } @VisibleForTesting - @TetheringState int getTetheringState(@Nullable String[] tethered) { + @TetheringState + int getTetheringState(@Nullable String[] tethered) { int tetherState = TETHERING_OFF; if (tethered == null) { tethered = mConnectivityManager.getTetheredIfaces(); @@ -223,24 +243,19 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe for (String s : tethered) { for (String regex : usbRegexs) { if (s.matches(regex)) { - return tetherState | TETHERING_USB_ON; + tetherState |= TETHERING_USB_ON; } } + if (s.matches(mEthernetRegex)) { + tetherState |= TETHERING_ETHERNET_ON; + } } return tetherState; } - public static boolean isBluetoothTethering(@TetheringState int state) { - return (state & TETHERING_BLUETOOTH_ON) != TETHERING_OFF; - } - - public static boolean isUsbTethering(@TetheringState int state) { - return (state & TETHERING_USB_ON) != TETHERING_OFF; - } - - public static boolean isWifiTethering(@TetheringState int state) { - return (state & TETHERING_WIFI_ON) != TETHERING_OFF; + public static boolean isTethering(@TetheringState int state, int choice) { + return (state & (1 << choice)) != TETHERING_OFF; } @Override @@ -251,15 +266,14 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe stopTethering(TETHERING_USB); stopTethering(TETHERING_WIFI); stopTethering(TETHERING_BLUETOOTH); + stopTethering(TETHERING_ETHERNET); } return true; } public void stopTethering(int choice) { int state = getTetheringState(null /* tethered */); - if ((choice == TETHERING_WIFI && isWifiTethering(state)) - || (choice == TETHERING_USB && isUsbTethering(state)) - || (choice == TETHERING_BLUETOOTH && isBluetoothTethering(state))) { + if (isTethering(state, choice)) { setSwitchEnabled(false); mConnectivityManager.stopTethering(choice); if (choice == TETHERING_BLUETOOTH) { @@ -272,41 +286,35 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } public void startTethering(int choice) { + if (choice == TETHERING_BLUETOOTH) { + mBluetoothTetheringStoppedByUser = false; + } int state = getTetheringState(null /* tethered */); - if ((choice == TETHERING_WIFI && isWifiTethering(state)) - || (choice == TETHERING_USB && isUsbTethering(state))) { + if (isTethering(state, choice)) { return; } - if (choice == TETHERING_BLUETOOTH) { - mBluetoothTetheringStoppedByUser = false; - if (mBluetoothAdapter == null || isBluetoothTethering(state)) { - return; - } else if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { - if (DEBUG) { - Log.d(TAG, "Turn on bluetooth first."); - } - mBluetoothEnableForTether = true; - mBluetoothAdapter.enable(); - return; + if (choice == TETHERING_BLUETOOTH && mBluetoothAdapter != null + && mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { + if (DEBUG) { + Log.d(TAG, "Turn on bluetooth first."); } + mBluetoothEnableForTether = true; + mBluetoothAdapter.enable(); + return; } setSwitchEnabled(false); mConnectivityManager.startTethering(choice, true /* showProvisioningUi */, - mOnStartTetheringCallback, new Handler(Looper.getMainLooper())); + mOnStartTetheringCallback, mMainThreadHandler); } private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - ArrayList active = null; boolean shouldUpdateState = false; - if (TextUtils.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, action)) { - active = intent.getStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER); - shouldUpdateState = true; - } else if (TextUtils.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION, action)) { + if (TextUtils.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION, action)) { shouldUpdateState = handleWifiApStateChanged(intent.getIntExtra( WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED)); } else if (TextUtils.equals(BluetoothAdapter.ACTION_STATE_CHANGED, action)) { @@ -315,11 +323,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } if (shouldUpdateState) { - if (active != null) { - updateState(active.toArray(new String[0])); - } else { - updateState(null/*tethered*/); - } + updateState(null /* tethered */); } } }; diff --git a/src/com/android/settings/network/UsbTetherPreferenceController.java b/src/com/android/settings/network/UsbTetherPreferenceController.java index a3a42936762..7cf1ddfcf98 100644 --- a/src/com/android/settings/network/UsbTetherPreferenceController.java +++ b/src/com/android/settings/network/UsbTetherPreferenceController.java @@ -21,54 +21,32 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.usb.UsbManager; -import android.net.TetheringManager; +import android.net.ConnectivityManager; import android.os.Environment; import android.text.TextUtils; import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; -import androidx.preference.Preference; import com.android.settings.Utils; /** * This controller helps to manage the switch state and visibility of USB tether switch - * preference. It stores preference values when preference changed. + * preference. * */ -public final class UsbTetherPreferenceController extends TetherBasePreferenceController implements - LifecycleObserver { +public final class UsbTetherPreferenceController extends TetherBasePreferenceController { private static final String TAG = "UsbTetherPrefController"; private boolean mUsbConnected; private boolean mMassStorageActive; - private boolean mUsbTethering; public UsbTetherPreferenceController(Context context, String prefKey) { super(context, prefKey); } - @Override - public boolean isChecked() { - return mUsbTethering; - } - - @Override - public boolean setChecked(boolean isChecked) { - if (mTetherEnabler == null) { - return false; - } - if (isChecked) { - mTetherEnabler.startTethering(TetheringManager.TETHERING_USB); - } else { - mTetherEnabler.stopTethering(TetheringManager.TETHERING_USB); - } - return true; - } - @OnLifecycleEvent(Lifecycle.Event.ON_START) public void onStart() { mMassStorageActive = Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState()); @@ -84,27 +62,19 @@ public final class UsbTetherPreferenceController extends TetherBasePreferenceCon } @Override - public int getAvailabilityStatus() { + public boolean shouldEnable() { + return mUsbConnected && !mMassStorageActive; + } + + @Override + public boolean shouldShow() { String[] usbRegexs = mCm.getTetherableUsbRegexs(); - if (usbRegexs == null || usbRegexs.length == 0 || Utils.isMonkeyRunning()) { - return CONDITIONALLY_UNAVAILABLE; - } else { - return AVAILABLE; - } + return usbRegexs != null && usbRegexs.length != 0 && !Utils.isMonkeyRunning(); } @Override - public void updateState(Preference preference) { - super.updateState(preference); - if (preference != null) { - preference.setEnabled(mUsbConnected && !mMassStorageActive); - } - } - - @Override - public void onTetherStateUpdated(int state) { - mUsbTethering = TetherEnabler.isUsbTethering(state); - updateState(mPreference); + public int getTetherType() { + return ConnectivityManager.TETHERING_USB; } @VisibleForTesting diff --git a/src/com/android/settings/network/WifiTetherDisablePreferenceController.java b/src/com/android/settings/network/WifiTetherDisablePreferenceController.java index 544a886d12e..38e831bd38d 100644 --- a/src/com/android/settings/network/WifiTetherDisablePreferenceController.java +++ b/src/com/android/settings/network/WifiTetherDisablePreferenceController.java @@ -16,34 +16,31 @@ package com.android.settings.network; -import android.content.Context; -import android.net.TetheringManager; +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_WIFI_ON; + +import android.content.Context; +import android.net.ConnectivityManager; -import androidx.lifecycle.LifecycleObserver; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; -import com.android.settingslib.TetherUtil; +import com.android.settings.Utils; /** * This controller helps to manage the switch state and visibility of wifi tether disable switch * preference. When the preference checked, wifi tether will be disabled. - * It stores preference value when preference changed and listens to usb tether and bluetooth tether - * preferences. * * @see BluetoothTetherPreferenceController * @see UsbTetherPreferenceController */ -public final class WifiTetherDisablePreferenceController extends TetherBasePreferenceController - implements LifecycleObserver { +public final class WifiTetherDisablePreferenceController extends TetherBasePreferenceController { private static final String TAG = "WifiTetherDisablePreferenceController"; - private boolean mBluetoothTethering; - private boolean mUsbTethering; - private boolean mWifiTethering; private PreferenceScreen mScreen; public WifiTetherDisablePreferenceController(Context context, String prefKey) { @@ -52,48 +49,57 @@ public final class WifiTetherDisablePreferenceController extends TetherBasePrefe @Override public boolean isChecked() { - return !mWifiTethering; + return !super.isChecked(); } @Override public boolean setChecked(boolean isChecked) { - if (mTetherEnabler == null) { - return false; - } - if (isChecked) { - mTetherEnabler.stopTethering(TetheringManager.TETHERING_WIFI); - } else { - mTetherEnabler.startTethering(TetheringManager.TETHERING_WIFI); - } - return true; + return super.setChecked(!isChecked); } - @VisibleForTesting - boolean shouldShow() { - return mBluetoothTethering || mUsbTethering; + private int getTetheringStateOfOtherInterfaces() { + return mTetheringState & (~TETHERING_WIFI_ON); } @Override - public int getAvailabilityStatus() { + public boolean shouldEnable() { + return true; + } + + @Override + public boolean shouldShow() { final String[] wifiRegexs = mCm.getTetherableWifiRegexs(); - if (wifiRegexs == null || wifiRegexs.length == 0 || !shouldShow() - || !TetherUtil.isTetherAvailable(mContext)) { - return CONDITIONALLY_UNAVAILABLE; - } else { - return AVAILABLE; - } + return wifiRegexs != null && wifiRegexs.length != 0 && !Utils.isMonkeyRunning() + && getTetheringStateOfOtherInterfaces() != TetherEnabler.TETHERING_OFF; + } + + @Override + public int getTetherType() { + return ConnectivityManager.TETHERING_WIFI; } @Override public CharSequence getSummary() { - if (mUsbTethering && mBluetoothTethering) { - return mContext.getString(R.string.disable_wifi_hotspot_when_usb_and_bluetooth_on); - } else if (mUsbTethering) { - return mContext.getString(R.string.disable_wifi_hotspot_when_usb_on); - } else if (mBluetoothTethering) { - return mContext.getString(R.string.disable_wifi_hotspot_when_bluetooth_on); + switch (getTetheringStateOfOtherInterfaces()) { + case TETHERING_USB_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_usb_on); + case TETHERING_BLUETOOTH_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_bluetooth_on); + case TETHERING_ETHERNET_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_ethernet_on); + case TETHERING_USB_ON | TETHERING_BLUETOOTH_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_usb_and_bluetooth_on); + case TETHERING_USB_ON | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_usb_and_ethernet_on); + case TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.disable_wifi_hotspot_when_bluetooth_and_ethernet_on); + case TETHERING_USB_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.disable_wifi_hotspot_when_usb_and_bluetooth_and_ethernet_on); + default: + return mContext.getString(R.string.summary_placeholder); } - return mContext.getString(R.string.summary_placeholder); } @Override @@ -108,15 +114,7 @@ public final class WifiTetherDisablePreferenceController extends TetherBasePrefe @Override public void updateState(Preference preference) { super.updateState(preference); - setVisible(mScreen, mPreferenceKey, shouldShow()); + preference.setVisible(isAvailable()); refreshSummary(preference); } - - @Override - public void onTetherStateUpdated(int state) { - mUsbTethering = TetherEnabler.isUsbTethering(state); - mBluetoothTethering = TetherEnabler.isBluetoothTethering(state); - mWifiTethering = TetherEnabler.isWifiTethering(state); - updateState(mPreference); - } } diff --git a/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java b/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java index f966e3c5e75..c9a8c449d14 100644 --- a/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java +++ b/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java @@ -16,12 +16,13 @@ package com.android.settings; +import static com.android.settings.AllInOneTetherSettings.BLUETOOTH_TETHER_KEY; +import static com.android.settings.AllInOneTetherSettings.ETHERNET_TETHER_KEY; import static com.android.settings.AllInOneTetherSettings.EXPANDED_CHILD_COUNT_DEFAULT; -import static com.android.settings.AllInOneTetherSettings.EXPANDED_CHILD_COUNT_WITHOUT_WIFI_CONFIG; +import static com.android.settings.AllInOneTetherSettings.EXPANDED_CHILD_COUNT_MAX; import static com.android.settings.AllInOneTetherSettings.EXPANDED_CHILD_COUNT_WITH_SECURITY_NON; -import static com.android.settings.network.TetherEnabler.BLUETOOTH_TETHER_KEY; -import static com.android.settings.network.TetherEnabler.USB_TETHER_KEY; -import static com.android.settings.network.TetherEnabler.WIFI_TETHER_DISABLE_KEY; +import static com.android.settings.AllInOneTetherSettings.USB_TETHER_KEY; +import static com.android.settings.AllInOneTetherSettings.WIFI_TETHER_DISABLE_KEY; import static com.google.common.truth.Truth.assertThat; @@ -37,6 +38,9 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.FeatureFlagUtils; +import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceScreen; + import com.android.settings.core.FeatureFlags; import com.android.settings.testutils.shadow.ShadowWifiManager; import com.android.settings.wifi.tether.WifiTetherAutoOffPreferenceController; @@ -62,6 +66,7 @@ public class AllInOneTetherSettingsTest { private static final String[] WIFI_REGEXS = {"wifi_regexs"}; private static final String[] USB_REGEXS = {"usb_regexs"}; private static final String[] BT_REGEXS = {"bt_regexs"}; + private static final String[] ETHERNET_REGEXS = {"ethernet_regexs"}; private Context mContext; private AllInOneTetherSettings mAllInOneTetherSettings; @@ -72,6 +77,10 @@ public class AllInOneTetherSettingsTest { private UserManager mUserManager; @Mock private WifiTetherSecurityPreferenceController mSecurityPreferenceController; + @Mock + private PreferenceScreen mPreferenceScreen; + @Mock + private PreferenceGroup mWifiTetherGroup; @Before public void setUp() { @@ -83,14 +92,16 @@ public class AllInOneTetherSettingsTest { doReturn(WIFI_REGEXS).when(mConnectivityManager).getTetherableWifiRegexs(); doReturn(USB_REGEXS).when(mConnectivityManager).getTetherableUsbRegexs(); doReturn(BT_REGEXS).when(mConnectivityManager).getTetherableBluetoothRegexs(); + doReturn(ETHERNET_REGEXS).when(mConnectivityManager).getTetherableIfaces(); doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE); // Assume the feature is enabled for most test cases. FeatureFlagUtils.setEnabled(mContext, FeatureFlags.TETHER_ALL_IN_ONE, true); - - mAllInOneTetherSettings = new AllInOneTetherSettings(); + mAllInOneTetherSettings = spy(new AllInOneTetherSettings()); + doReturn(mPreferenceScreen).when(mAllInOneTetherSettings).getPreferenceScreen(); ReflectionHelpers.setField(mAllInOneTetherSettings, "mLifecycle", mock(Lifecycle.class)); ReflectionHelpers.setField(mAllInOneTetherSettings, "mSecurityPreferenceController", mSecurityPreferenceController); + ReflectionHelpers.setField(mAllInOneTetherSettings, "mWifiTetherGroup", mWifiTetherGroup); } @Test @@ -110,6 +121,7 @@ public class AllInOneTetherSettingsTest { assertThat(niks).doesNotContain(AllInOneTetherSettings.KEY_WIFI_TETHER_SECURITY); assertThat(niks).doesNotContain(BLUETOOTH_TETHER_KEY); assertThat(niks).doesNotContain(USB_TETHER_KEY); + assertThat(niks).doesNotContain(ETHERNET_TETHER_KEY); // This key should be returned because it's not visible by default. assertThat(niks).contains(WIFI_TETHER_DISABLE_KEY); @@ -131,6 +143,7 @@ public class AllInOneTetherSettingsTest { assertThat(niks).contains(WIFI_TETHER_DISABLE_KEY); assertThat(niks).contains(BLUETOOTH_TETHER_KEY); assertThat(niks).contains(USB_TETHER_KEY); + assertThat(niks).contains(ETHERNET_TETHER_KEY); } @Test @@ -149,6 +162,7 @@ public class AllInOneTetherSettingsTest { assertThat(niks).contains(WIFI_TETHER_DISABLE_KEY); assertThat(niks).doesNotContain(BLUETOOTH_TETHER_KEY); assertThat(niks).doesNotContain(USB_TETHER_KEY); + assertThat(niks).doesNotContain(ETHERNET_TETHER_KEY); } @Test @@ -167,29 +181,31 @@ public class AllInOneTetherSettingsTest { } @Test - public void getInitialExpandedChildCount_shouldShowWifiConfigWithSecurity() { - ReflectionHelpers.setField(mAllInOneTetherSettings, "mWifiTethering", true); + public void getInitialChildCount_withSecurity() { when(mSecurityPreferenceController.getSecurityType()) .thenReturn(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); - assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) - .isEqualTo(EXPANDED_CHILD_COUNT_DEFAULT); + assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()).isEqualTo( + EXPANDED_CHILD_COUNT_DEFAULT); } @Test - public void getInitialExpandedChildCount_shouldShowWifiConfigWithoutSecurity() { - ReflectionHelpers.setField(mAllInOneTetherSettings, "mWifiTethering", true); + public void getInitialChildCount_withoutSecurity() { when(mSecurityPreferenceController.getSecurityType()) .thenReturn(SoftApConfiguration.SECURITY_TYPE_OPEN); - assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) - .isEqualTo(EXPANDED_CHILD_COUNT_WITH_SECURITY_NON); + assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()).isEqualTo( + EXPANDED_CHILD_COUNT_WITH_SECURITY_NON); } @Test - public void getInitialExpandedChildCount_shouldNotShowWifiConfig() { - ReflectionHelpers.setField(mAllInOneTetherSettings, "mWifiTethering", false); - ReflectionHelpers.setField(mAllInOneTetherSettings, "mBluetoothTethering", true); + public void getInitialExpandedChildCount_expandAllChild() { assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) - .isEqualTo(EXPANDED_CHILD_COUNT_WITHOUT_WIFI_CONFIG); + .isNotEqualTo(EXPANDED_CHILD_COUNT_MAX); + ReflectionHelpers.setField(mAllInOneTetherSettings, "mShouldShowWifiConfig", false); + assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) + .isEqualTo(EXPANDED_CHILD_COUNT_MAX); + ReflectionHelpers.setField(mAllInOneTetherSettings, "mShouldShowWifiConfig", true); + assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) + .isEqualTo(EXPANDED_CHILD_COUNT_MAX); } private void setupIsTetherAvailable(boolean returnValue) { diff --git a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java index 282a1709aac..12e687d8222 100644 --- a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java @@ -16,6 +16,14 @@ package com.android.settings.network; +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_OFF; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_WIFI_ON; + +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -27,6 +35,7 @@ import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; import android.content.Context; +import com.android.settings.R; import com.android.settings.widget.MasterSwitchPreference; import org.junit.Before; @@ -34,14 +43,72 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; +import org.robolectric.ParameterizedRobolectricTestRunner; import org.robolectric.util.ReflectionHelpers; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; -@RunWith(RobolectricTestRunner.class) +@RunWith(ParameterizedRobolectricTestRunner.class) public class AllInOneTetherPreferenceControllerTest { + @ParameterizedRobolectricTestRunner.Parameters(name = "TetherState: {0}") + public static List params() { + return Arrays.asList(new Object[][] { + {TETHERING_OFF, R.string.tether_settings_summary_off}, + {TETHERING_WIFI_ON, R.string.tether_settings_summary_hotspot_only}, + {TETHERING_USB_ON, R.string.tether_settings_summary_usb_tethering_only}, + {TETHERING_BLUETOOTH_ON, R.string.tether_settings_summary_bluetooth_tethering_only}, + {TETHERING_ETHERNET_ON, R.string.tether_settings_summary_ethernet_tethering_only}, + { + TETHERING_WIFI_ON | TETHERING_USB_ON, + R.string.tether_settings_summary_hotspot_and_usb + }, + { + TETHERING_WIFI_ON | TETHERING_BLUETOOTH_ON, + R.string.tether_settings_summary_hotspot_and_bluetooth + }, + { + TETHERING_WIFI_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_hotspot_and_ethernet + }, + { + TETHERING_USB_ON | TETHERING_BLUETOOTH_ON, + R.string.tether_settings_summary_usb_and_bluetooth + }, + { + TETHERING_USB_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_usb_and_ethernet + }, + { + TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_bluetooth_and_ethernet + }, + { + TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_BLUETOOTH_ON, + R.string.tether_settings_summary_hotspot_and_usb_and_bluetooth + }, + { + TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_hotspot_and_usb_and_ethernet + }, + { + TETHERING_WIFI_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_hotspot_and_bluetooth_and_ethernet + }, + { + TETHERING_USB_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_usb_and_bluetooth_and_ethernet + }, + { + TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_BLUETOOTH_ON + | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_all + } + }); + } + @Mock private Context mContext; @Mock @@ -50,6 +117,13 @@ public class AllInOneTetherPreferenceControllerTest { private MasterSwitchPreference mPreference; private AllInOneTetherPreferenceController mController; + private final int mTetherState; + private final int mSummaryResId; + + public AllInOneTetherPreferenceControllerTest(int tetherState, int summaryResId) { + mTetherState = tetherState; + mSummaryResId = summaryResId; + } @Before public void setUp() { @@ -90,4 +164,10 @@ public class AllInOneTetherPreferenceControllerTest { verify(mBluetoothAdapter).closeProfileProxy(BluetoothProfile.PAN, pan); } + + @Test + public void getSummary_afterTetherStateChanged() { + mController.onTetherStateUpdated(mTetherState); + assertThat(mController.getSummary()).isEqualTo(mContext.getString(mSummaryResId)); + } } diff --git a/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java index bab82ef250c..3b1f00818ec 100644 --- a/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java @@ -16,8 +16,6 @@ package com.android.settings.network; -import static com.android.settings.network.TetherEnabler.BLUETOOTH_TETHER_KEY; - import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -26,6 +24,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.net.ConnectivityManager; import android.net.TetheringManager; @@ -62,7 +61,7 @@ public class BluetoothTetherPreferenceControllerTest { when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mConnectivityManager); when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[] {""}); - mController = new BluetoothTetherPreferenceController(mContext, BLUETOOTH_TETHER_KEY); + mController = new BluetoothTetherPreferenceController(mContext, "BLUETOOTH"); mController.setTetherEnabler(mTetherEnabler); ReflectionHelpers.setField(mController, "mPreference", mSwitchPreference); } @@ -98,14 +97,17 @@ public class BluetoothTetherPreferenceControllerTest { } @Test - public void display_availableChangedCorrectly() { - when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[] {""}); - assertThat(mController.isAvailable()).isTrue(); - + public void shouldShow_noBluetoothTetherable() { when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[0]); assertThat(mController.isAvailable()).isFalse(); } + @Test + public void shouldEnable_transientState() { + ReflectionHelpers.setField(mController, "mBluetoothState", + BluetoothAdapter.STATE_TURNING_OFF); + assertThat(mController.shouldEnable()).isFalse(); + } @Test public void setChecked_shouldStartBluetoothTethering() { mController.setChecked(true); diff --git a/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java new file mode 100644 index 00000000000..d2e53b85ace --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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.network; + + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.EthernetManager; +import android.net.TetheringManager; + +import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(RobolectricTestRunner.class) +public class EthernetTetherPreferenceControllerTest { + + @Rule + public MockitoRule mocks = MockitoJUnit.rule(); + + @Mock + private ConnectivityManager mConnectivityManager; + @Mock + private EthernetManager mEthernetManager; + @Mock + private TetherEnabler mTetherEnabler; + + private Context mContext; + private EthernetTetherPreferenceController mController; + private SwitchPreference mPreference; + private static final String ETHERNET_REGEX = "ethernet"; + + @Before + public void setUp() { + mContext = spy(ApplicationProvider.getApplicationContext()); + mPreference = spy(SwitchPreference.class); + when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) + .thenReturn(mConnectivityManager); + when(mConnectivityManager.getTetherableIfaces()).thenReturn(new String[]{ETHERNET_REGEX}); + when(mContext.getSystemService(Context.ETHERNET_SERVICE)).thenReturn(mEthernetManager); + mController = new EthernetTetherPreferenceController(mContext, "ethernet"); + mController.setTetherEnabler(mTetherEnabler); + ReflectionHelpers.setField(mController, "mEthernetRegex", ETHERNET_REGEX); + ReflectionHelpers.setField(mController, "mPreference", mPreference); + } + + @Test + public void lifecycle_shouldRegisterReceiverOnStart() { + mController.onStart(); + + verify(mEthernetManager).addListener(eq(mController.mEthernetListener)); + } + + @Test + public void lifecycle_shouldAddListenerOnResume() { + mController.onResume(); + verify(mTetherEnabler).addListener(mController); + } + + @Test + public void lifecycle_shouldRemoveListenerOnPause() { + mController.onPause(); + verify(mTetherEnabler).removeListener(mController); + } + + @Test + public void lifecycle_shouldUnregisterReceiverOnStop() { + mController.onStart(); + EthernetManager.Listener listener = mController.mEthernetListener; + mController.onStop(); + + verify(mEthernetManager).removeListener(eq(listener)); + assertThat(mController.mEthernetListener).isNull(); + } + + @Test + public void shouldEnable_noTetherable() { + when(mConnectivityManager.getTetherableIfaces()).thenReturn(new String[0]); + assertThat(mController.shouldEnable()).isFalse(); + } + + @Test + public void shouldShow_noEthernetInterface() { + ReflectionHelpers.setField(mController, "mEthernetRegex", ""); + assertThat(mController.shouldShow()).isFalse(); + } + + @Test + public void setChecked_shouldStartEthernetTethering() { + mController.setChecked(true); + verify(mTetherEnabler).startTethering(TetheringManager.TETHERING_ETHERNET); + } + + @Test + public void setUnchecked_shouldStopEthernetTethering() { + mController.setChecked(false); + verify(mTetherEnabler).stopTethering(TetheringManager.TETHERING_ETHERNET); + } + + @Test + public void switch_shouldCheckedWhenEthernetTethering() { + mController.onTetherStateUpdated(TetherEnabler.TETHERING_ETHERNET_ON); + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void switch_shouldUnCheckedWhenEthernetNotTethering() { + mController.onTetherStateUpdated(TetherEnabler.TETHERING_OFF); + assertThat(mController.isChecked()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java b/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java index 29d07afc859..87806bed640 100644 --- a/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java +++ b/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java @@ -16,6 +16,17 @@ package com.android.settings.network; +import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; +import static android.net.ConnectivityManager.TETHERING_USB; +import static android.net.ConnectivityManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_ETHERNET; + +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_OFF; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_WIFI_ON; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -63,6 +74,8 @@ public class TetherEnablerTest { @Mock private ConnectivityManager mConnectivityManager; @Mock + private TetheringManager mTetheringManager; + @Mock private NetworkPolicyManager mNetworkPolicyManager; @Mock private BluetoothPan mBluetoothPan; @@ -85,6 +98,7 @@ public class TetherEnablerTest { when(context.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager); when(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mConnectivityManager); + when(context.getSystemService(Context.TETHERING_SERVICE)).thenReturn(mTetheringManager); when(context.getSystemService(Context.NETWORK_POLICY_SERVICE)).thenReturn( mNetworkPolicyManager); when(mConnectivityManager.getTetherableIfaces()).thenReturn(new String[0]); @@ -104,6 +118,23 @@ public class TetherEnablerTest { assertThat(mSwitchBar.isChecked()).isTrue(); } + @Test + public void lifecycle_onStart_shoudRegisterTetheringEventCallback() { + mEnabler.onStart(); + verify(mTetheringManager).registerTetheringEventCallback(any(), + eq(mEnabler.mTetheringEventCallback)); + } + + @Test + public void lifecycle_onStop_shouldUnregisterTetheringEventCallback() { + mEnabler.onStart(); + TetheringManager.TetheringEventCallback callback = mEnabler.mTetheringEventCallback; + + mEnabler.onStop(); + verify(mTetheringManager).unregisterTetheringEventCallback(callback); + assertThat(mEnabler.mTetheringEventCallback).isNull(); + } + @Test public void lifecycle_onStop_resetBluetoothTetheringStoppedByUser() { mEnabler.onStart(); @@ -143,13 +174,40 @@ public class TetherEnablerTest { @Test public void onSwitchToggled_onlyStartsWifiTetherWhenNeeded() { - when(mWifiManager.isWifiApEnabled()).thenReturn(true); + doReturn(TETHERING_WIFI_ON).when(mEnabler).getTetheringState(null /* tethered */); mEnabler.onSwitchToggled(true); verify(mConnectivityManager, never()).startTethering(anyInt(), anyBoolean(), any(), any()); - doReturn(false).when(mWifiManager).isWifiApEnabled(); + doReturn(TETHERING_OFF).when(mEnabler).getTetheringState(null /* tethered */); mEnabler.onSwitchToggled(true); - verify(mConnectivityManager).startTethering(anyInt(), anyBoolean(), any(), any()); + verify(mConnectivityManager).startTethering(eq(TETHERING_WIFI), anyBoolean(), any(), any()); + verify(mConnectivityManager, never()).startTethering(eq(TETHERING_USB), anyBoolean(), any(), + any()); + verify(mConnectivityManager, never()).startTethering(eq(TETHERING_BLUETOOTH), anyBoolean(), + any(), any()); + verify(mConnectivityManager, never()).startTethering(eq(TETHERING_ETHERNET), anyBoolean(), + any(), any()); + } + + @Test + public void onSwitchToggled_stopAllTetheringInterfaces() { + mEnabler.onStart(); + + doReturn(TETHERING_WIFI_ON).when(mEnabler).getTetheringState(null /* tethered */); + mEnabler.onSwitchToggled(false); + verify(mConnectivityManager).stopTethering(TETHERING_WIFI); + + doReturn(TETHERING_USB_ON).when(mEnabler).getTetheringState(null /* tethered */); + mEnabler.onSwitchToggled(false); + verify(mConnectivityManager).stopTethering(TETHERING_USB); + + doReturn(TETHERING_BLUETOOTH_ON).when(mEnabler).getTetheringState(null /* tethered */); + mEnabler.onSwitchToggled(false); + verify(mConnectivityManager).stopTethering(TETHERING_BLUETOOTH); + + doReturn(TETHERING_ETHERNET_ON).when(mEnabler).getTetheringState(null /* tethered */); + mEnabler.onSwitchToggled(false); + verify(mConnectivityManager).stopTethering(TETHERING_ETHERNET); } @Test @@ -169,8 +227,7 @@ public class TetherEnablerTest { public void stopTethering_setBluetoothTetheringStoppedByUserAndUpdateState() { mSwitchWidgetController.setListener(mEnabler); mSwitchWidgetController.startListening(); - int state = TetherEnabler.TETHERING_BLUETOOTH_ON; - doReturn(state).when(mEnabler).getTetheringState(null /* tethered */); + doReturn(TETHERING_BLUETOOTH_ON).when(mEnabler).getTetheringState(null /* tethered */); mEnabler.stopTethering(TetheringManager.TETHERING_BLUETOOTH); assertThat(mEnabler.mBluetoothTetheringStoppedByUser).isTrue(); @@ -238,4 +295,20 @@ public class TetherEnablerTest { mEnabler.removeListener(listener); assertThat(mEnabler.mListeners).doesNotContain(listener); } + + @Test + public void isTethering_shouldReturnCorrectly() { + assertThat(TetherEnabler.isTethering(TETHERING_WIFI_ON, TETHERING_WIFI)).isTrue(); + assertThat(TetherEnabler.isTethering(~TETHERING_WIFI_ON, TETHERING_WIFI)).isFalse(); + + assertThat(TetherEnabler.isTethering(TETHERING_USB_ON, TETHERING_USB)).isTrue(); + assertThat(TetherEnabler.isTethering(~TETHERING_USB_ON, TETHERING_USB)).isFalse(); + + assertThat(TetherEnabler.isTethering(TETHERING_BLUETOOTH_ON, TETHERING_BLUETOOTH)).isTrue(); + assertThat(TetherEnabler.isTethering(~TETHERING_BLUETOOTH_ON, TETHERING_BLUETOOTH)) + .isFalse(); + + assertThat(TetherEnabler.isTethering(TETHERING_ETHERNET_ON, TETHERING_ETHERNET)).isTrue(); + assertThat(TetherEnabler.isTethering(~TETHERING_ETHERNET_ON, TETHERING_ETHERNET)).isFalse(); + } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java index fbb98a4f471..066084edd85 100644 --- a/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java @@ -16,8 +16,6 @@ package com.android.settings.network; -import static com.android.settings.network.TetherEnabler.USB_TETHER_KEY; - import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -61,7 +59,7 @@ public class UsbTetherPreferenceControllerTest { when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mConnectivityManager); when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{""}); - mController = new UsbTetherPreferenceController(mContext, USB_TETHER_KEY); + mController = new UsbTetherPreferenceController(mContext, "USB"); mController.setTetherEnabler(mTetherEnabler); mSwitchPreference = spy(SwitchPreference.class); ReflectionHelpers.setField(mController, "mPreference", mSwitchPreference); @@ -95,12 +93,15 @@ public class UsbTetherPreferenceControllerTest { } @Test - public void display_availableChangedCorrectly() { - when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{""}); - assertThat(mController.isAvailable()).isTrue(); - + public void shouldShow_noTetherableUsb() { when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[0]); - assertThat(mController.isAvailable()).isFalse(); + assertThat(mController.shouldShow()).isFalse(); + } + + @Test + public void shouldEnable_noUsbConnected() { + ReflectionHelpers.setField(mController, "mUsbConnected", false); + assertThat(mController.shouldEnable()).isFalse(); } @Test diff --git a/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java index 211f9329985..1d2042c4ae0 100644 --- a/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java @@ -16,13 +16,15 @@ package com.android.settings.network; -import static com.android.settings.network.TetherEnabler.WIFI_TETHER_DISABLE_KEY; +import static com.android.settings.AllInOneTetherSettings.WIFI_TETHER_DISABLE_KEY; +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_OFF; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; @@ -32,17 +34,48 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.R; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; +import org.robolectric.ParameterizedRobolectricTestRunner; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +import java.util.Arrays; +import java.util.List; + +@RunWith(ParameterizedRobolectricTestRunner.class) public class WifiTetherDisablePreferenceControllerTest { + @ParameterizedRobolectricTestRunner.Parameters(name = "TetherState: {0}") + public static List params() { + return Arrays.asList(new Object[][] { + {TETHERING_OFF, R.string.summary_placeholder}, + {TETHERING_USB_ON, R.string.disable_wifi_hotspot_when_usb_on}, + {TETHERING_BLUETOOTH_ON, R.string.disable_wifi_hotspot_when_bluetooth_on}, + {TETHERING_ETHERNET_ON, R.string.disable_wifi_hotspot_when_ethernet_on}, + { + TETHERING_USB_ON | TETHERING_BLUETOOTH_ON, + R.string.disable_wifi_hotspot_when_usb_and_bluetooth_on + }, + { + TETHERING_USB_ON | TETHERING_ETHERNET_ON, + R.string.disable_wifi_hotspot_when_usb_and_ethernet_on + }, + { + TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.disable_wifi_hotspot_when_bluetooth_and_ethernet_on + }, + { + TETHERING_USB_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.disable_wifi_hotspot_when_usb_and_bluetooth_and_ethernet_on + } + }); + } + @Mock private ConnectivityManager mConnectivityManager; @Mock @@ -53,6 +86,13 @@ public class WifiTetherDisablePreferenceControllerTest { private SwitchPreference mPreference; private Context mContext; private WifiTetherDisablePreferenceController mController; + private final int mTetherState; + private final int mSummaryResId; + + public WifiTetherDisablePreferenceControllerTest(int tetherState, int summaryResId) { + mTetherState = tetherState; + mSummaryResId = summaryResId; + } @Before public void setUp() { @@ -71,21 +111,16 @@ public class WifiTetherDisablePreferenceControllerTest { } @Test - public void display_availableChangedCorrectly() { + public void shouldShow_noTetherableWifi() { when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[0]); - assertThat(mController.isAvailable()).isFalse(); - - when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"test"}); - ReflectionHelpers.setField(mController, "mBluetoothTethering", false); - ReflectionHelpers.setField(mController, "mUsbTethering", false); - assertThat(mController.isAvailable()).isFalse(); + assertThat(mController.shouldShow()).isFalse(); } @Test - public void switch_shouldListenToUsbAndBluetooth() { + public void onTetherStateUpdated_visibilityChangeCorrectly() { int state = TetherEnabler.TETHERING_BLUETOOTH_ON; mController.onTetherStateUpdated(state); - verify(mPreference).setVisible(eq(true)); + assertThat(mController.shouldShow()).isTrue(); state |= TetherEnabler.TETHERING_USB_ON; mController.onTetherStateUpdated(state); @@ -97,6 +132,12 @@ public class WifiTetherDisablePreferenceControllerTest { state = TetherEnabler.TETHERING_OFF; mController.onTetherStateUpdated(state); - verify(mPreference).setVisible(eq(false)); + assertThat(mController.shouldShow()).isFalse(); + } + + @Test + public void getSummary_onTetherStateUpdated() { + mController.onTetherStateUpdated(mTetherState); + assertThat(mController.getSummary()).isEqualTo(mContext.getString(mSummaryResId)); } } From f74c0a72b612d9efabbbf9d008086b865ceaebdc Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Fri, 17 Apr 2020 02:29:56 +0800 Subject: [PATCH 07/16] Show default description only if description and html description are empty * AccessibilitySettings only get the description to pass to the ToggleFeaturePreferenceFragment * ToggleFeaturePreferenceFragment handle the default description logic Bug: 154092127 Test: make -j64 RunSettingsRoboTests ROBOTEST_FILTER="com.android.settings.accessibility.AccessibilitySettingsTest" Change-Id: I516a393aeef1472ca5d185d477a2b0b108fc5342 --- .../accessibility/AccessibilitySettings.java | 13 ++++--------- .../ToggleFeaturePreferenceFragment.java | 17 +++++++++++++---- .../AccessibilitySettingsTest.java | 11 ----------- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index 17750df75e6..3d47ca8dd8d 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -307,11 +307,7 @@ public class AccessibilitySettings extends DashboardFragment { return context.getText(R.string.accessibility_description_state_stopped); } - final String description = info.loadDescription(context.getPackageManager()); - - return TextUtils.isEmpty(description) - ? context.getText(R.string.accessibility_service_default_description) - : description; + return info.loadDescription(context.getPackageManager()); } static boolean isRampingRingerEnabled(final Context context) { @@ -460,7 +456,7 @@ public class AccessibilitySettings extends DashboardFragment { } /** - * Update the order of perferences in the category by matching their preference + * Update the order of preferences in the category by matching their preference * key with the string array of preference order which is defined in the xml. * * @param categoryKey The key of the category need to update the order @@ -708,10 +704,9 @@ public class AccessibilitySettings extends DashboardFragment { CharSequence title, CharSequence summary, int imageRes, String htmlDescription, ComponentName componentName) { final Bundle extras = preference.getExtras(); - extras.putString(EXTRA_PREFERENCE_KEY, prefKey); - extras.putString(EXTRA_TITLE, title.toString()); - extras.putString(EXTRA_SUMMARY, summary.toString()); + extras.putCharSequence(EXTRA_TITLE, title); + extras.putCharSequence(EXTRA_SUMMARY, summary); extras.putParcelable(EXTRA_COMPONENT_NAME, componentName); extras.putInt(EXTRA_ANIMATED_IMAGE_RES, imageRes); extras.putString(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, htmlDescription); diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java index 20ef7bc0e0f..eeb1f3ae5cf 100644 --- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java @@ -83,6 +83,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference protected ComponentName mComponentName; protected CharSequence mPackageName; protected Uri mImageUri; + private CharSequence mDescription; protected CharSequence mHtmlDescription; // Used to restore the edit dialog status. protected int mUserShortcutTypesCache = UserShortcutType.EMPTY; @@ -190,7 +191,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference groupCategory.addPreference(mSettingsPreference); } - if (mHtmlDescription != null) { + if (!TextUtils.isEmpty(mHtmlDescription)) { final PreferenceCategory introductionCategory = new PreferenceCategory( getPrefContext()); final CharSequence title = getString(R.string.accessibility_introduction_title, @@ -205,6 +206,16 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference htmlTextPreference.setSelectable(false); introductionCategory.addPreference(htmlTextPreference); } + + if (!TextUtils.isEmpty(mDescription)) { + createFooterPreference(mDescription); + } + + if (TextUtils.isEmpty(mHtmlDescription) && TextUtils.isEmpty(mDescription)) { + final CharSequence defaultDescription = getText( + R.string.accessibility_service_default_description); + createFooterPreference(defaultDescription); + } } @Override @@ -364,9 +375,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference // Summary. if (arguments.containsKey(AccessibilitySettings.EXTRA_SUMMARY)) { - final CharSequence summary = arguments.getCharSequence( - AccessibilitySettings.EXTRA_SUMMARY); - createFooterPreference(summary); + mDescription = arguments.getCharSequence(AccessibilitySettings.EXTRA_SUMMARY); } // Settings html description. diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java index 98d29184bed..c6a7684dd8e 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java @@ -214,17 +214,6 @@ public class AccessibilitySettingsTest { assertThat(description).isEqualTo(DEFAULT_DESCRIPTION); } - @Test - public void getServiceDescription_noDescription_showsDefaultString() { - doReturn(EMPTY_STRING).when(mServiceInfo).loadDescription(any()); - - final CharSequence description = AccessibilitySettings.getServiceDescription(mContext, - mServiceInfo, SERVICE_ENABLED); - - assertThat(description).isEqualTo( - mContext.getString(R.string.accessibility_service_default_description)); - } - @Test public void createAccessibilityServicePreferenceList_hasOneInfo_containsSameKey() { final String key = DUMMY_COMPONENT_NAME.flattenToString(); From 4fe1de57a5c0034704823b9b053e95ca1a508098 Mon Sep 17 00:00:00 2001 From: Tim Peng Date: Tue, 21 Apr 2020 10:22:15 +0800 Subject: [PATCH 08/16] Change the wording from "Stop casting" to "Stop" -The string is freezed. Reuse current "Stop" string Bug: 153705889 Test: make -j42 RunSettingsRoboTests Change-Id: I39184dcbfda5937677ab171a66ad5dcbbb8e6b68 --- src/com/android/settings/panel/MediaOutputPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/panel/MediaOutputPanel.java b/src/com/android/settings/panel/MediaOutputPanel.java index 1bf6f26ece5..3a4d3410cd1 100644 --- a/src/com/android/settings/panel/MediaOutputPanel.java +++ b/src/com/android/settings/panel/MediaOutputPanel.java @@ -167,7 +167,7 @@ public class MediaOutputPanel implements PanelContent, LocalMediaManager.DeviceC @Override public CharSequence getCustomizedButtonTitle() { - return mContext.getText(R.string.media_output_panel_stop_casting_button); + return mContext.getText(R.string.service_stop); } @Override From 9bc2f7f8bc6821dd617a096a5d719bd630c25b07 Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Mon, 20 Apr 2020 20:11:51 +0800 Subject: [PATCH 09/16] [Settings] Code refactor Minor code refactor Bug: 141833767 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=DataUsagePreferenceControllerTest Change-Id: I060e7c880d91a0e5059610c5ceae319d47c19c7a --- .../telephony/DataUsagePreferenceController.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/network/telephony/DataUsagePreferenceController.java b/src/com/android/settings/network/telephony/DataUsagePreferenceController.java index b8a31fe1852..d9617e6ae5a 100644 --- a/src/com/android/settings/network/telephony/DataUsagePreferenceController.java +++ b/src/com/android/settings/network/telephony/DataUsagePreferenceController.java @@ -44,25 +44,25 @@ public class DataUsagePreferenceController extends TelephonyBasePreferenceContro @Override public int getAvailabilityStatus(int subId) { - return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + return (SubscriptionManager.isValidSubscriptionId(subId)) ? AVAILABLE : AVAILABLE_UNSEARCHABLE; } @Override public boolean handlePreferenceTreeClick(Preference preference) { - if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { - mContext.startActivity(mIntent); - return true; + if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { + return false; } - return false; + mContext.startActivity(mIntent); + return true; } @Override public void updateState(Preference preference) { super.updateState(preference); - if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { preference.setEnabled(false); return; } From 50942484874b1b294cb08a8e52f1201da49c8d22 Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Tue, 21 Apr 2020 14:45:51 +0800 Subject: [PATCH 10/16] Ignore a lot of failed roboletric test cases Bug: 154568213 Bug: 154568594 Bug: 154567856 Bug: 154566065 Bug: 154566012 Bug: 154566007 Bug: 154564960 Bug: 154564366 Bug: 154564361 Bug: 154564994 Bug: 154563784 Bug: 154564243 Bug: 154563562 Bug: 154564136 Bug: 154564211 Bug: 154563778 Bug: 154563910 Bug: 154562715 Bug: 154563116 Bug: 154562264 Bug: 154562785 Bug: 154563290 Bug: 154561690 Bug: 154562361 Bug: 154560878 Bug: 154560145 Test: make RunSettingsRoboTests Change-Id: I220540d519b222ad7d3b69070a9262bb25f22d23 --- .../specialaccess/PaymentSettingsEnablerTest.java | 2 ++ .../connecteddevice/NfcAndPaymentFragmentTest.java | 2 ++ .../settings/datausage/CellDataPreferenceTest.java | 2 ++ .../DataUsageSummaryPreferenceControllerTest.java | 13 +++++++++++++ .../settings/datausage/DataUsageSummaryTest.java | 3 +++ .../settings/datausage/DataUsageUtilsTest.java | 3 +++ ...cedMacRandomizationPreferenceControllerTest.java | 2 ++ ...ightDisplayAutoModePreferenceControllerTest.java | 3 ++- .../DarkModeScheduleSelectorControllerTest.java | 2 ++ ...isabledInDsdsFooterPreferenceControllerTest.java | 2 ++ .../notification/RedactionInterstitialTest.java | 3 +++ .../notification/zen/ZenModeSettingsTest.java | 2 ++ 12 files changed, 38 insertions(+), 1 deletion(-) diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/PaymentSettingsEnablerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/PaymentSettingsEnablerTest.java index f1d8952c741..62b95d191fd 100644 --- a/tests/robotests/src/com/android/settings/applications/specialaccess/PaymentSettingsEnablerTest.java +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/PaymentSettingsEnablerTest.java @@ -28,6 +28,7 @@ import androidx.preference.Preference; import com.android.settings.R; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; @@ -35,6 +36,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) +@Ignore public class PaymentSettingsEnablerTest { private Context mContext; private Preference mPreference; diff --git a/tests/robotests/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentTest.java index af68784a4c5..6a151081578 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentTest.java @@ -26,6 +26,7 @@ import android.nfc.NfcAdapter; import android.provider.SearchIndexableResource; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -62,6 +63,7 @@ public class NfcAndPaymentFragmentTest { } @Test + @Ignore public void searchIndexProvider_shouldIndexAllItems() { when(mContext.getApplicationContext()).thenReturn(mContext); when(NfcAdapter.getDefaultAdapter(mContext)).thenReturn(mNfcAdapter); diff --git a/tests/robotests/src/com/android/settings/datausage/CellDataPreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/CellDataPreferenceTest.java index 0b8ebbf8519..5f2a54c5bc7 100644 --- a/tests/robotests/src/com/android/settings/datausage/CellDataPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/datausage/CellDataPreferenceTest.java @@ -31,6 +31,7 @@ import androidx.preference.PreferenceViewHolder; import com.android.settings.network.ProxySubscriptionManager; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -39,6 +40,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) +@Ignore public class CellDataPreferenceTest { @Mock diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java index eab3dde65f9..a0a5f1272ed 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java @@ -52,6 +52,7 @@ import com.android.settingslib.net.DataUsageController; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -144,6 +145,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testSummaryUpdate_onePlan_basic() { final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); @@ -169,6 +171,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testSummaryUpdate_noPlan_basic() { final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); @@ -194,6 +197,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testSummaryUpdate_noCarrier_basic() { final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); @@ -221,6 +225,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testSummaryUpdate_noPlanData_basic() { final long now = System.currentTimeMillis(); @@ -248,6 +253,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testSummaryUpdate_noLimitNoWarning() { final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); @@ -265,6 +271,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testSummaryUpdate_warningOnly() { final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); @@ -286,6 +293,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testSummaryUpdate_limitOnly() { final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); @@ -307,6 +315,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testSummaryUpdate_limitAndWarning() { final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); @@ -330,6 +339,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testSummaryUpdate_noSim_shouldSetWifiMode() { final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); @@ -354,6 +364,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testMobileData_preferenceAvailable() { mController = new DataUsageSummaryPreferenceController( mDataUsageController, @@ -368,6 +379,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testMobileData_noSimNoWifi_preferenceDisabled() { mController = new DataUsageSummaryPreferenceController( mDataUsageController, @@ -385,6 +397,7 @@ public class DataUsageSummaryPreferenceControllerTest { } @Test + @Ignore public void testMobileData_noSimWifi_preferenceDisabled() { mController = new DataUsageSummaryPreferenceController( mDataUsageController, diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java index d5eaa9a7d62..1b21bbfc885 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java @@ -125,6 +125,7 @@ public class DataUsageSummaryTest { } @Test + @Ignore public void configuration_withoutSim_shouldShowWifiSectionOnly() { ShadowDataUsageUtils.IS_MOBILE_DATA_SUPPORTED = true; ShadowDataUsageUtils.IS_WIFI_SUPPORTED = true; @@ -144,6 +145,7 @@ public class DataUsageSummaryTest { } @Test + @Ignore public void configuration_withoutMobile_shouldShowWifiSectionOnly() { ShadowDataUsageUtils.IS_MOBILE_DATA_SUPPORTED = false; ShadowDataUsageUtils.IS_WIFI_SUPPORTED = true; @@ -164,6 +166,7 @@ public class DataUsageSummaryTest { @Test @Config(shadows = ShadowSubscriptionManager.class) + @Ignore public void configuration_invalidDataSusbscription_shouldShowWifiSectionOnly() { ShadowDataUsageUtils.IS_MOBILE_DATA_SUPPORTED = true; ShadowDataUsageUtils.IS_WIFI_SUPPORTED = true; diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java index fe02cb1192e..33ac764ee2d 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java @@ -31,6 +31,7 @@ import android.telephony.TelephonyManager; import android.util.DataUnit; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -76,6 +77,7 @@ public final class DataUsageUtilsTest { } @Test + @Ignore public void hasSim_simStateReady() { when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY); final boolean hasSim = DataUsageUtils.hasSim(mContext); @@ -83,6 +85,7 @@ public final class DataUsageUtilsTest { } @Test + @Ignore public void hasSim_simStateMissing() { when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_ABSENT); final boolean hasSim = DataUsageUtils.hasSim(mContext); diff --git a/tests/robotests/src/com/android/settings/development/WifiEnhancedMacRandomizationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/WifiEnhancedMacRandomizationPreferenceControllerTest.java index 4a45ce70387..862f78f7d14 100644 --- a/tests/robotests/src/com/android/settings/development/WifiEnhancedMacRandomizationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/WifiEnhancedMacRandomizationPreferenceControllerTest.java @@ -27,6 +27,7 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -74,6 +75,7 @@ public class WifiEnhancedMacRandomizationPreferenceControllerTest { } @Test + @Ignore public void updateState_preferenceShouldBeChecked() { Settings.Global.putInt(mContext.getContentResolver(), ENHANCED_MAC_RANDOMIZATION_FEATURE_FLAG, 1); diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java index de5c81e037a..d6500dbb927 100644 --- a/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java @@ -18,12 +18,12 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.hardware.display.ColorDisplayManager; -import android.provider.Settings.Secure; import com.android.settings.testutils.shadow.SettingsShadowResources; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -64,6 +64,7 @@ public class NightDisplayAutoModePreferenceControllerTest { } @Test + @Ignore public void onPreferenceChange_changesAutoMode() { mController.onPreferenceChange(null, String.valueOf(ColorDisplayManager.AUTO_MODE_TWILIGHT)); diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java index d741235ff56..92ecdc83315 100644 --- a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java @@ -37,6 +37,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -102,6 +103,7 @@ public class DarkModeScheduleSelectorControllerTest { } @Test + @Ignore public void nightMode_selectNightMode_locationOff() { when(mLocationManager.isLocationEnabled()).thenReturn(false); mController.onPreferenceChange(mPreference, diff --git a/tests/robotests/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceControllerTest.java index c75d874e25c..2cd4d4293e8 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceControllerTest.java @@ -27,6 +27,7 @@ import android.content.Context; import android.telephony.TelephonyManager; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -59,6 +60,7 @@ public class NrDisabledInDsdsFooterPreferenceControllerTest { } @Test + @Ignore public void isAvailable_dataOnAndDsdsAnd5GSupported_Available() { when(mTelephonyManager.getSupportedRadioAccessFamily()) .thenReturn(TelephonyManager.NETWORK_TYPE_BITMASK_NR); diff --git a/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java b/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java index a2ca62eda6b..081f76421f6 100644 --- a/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java +++ b/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java @@ -25,6 +25,7 @@ import com.android.settings.testutils.shadow.ShadowUtils; import org.junit.After; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -102,6 +103,7 @@ public class RedactionInterstitialTest { } @Test + @Ignore public void managedProfileNoRestrictionsTest() { setupSettings(1 /* show */, 1 /* showUnredacted */); final ShadowUserManager sum = @@ -115,6 +117,7 @@ public class RedactionInterstitialTest { } @Test + @Ignore public void managedProfileUnredactedRestrictionTest() { setupSettings(1 /* show */, 1 /* showUnredacted */); final ShadowUserManager sum = diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeSettingsTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeSettingsTest.java index ea750560572..352c0435128 100644 --- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeSettingsTest.java +++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeSettingsTest.java @@ -29,6 +29,7 @@ import com.android.settings.R; import com.android.settings.notification.zen.ZenModeSettings; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -70,6 +71,7 @@ public class ZenModeSettingsTest { } @Test + @Ignore public void testGetCallsSettingSummary_none() { Policy policy = new Policy(0, 0, 0, 0); assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Don\u2019t allow any calls"); From dcef423720eeda987811ccaf65a8de0f4c72e64c Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Sun, 19 Apr 2020 17:54:33 +0800 Subject: [PATCH 11/16] [Settings] Refactor test case DataUsageSummaryPreferenceControllerTest Refactor test case of DataUsageSummaryPreferenceControllerTest Bug: 141833767 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=DataUsageSummaryPreferenceControllerTest Change-Id: Ieb551a32d87c53cbd0765e19e710f1f0469da9d5 --- .../DataUsageSummaryPreferenceController.java | 87 ++++----- ...aUsageSummaryPreferenceControllerTest.java | 181 ++++++++++-------- 2 files changed, 142 insertions(+), 126 deletions(-) diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java index bfe78e5de07..42c2b736839 100644 --- a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java +++ b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java @@ -68,13 +68,12 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll private final EntityHeaderController mEntityHeaderController; private final Lifecycle mLifecycle; private final PreferenceFragmentCompat mFragment; - protected final DataUsageController mDataUsageController; - protected final DataUsageInfoController mDataInfoController; - private final NetworkTemplate mDefaultTemplate; - protected final NetworkPolicyEditor mPolicyEditor; - private final int mDataUsageTemplate; - private final boolean mHasMobileData; - private final SubscriptionManager mSubscriptionManager; + protected DataUsageController mDataUsageController; + protected DataUsageInfoController mDataInfoController; + private NetworkTemplate mDefaultTemplate; + protected NetworkPolicyEditor mPolicyEditor; + private int mDataUsageTemplate; + private boolean mHasMobileData; /** Name of the carrier, or null if not available */ private CharSequence mCarrierName; @@ -112,29 +111,31 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll fragment, null); mLifecycle = lifecycle; mFragment = fragment; + init(subscriptionId); + } + + protected void init(int subscriptionId) { mSubscriptionId = subscriptionId; - mDefaultTemplate = DataUsageUtils.getDefaultTemplate(activity, mSubscriptionId); - NetworkPolicyManager policyManager = activity.getSystemService(NetworkPolicyManager.class); + mDefaultTemplate = DataUsageUtils.getDefaultTemplate(mContext, mSubscriptionId); + final NetworkPolicyManager policyManager = + mContext.getSystemService(NetworkPolicyManager.class); mPolicyEditor = new NetworkPolicyEditor(policyManager); mHasMobileData = SubscriptionManager.isValidSubscriptionId(mSubscriptionId) - && DataUsageUtils.hasMobileData(activity); + && DataUsageUtils.hasMobileData(mContext); - mDataUsageController = new DataUsageController(activity); + mDataUsageController = new DataUsageController(mContext); mDataUsageController.setSubscriptionId(mSubscriptionId); mDataInfoController = new DataUsageInfoController(); if (mHasMobileData) { mDataUsageTemplate = R.string.cell_data_template; - } else if (DataUsageUtils.hasWifiRadio(activity)) { + } else if (DataUsageUtils.hasWifiRadio(mContext)) { mDataUsageTemplate = R.string.wifi_data_template; } else { mDataUsageTemplate = R.string.ethernet_data_template; } - - mSubscriptionManager = (SubscriptionManager) - mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); } @VisibleForTesting @@ -144,8 +145,6 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll NetworkTemplate defaultTemplate, NetworkPolicyEditor policyEditor, int dataUsageTemplate, - boolean hasMobileData, - SubscriptionManager subscriptionManager, Activity activity, Lifecycle lifecycle, EntityHeaderController entityHeaderController, @@ -157,8 +156,7 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll mDefaultTemplate = defaultTemplate; mPolicyEditor = policyEditor; mDataUsageTemplate = dataUsageTemplate; - mHasMobileData = hasMobileData; - mSubscriptionManager = subscriptionManager; + mHasMobileData = true; mActivity = activity; mLifecycle = lifecycle; mEntityHeaderController = entityHeaderController; @@ -174,24 +172,25 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll } @VisibleForTesting - void setPlanValues(int dataPlanCount, long dataPlanSize, long dataPlanUse) { - mDataplanCount = dataPlanCount; - mDataplanSize = dataPlanSize; - mDataBarSize = dataPlanSize; - mDataplanUse = dataPlanUse; + List getSubscriptionPlans(int subscriptionId) { + return ProxySubscriptionManager.getInstance(mContext).get() + .getSubscriptionPlans(subscriptionId); } @VisibleForTesting - void setCarrierValues(String carrierName, long snapshotTime, long cycleEnd, Intent intent) { - mCarrierName = carrierName; - mSnapshotTime = snapshotTime; - mCycleEnd = cycleEnd; - mManageSubscriptionIntent = intent; + SubscriptionInfo getSubscriptionInfo(int subscriptionId) { + return ProxySubscriptionManager.getInstance(mContext) + .getAccessibleSubscriptionInfo(subscriptionId); + } + + @VisibleForTesting + boolean hasSim() { + return DataUsageUtils.hasSim(mContext); } @Override public int getAvailabilityStatus() { - return DataUsageUtils.hasSim(mActivity) + return hasSim() || DataUsageUtils.hasWifiRadio(mContext) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @@ -200,7 +199,8 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll DataUsageSummaryPreference summaryPreference = (DataUsageSummaryPreference) preference; final DataUsageController.DataUsageInfo info; - if (DataUsageUtils.hasSim(mActivity)) { + final SubscriptionInfo subInfo = getSubscriptionInfo(mSubscriptionId); + if (hasSim()) { info = mDataUsageController.getDataUsageInfo(mDefaultTemplate); mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(mDefaultTemplate)); summaryPreference.setWifiMode(/* isWifiMode */ false, @@ -223,9 +223,7 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll return; } - if (mSubscriptionManager != null) { - refreshDataplanInfo(info); - } + refreshDataplanInfo(info, subInfo); if (info.warningLevel > 0 && info.limitLevel > 0) { summaryPreference.setLimitInfo(TextUtils.expandTemplate( @@ -260,7 +258,8 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll // TODO(b/70950124) add test for this method once the robolectric shadow run script is // completed (b/3526807) - private void refreshDataplanInfo(DataUsageController.DataUsageInfo info) { + private void refreshDataplanInfo(DataUsageController.DataUsageInfo info, + SubscriptionInfo subInfo) { // reset data before overwriting mCarrierName = null; mDataplanCount = 0; @@ -271,16 +270,10 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll mCycleEnd = info.cycleEnd; mSnapshotTime = -1L; - final ProxySubscriptionManager proxySubsciptionMgr = - ProxySubscriptionManager.getInstance(mContext); - final SubscriptionInfo subInfo = proxySubsciptionMgr - .getAccessibleSubscriptionInfo(mSubscriptionId); if (subInfo != null && mHasMobileData) { mCarrierName = subInfo.getCarrierName(); - List plans = mSubscriptionManager.getSubscriptionPlans( - mSubscriptionId); - final SubscriptionPlan primaryPlan = getPrimaryPlan(mSubscriptionManager, - mSubscriptionId); + final List plans = getSubscriptionPlans(mSubscriptionId); + final SubscriptionPlan primaryPlan = getPrimaryPlan(plans); if (primaryPlan != null) { mDataplanCount = plans.size(); @@ -313,7 +306,8 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll * {@code null} if no carrier app is defined, or if the defined * carrier app provides no management activity. */ - private Intent createManageSubscriptionIntent(int subId) { + @VisibleForTesting + Intent createManageSubscriptionIntent(int subId) { final INetworkPolicyManager iNetPolicyManager = INetworkPolicyManager.Stub.asInterface( ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); String owner = ""; @@ -327,7 +321,7 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll return null; } - final List plans = mSubscriptionManager.getSubscriptionPlans(subId); + final List plans = getSubscriptionPlans(subId); if (plans.isEmpty()) { return null; } @@ -344,8 +338,7 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll return intent; } - public static SubscriptionPlan getPrimaryPlan(SubscriptionManager subManager, int primaryId) { - List plans = subManager.getSubscriptionPlans(primaryId); + private static SubscriptionPlan getPrimaryPlan(List plans) { if (CollectionUtils.isEmpty(plans)) { return null; } diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java index eab3dde65f9..d6f3e947d87 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java @@ -34,8 +34,11 @@ import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkTemplate; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionPlan; import android.telephony.TelephonyManager; +import android.util.RecurrenceRule; import androidx.fragment.app.FragmentActivity; import androidx.preference.PreferenceFragmentCompat; @@ -63,6 +66,10 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import java.time.Instant; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; @RunWith(RobolectricTestRunner.class) @@ -86,7 +93,9 @@ public class DataUsageSummaryPreferenceControllerTest { @Mock private NetworkTemplate mNetworkTemplate; @Mock - private SubscriptionManager mSubscriptionManager; + private SubscriptionInfo mSubscriptionInfo; + @Mock + private SubscriptionPlan mSubscriptionPlan; @Mock private Lifecycle mLifecycle; @Mock(answer = Answers.RETURNS_DEEP_STUBS) @@ -105,6 +114,7 @@ public class DataUsageSummaryPreferenceControllerTest { private Context mContext; private DataUsageSummaryPreferenceController mController; private int mDefaultSubscriptionId; + private List mSubscriptionPlans; @Before public void setUp() { @@ -112,30 +122,45 @@ public class DataUsageSummaryPreferenceControllerTest { mContext = spy(RuntimeEnvironment.application); doReturn("%1$s %2%s").when(mContext) - .getString(com.android.internal.R.string.fileSizeSuffix); + .getString(com.android.internal.R.string.fileSizeSuffix); + + mDefaultSubscriptionId = 1234; + mSubscriptionPlans = new ArrayList(); mFactory = FakeFeatureFactory.setupForTest(); when(mFactory.metricsFeatureProvider.getMetricsCategory(any(Object.class))) .thenReturn(MetricsProto.MetricsEvent.SETTINGS_APP_NOTIF_CATEGORY); ShadowEntityHeaderController.setUseMock(mHeaderController); - mDataInfoController = new DataUsageInfoController(); + + mDataInfoController = spy(new DataUsageInfoController()); + doReturn(-1L).when(mDataInfoController).getSummaryLimit(any()); mActivity = spy(Robolectric.buildActivity(FragmentActivity.class).get()); - when(mActivity.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); + doReturn(mTelephonyManager).when(mActivity).getSystemService(TelephonyManager.class); + doReturn(mTelephonyManager).when(mTelephonyManager) + .createForSubscriptionId(mDefaultSubscriptionId); when(mActivity.getSystemService(Context.CONNECTIVITY_SERVICE)) .thenReturn(mConnectivityManager); - when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY); + doReturn(TelephonyManager.SIM_STATE_READY).when(mTelephonyManager).getSimState(); when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(false); - mDefaultSubscriptionId = 1234; - mController = new DataUsageSummaryPreferenceController( + + mController = spy(new DataUsageSummaryPreferenceController( mDataUsageController, mDataInfoController, mNetworkTemplate, mPolicyEditor, R.string.cell_data_template, - true, - null, - mActivity, null, null, null, mDefaultSubscriptionId); + mActivity, null, null, null, mDefaultSubscriptionId)); + doReturn(null).when(mController).getSubscriptionInfo( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + doReturn(null).when(mController).getSubscriptionPlans( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + + doReturn(CARRIER_NAME).when(mSubscriptionInfo).getCarrierName(); + doReturn(mSubscriptionInfo).when(mController).getSubscriptionInfo(mDefaultSubscriptionId); + doReturn(mSubscriptionPlans).when(mController).getSubscriptionPlans(mDefaultSubscriptionId); + + doReturn(true).when(mController).hasSim(); } @After @@ -150,9 +175,10 @@ public class DataUsageSummaryPreferenceControllerTest { final Intent intent = new Intent(); - when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info); - mController.setPlanValues(1 /* dataPlanCount */, LIMIT1, USAGE1); - mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent); + doReturn(info).when(mDataUsageController).getDataUsageInfo(any()); + setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS); + createTestDataPlan(info.cycleStart, info.cycleEnd); + doReturn(intent).when(mController).createManageSubscriptionIntent(mDefaultSubscriptionId); mController.updateState(mSummaryPreference); @@ -161,7 +187,8 @@ public class DataUsageSummaryPreferenceControllerTest { CharSequence value = captor.getValue(); assertThat(value.toString()).isEqualTo("512 MB data warning / 1.00 GB data limit"); - verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS, + verify(mSummaryPreference).setUsageInfo((info.cycleEnd / 1000) * 1000, + now - UPDATE_BACKOFF_MS, CARRIER_NAME, 1 /* numPlans */, intent); verify(mSummaryPreference).setChartEnabled(true); verify(mSummaryPreference).setWifiMode(false /* isWifiMode */, null /* usagePeriod */, @@ -175,9 +202,8 @@ public class DataUsageSummaryPreferenceControllerTest { final Intent intent = new Intent(); - when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info); - mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1); - mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent); + doReturn(info).when(mDataUsageController).getDataUsageInfo(any()); + setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS); mController.updateState(mSummaryPreference); @@ -186,8 +212,12 @@ public class DataUsageSummaryPreferenceControllerTest { CharSequence value = captor.getValue(); assertThat(value.toString()).isEqualTo("512 MB data warning / 1.00 GB data limit"); - verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS, - CARRIER_NAME, 0 /* numPlans */, intent); + verify(mSummaryPreference).setUsageInfo( + info.cycleEnd, + -1L /* snapshotTime */, + CARRIER_NAME, + 0 /* numPlans */, + null /* launchIntent */); verify(mSummaryPreference).setChartEnabled(true); verify(mSummaryPreference).setWifiMode(false /* isWifiMode */, null /* usagePeriod */, false /* isSingleWifi */); @@ -198,10 +228,10 @@ public class DataUsageSummaryPreferenceControllerTest { final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); - when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info); - mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1); - mController.setCarrierValues(null /* carrierName */, -1L /* snapshotTime */, - info.cycleEnd, null /* intent */); + doReturn(info).when(mDataUsageController).getDataUsageInfo(any()); + doReturn(null).when(mSubscriptionInfo).getCarrierName(); + setupTestDataUsage(LIMIT1, USAGE1, -1L /* snapshotTime */); + mController.updateState(mSummaryPreference); ArgumentCaptor captor = ArgumentCaptor.forClass(CharSequence.class); @@ -226,10 +256,10 @@ public class DataUsageSummaryPreferenceControllerTest { final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); - when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info); - mController.setPlanValues(0 /* dataPlanCount */, -1L /* dataPlanSize */, USAGE1); - mController.setCarrierValues(null /* carrierName */, -1L /* snapshotTime */, - info.cycleEnd, null /* intent */); + doReturn(info).when(mDataUsageController).getDataUsageInfo(any()); + doReturn(null).when(mSubscriptionInfo).getCarrierName(); + setupTestDataUsage(-1L /* dataPlanSize */, USAGE1, -1L /* snapshotTime */); + mController.updateState(mSummaryPreference); ArgumentCaptor captor = ArgumentCaptor.forClass(CharSequence.class); @@ -256,9 +286,8 @@ public class DataUsageSummaryPreferenceControllerTest { final Intent intent = new Intent(); - when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info); - mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1); - mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent); + doReturn(info).when(mDataUsageController).getDataUsageInfo(any()); + setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS); mController.updateState(mSummaryPreference); verify(mSummaryPreference).setLimitInfo(null); @@ -273,9 +302,8 @@ public class DataUsageSummaryPreferenceControllerTest { final Intent intent = new Intent(); - when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info); - mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1); - mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent); + doReturn(info).when(mDataUsageController).getDataUsageInfo(any()); + setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS); mController.updateState(mSummaryPreference); @@ -294,9 +322,8 @@ public class DataUsageSummaryPreferenceControllerTest { final Intent intent = new Intent(); - when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info); - mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1); - mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent); + doReturn(info).when(mDataUsageController).getDataUsageInfo(any()); + setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS); mController.updateState(mSummaryPreference); @@ -315,9 +342,8 @@ public class DataUsageSummaryPreferenceControllerTest { final Intent intent = new Intent(); - when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info); - mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1); - mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent); + doReturn(info).when(mDataUsageController).getDataUsageInfo(any()); + setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS); mController.updateState(mSummaryPreference); @@ -331,6 +357,11 @@ public class DataUsageSummaryPreferenceControllerTest { @Test public void testSummaryUpdate_noSim_shouldSetWifiMode() { + mController.init(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mController.mDataUsageController = mDataUsageController; + doReturn(TelephonyManager.SIM_STATE_ABSENT).when(mTelephonyManager).getSimState(); + doReturn(false).when(mController).hasSim(); + final long now = System.currentTimeMillis(); final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now); info.warningLevel = BillingCycleSettings.MIB_IN_BYTES; @@ -338,11 +369,9 @@ public class DataUsageSummaryPreferenceControllerTest { final Intent intent = new Intent(); - when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info); - mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1); - mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent); + doReturn(info).when(mDataUsageController).getDataUsageInfo(any()); + setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS); - when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_ABSENT); mController.updateState(mSummaryPreference); verify(mSummaryPreference).setWifiMode(true /* isWifiMode */, info.period /* usagePeriod */, @@ -355,48 +384,27 @@ public class DataUsageSummaryPreferenceControllerTest { @Test public void testMobileData_preferenceAvailable() { - mController = new DataUsageSummaryPreferenceController( - mDataUsageController, - mDataInfoController, - mNetworkTemplate, - mPolicyEditor, - R.string.cell_data_template, - true, - mSubscriptionManager, - mActivity, null, null, null, mDefaultSubscriptionId); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test public void testMobileData_noSimNoWifi_preferenceDisabled() { - mController = new DataUsageSummaryPreferenceController( - mDataUsageController, - mDataInfoController, - mNetworkTemplate, - mPolicyEditor, - R.string.cell_data_template, - true, - mSubscriptionManager, - mActivity, null, null, null, mDefaultSubscriptionId); - - when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_ABSENT); + final int subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + mController.init(subscriptionId); + mController.mDataUsageController = mDataUsageController; + doReturn(TelephonyManager.SIM_STATE_ABSENT).when(mTelephonyManager).getSimState(); + doReturn(false).when(mController).hasSim(); when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(false); - assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(CONDITIONALLY_UNAVAILABLE); } @Test public void testMobileData_noSimWifi_preferenceDisabled() { - mController = new DataUsageSummaryPreferenceController( - mDataUsageController, - mDataInfoController, - mNetworkTemplate, - mPolicyEditor, - R.string.cell_data_template, - true, - mSubscriptionManager, - mActivity, null, null, null, mDefaultSubscriptionId); - - when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_ABSENT); + final int subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + mController.init(subscriptionId); + mController.mDataUsageController = mDataUsageController; + doReturn(TelephonyManager.SIM_STATE_ABSENT).when(mTelephonyManager).getSimState(); when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(true); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @@ -405,16 +413,14 @@ public class DataUsageSummaryPreferenceControllerTest { public void testMobileData_entityHeaderSet() { final RecyclerView recyclerView = new RecyclerView(mActivity); - mController = new DataUsageSummaryPreferenceController( + mController = spy(new DataUsageSummaryPreferenceController( mDataUsageController, mDataInfoController, mNetworkTemplate, mPolicyEditor, R.string.cell_data_template, - true, - mSubscriptionManager, mActivity, mLifecycle, mHeaderController, mPreferenceFragment, - mDefaultSubscriptionId); + mDefaultSubscriptionId)); when(mPreferenceFragment.getListView()).thenReturn(recyclerView); @@ -437,4 +443,21 @@ public class DataUsageSummaryPreferenceControllerTest { info.cycleEnd = info.cycleStart + CYCLE_LENGTH_MS; return info; } + + private void setupTestDataUsage(long dataPlanSize, long dataUsageSize, long snapshotTime) { + doReturn(dataPlanSize).when(mSubscriptionPlan).getDataLimitBytes(); + doReturn(dataUsageSize).when(mSubscriptionPlan).getDataUsageBytes(); + doReturn(snapshotTime).when(mSubscriptionPlan).getDataUsageTime(); + + doReturn(dataPlanSize).when(mDataInfoController).getSummaryLimit(any()); + } + + private void createTestDataPlan(long startTime, long endTime) { + final RecurrenceRule recurrenceRule = new RecurrenceRule( + Instant.ofEpochMilli(startTime).atZone(ZoneId.systemDefault()), + Instant.ofEpochMilli(endTime).atZone(ZoneId.systemDefault()), + null); + doReturn(recurrenceRule).when(mSubscriptionPlan).getCycleRule(); + mSubscriptionPlans.add(mSubscriptionPlan); + } } From 205b585cf3652d3bde5a20c3eb67d64ea0a85268 Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Tue, 21 Apr 2020 12:10:30 +0800 Subject: [PATCH 12/16] [Wi-Fi] Show not show Wi-Fi edit UI for never connected open Wi-Fi networks When users click a Wi-Fi network and it's WifiConfiguration.getNetworkSelectionStatus().hasEverConnected() is false, WifiSettings2 will launch the Wi-Fi edit UI for users to edit password again. It's not necessary to show the Wi-Fi edit UI if the Wi-Fi network is a open network. Bug: 154548505 Test: manual Click a never connected secure Wi-Fi and edit UI shows. Click a never connected open Wi-Fi and edit UI does not show. Change-Id: Ie8489aff001942f92fbfaafd772f84b1b4a09cf4 --- src/com/android/settings/wifi/WifiSettings2.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/wifi/WifiSettings2.java b/src/com/android/settings/wifi/WifiSettings2.java index 30d5ad08da4..d26e8c349c0 100644 --- a/src/com/android/settings/wifi/WifiSettings2.java +++ b/src/com/android/settings/wifi/WifiSettings2.java @@ -539,9 +539,11 @@ public class WifiSettings2 extends RestrictedSettingsFragment final WifiEntry selectedEntry = ((LongPressWifiEntryPreference) preference).getWifiEntry(); - if (selectedEntry.getWifiConfiguration() != null) { - if (!selectedEntry.getWifiConfiguration().getNetworkSelectionStatus() - .hasEverConnected()) { + // If the clicked WiFi entry is never connected, launch Wi-Fi edit UI to edit password. + if (selectedEntry.getSecurity() != WifiEntry.SECURITY_NONE + && selectedEntry.getSecurity() != WifiEntry.SECURITY_OWE) { + final WifiConfiguration config = selectedEntry.getWifiConfiguration(); + if (config != null && !config.getNetworkSelectionStatus().hasEverConnected()) { launchConfigNewNetworkFragment(selectedEntry); return true; } From e94de7fbb2272fa1ac744a78ae355578ad6116d9 Mon Sep 17 00:00:00 2001 From: Tim Peng Date: Tue, 21 Apr 2020 17:05:44 +0800 Subject: [PATCH 13/16] The volume slider should not show for the unselected device -Design changes Bug: 154555379 Test: Manual test Change-Id: Icb127867911bc4bba0b77ce374332451b23f1215 --- src/com/android/settings/media/MediaOutputGroupSlice.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/media/MediaOutputGroupSlice.java b/src/com/android/settings/media/MediaOutputGroupSlice.java index 402eb6bb7cf..1a82b6d314e 100644 --- a/src/com/android/settings/media/MediaOutputGroupSlice.java +++ b/src/com/android/settings/media/MediaOutputGroupSlice.java @@ -135,7 +135,7 @@ public class MediaOutputGroupSlice implements CustomSliceable { IconCompat.createWithResource(mContext, R.drawable.ic_check_box_anim), "", selected); - if (maxVolume > 0 && !adjustVolumeUserRestriction) { + if (maxVolume > 0 && selected && !adjustVolumeUserRestriction) { // Add InputRange row final ListBuilder.InputRangeBuilder builder = new ListBuilder.InputRangeBuilder() .setTitleItem(titleIcon, ListBuilder.ICON_IMAGE) From 5308d5f88b18bb8029e9bbf714a4366f5b2e39b1 Mon Sep 17 00:00:00 2001 From: Tim Peng Date: Tue, 21 Apr 2020 17:14:13 +0800 Subject: [PATCH 14/16] Fix Robotest failed Bug: 154578656 Test: make -j50 RunSettingsRoboTests ROBOTEST_FILTER=MediaOutputGroupSliceTest make -j50 RunSettingsRoboTests ROBOTEST_FILTER=MediaOutputSliceTest Change-Id: If675c27ac412c2a49f9ed1c9b71a84c172f54fd6 --- .../android/settings/media/MediaOutputGroupSliceTest.java | 2 ++ .../com/android/settings/media/MediaOutputSliceTest.java | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputGroupSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputGroupSliceTest.java index b4ad48035ba..4fbcb2d4df1 100644 --- a/tests/robotests/src/com/android/settings/media/MediaOutputGroupSliceTest.java +++ b/tests/robotests/src/com/android/settings/media/MediaOutputGroupSliceTest.java @@ -30,6 +30,7 @@ import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_GROUP import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -109,6 +110,7 @@ public class MediaOutputGroupSliceTest { when(sMediaDeviceUpdateWorker.getPackageName()).thenReturn(TEST_PACKAGE_NAME); mDrawable = mContext.getDrawable(R.drawable.ic_check_box_blue_24dp); when(sMediaDeviceUpdateWorker.getSelectableMediaDevice()).thenReturn(mSelectableDevices); + doReturn(false).when(sMediaDeviceUpdateWorker).hasAdjustVolumeUserRestriction(); when(mDevice1.getId()).thenReturn(TEST_DEVICE_1_ID); when(mDevice1.getIcon()).thenReturn(mDrawable); when(mDevice1.getName()).thenReturn(TEST_DEVICE_1_NAME); diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java index d4590b5a455..4e258014a58 100644 --- a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java +++ b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java @@ -25,6 +25,7 @@ import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_SLICE import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -101,10 +102,11 @@ public class MediaOutputSliceTest { mShadowBluetoothAdapter.setEnabled(true); mMediaOutputSlice = new MediaOutputSlice(mContext); - mMediaDeviceUpdateWorker = new MediaDeviceUpdateWorker(mContext, - MEDIA_OUTPUT_SLICE_URI); + mMediaDeviceUpdateWorker = spy(new MediaDeviceUpdateWorker(mContext, + MEDIA_OUTPUT_SLICE_URI)); mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices); mMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager; + doReturn(false).when(mMediaDeviceUpdateWorker).hasAdjustVolumeUserRestriction(); mMediaOutputSlice.init(mMediaDeviceUpdateWorker); } From d796da16f0e60eac981522a7fe7b21ba91db5cdd Mon Sep 17 00:00:00 2001 From: Beverly Date: Tue, 21 Apr 2020 09:31:16 -0400 Subject: [PATCH 15/16] Update ZenModeSettingsTest String was updated Test: make ROBOTEST_FILTER=ZenModeSettingsTest RunSettingsRoboTests Fixes: 154568594 Change-Id: Ia67f7ff2e3692cc4f40b87e94e3d3952002a9e87 --- .../android/settings/notification/zen/ZenModeSettingsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeSettingsTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeSettingsTest.java index ea750560572..f8cbf2ecadb 100644 --- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeSettingsTest.java +++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeSettingsTest.java @@ -72,7 +72,7 @@ public class ZenModeSettingsTest { @Test public void testGetCallsSettingSummary_none() { Policy policy = new Policy(0, 0, 0, 0); - assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Don\u2019t allow any calls"); + assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("None"); } @Test From 4922aa006aeee92f90b836dea5421a5d1e3e45be Mon Sep 17 00:00:00 2001 From: Beverly Date: Tue, 21 Apr 2020 14:49:33 -0400 Subject: [PATCH 16/16] Notification history a11y fixes - When clicking the expand/collapse button to see the posted notifications from an app in the last 24 hours, refocus accessibility on the button so the entire button (contentDescription + clickability) are announced. Previously only the contentDescription update was being announced. - Fix local context menu of NotificationHistory elements by calling the super method in performAccessibilityAction Test: manual Fixes: 153396313 Fixes: 153518629 Change-Id: I3d847ec1f2b72dcf411c6c7c7fe2dc061ccfde26 --- .../history/NotificationHistoryActivity.java | 22 ++++++++++--------- .../history/NotificationHistoryAdapter.java | 3 ++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java index 144d102e651..acfc269354f 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java +++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java @@ -18,6 +18,8 @@ package com.android.settings.notification.history; import static android.provider.Settings.Secure.NOTIFICATION_HISTORY_ENABLED; +import static androidx.core.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED; + import android.app.Activity; import android.app.ActivityManager; import android.app.INotificationManager; @@ -88,15 +90,15 @@ public class NotificationHistoryActivity extends Activity { ? getString(R.string.condition_expand_hide) : getString(R.string.condition_expand_show)); expand.setOnClickListener(v -> { - container.setVisibility(container.getVisibility() == View.VISIBLE - ? View.GONE : View.VISIBLE); - expand.setImageResource(container.getVisibility() == View.VISIBLE - ? R.drawable.ic_expand_less - : com.android.internal.R.drawable.ic_expand_more); - expand.setContentDescription(container.getVisibility() == View.VISIBLE - ? getString(R.string.condition_expand_hide) - : getString(R.string.condition_expand_show)); - expand.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE); + container.setVisibility(container.getVisibility() == View.VISIBLE + ? View.GONE : View.VISIBLE); + expand.setImageResource(container.getVisibility() == View.VISIBLE + ? R.drawable.ic_expand_less + : com.android.internal.R.drawable.ic_expand_more); + expand.setContentDescription(container.getVisibility() == View.VISIBLE + ? getString(R.string.condition_expand_hide) + : getString(R.string.condition_expand_show)); + expand.sendAccessibilityEvent(TYPE_VIEW_ACCESSIBILITY_FOCUSED); }); TextView label = viewForPackage.findViewById(R.id.label); @@ -108,7 +110,7 @@ public class NotificationHistoryActivity extends Activity { count.setText(getResources().getQuantityString(R.plurals.notification_history_count, nhp.notifications.size(), nhp.notifications.size())); - NotificationHistoryRecyclerView rv = + final NotificationHistoryRecyclerView rv = viewForPackage.findViewById(R.id.notification_list); rv.setAdapter(new NotificationHistoryAdapter(mNm, rv)); ((NotificationHistoryAdapter) rv.getAdapter()).onRebuildComplete( diff --git a/src/com/android/settings/notification/history/NotificationHistoryAdapter.java b/src/com/android/settings/notification/history/NotificationHistoryAdapter.java index 9d652d97f2c..afe36ef0589 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryAdapter.java +++ b/src/com/android/settings/notification/history/NotificationHistoryAdapter.java @@ -91,11 +91,12 @@ public class NotificationHistoryAdapter extends new AccessibilityNodeInfo.AccessibilityAction( AccessibilityNodeInfo.ACTION_CLICK, description); info.addAction(customClick); - //info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS); + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS); } @Override public boolean performAccessibilityAction(View host, int action, Bundle args) { + super.performAccessibilityAction(host, action, args); if (action == AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS.getId()) { onItemSwipeDeleted(position); return true;