From 212b5676d058e7c99831a6537f97d0d04a11bc8a Mon Sep 17 00:00:00 2001 From: Antony Sargent Date: Tue, 5 Jun 2018 14:31:32 -0700 Subject: [PATCH 1/8] Remove references to SettingsBase styles We've moved the values for several preference-related styles used in Settings from SettingsLib into the support library. This CL removes the references to the SettingsLib versions from Settings so they can be removed from SettingsLib. Also delete an unused layout file that was moved to SettingsLib a long time ago (preference_dropdown_material_settings.xml). Bug: 64689839 Test: visual (styles for things like icon spacing, dividers, etc. should be the same) Change-Id: Ib7a745218086269c2e861b18df68bd835929da19 --- .../preference_dropdown_material_settings.xml | 35 ------------------- res/values/styles_preference.xml | 12 +++---- 2 files changed, 6 insertions(+), 41 deletions(-) delete mode 100644 res/layout/preference_dropdown_material_settings.xml diff --git a/res/layout/preference_dropdown_material_settings.xml b/res/layout/preference_dropdown_material_settings.xml deleted file mode 100644 index a3f5ab903fc..00000000000 --- a/res/layout/preference_dropdown_material_settings.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml index 6b632ca7b1d..a55f5caae12 100644 --- a/res/values/styles_preference.xml +++ b/res/values/styles_preference.xml @@ -20,27 +20,27 @@ - - - - - - From 756e3b6caf566143a136baa37929544e7a0386ce Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 7 Jun 2018 10:43:47 -0400 Subject: [PATCH 2/8] Add summary to PreventRingingParent Parent preference previously didn't have a summary Moved summary test to PreventRingingParentPreferenceControllerTest Test: PreventRingingParentPreferenceControllerTest.java Change-Id: I2891e1ccffc4ea8007c8bd25689f242ee34c652c --- ...ventRingingParentPreferenceController.java | 27 ++++++++++++- .../PreventRingingPreferenceController.java | 20 ---------- ...RingingParentPreferenceControllerTest.java | 38 +++++++++++++++++-- ...reventRingingPreferenceControllerTest.java | 23 ----------- 4 files changed, 61 insertions(+), 47 deletions(-) diff --git a/src/com/android/settings/gestures/PreventRingingParentPreferenceController.java b/src/com/android/settings/gestures/PreventRingingParentPreferenceController.java index 88147657b27..afb34315260 100644 --- a/src/com/android/settings/gestures/PreventRingingParentPreferenceController.java +++ b/src/com/android/settings/gestures/PreventRingingParentPreferenceController.java @@ -16,12 +16,20 @@ package com.android.settings.gestures; -import android.content.Context; +import static android.provider.Settings.Secure.VOLUME_HUSH_GESTURE; +import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE; +import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE; +import android.content.Context; +import android.provider.Settings; + +import com.android.settings.R; import com.android.settings.core.BasePreferenceController; public class PreventRingingParentPreferenceController extends BasePreferenceController { + final String SECURE_KEY = VOLUME_HUSH_GESTURE; + public PreventRingingParentPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); } @@ -33,4 +41,21 @@ public class PreventRingingParentPreferenceController extends BasePreferenceCont ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE; } + @Override + public CharSequence getSummary() { + int value = Settings.Secure.getInt( + mContext.getContentResolver(), SECURE_KEY, VOLUME_HUSH_VIBRATE); + int summary; + switch (value) { + case VOLUME_HUSH_VIBRATE: + summary = R.string.prevent_ringing_option_vibrate_summary; + break; + case VOLUME_HUSH_MUTE: + summary = R.string.prevent_ringing_option_mute_summary; + break; + default: + summary = R.string.prevent_ringing_option_none_summary; + } + return mContext.getText(summary); + } } diff --git a/src/com/android/settings/gestures/PreventRingingPreferenceController.java b/src/com/android/settings/gestures/PreventRingingPreferenceController.java index be55151f91e..7f685e59b56 100644 --- a/src/com/android/settings/gestures/PreventRingingPreferenceController.java +++ b/src/com/android/settings/gestures/PreventRingingPreferenceController.java @@ -50,8 +50,6 @@ public class PreventRingingPreferenceController extends PreventRingingParentPref @VisibleForTesting boolean mVideoPaused; - private final String SECURE_KEY = VOLUME_HUSH_GESTURE; - public PreventRingingPreferenceController(Context context, String key) { super(context, key); } @@ -95,24 +93,6 @@ public class PreventRingingPreferenceController extends PreventRingingParentPref } } - @Override - public CharSequence getSummary() { - int value = Settings.Secure.getInt( - mContext.getContentResolver(), SECURE_KEY, VOLUME_HUSH_VIBRATE); - int summary; - switch (value) { - case VOLUME_HUSH_VIBRATE: - summary = R.string.prevent_ringing_option_vibrate_summary; - break; - case VOLUME_HUSH_MUTE: - summary = R.string.prevent_ringing_option_mute_summary; - break; - default: - summary = R.string.prevent_ringing_option_none_summary; - } - return mContext.getString(summary); - } - @Override public void onCreate(Bundle savedInstanceState) { if (savedInstanceState != null) { diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingParentPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingParentPreferenceControllerTest.java index 33a00fac303..bffc847a3b7 100644 --- a/tests/robotests/src/com/android/settings/gestures/PreventRingingParentPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingParentPreferenceControllerTest.java @@ -16,14 +16,25 @@ package com.android.settings.gestures; +import static android.provider.Settings.Secure.VOLUME_HUSH_GESTURE; +import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE; +import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; +import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE; + import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; + 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; import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; +import android.provider.Settings; +import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; @@ -41,18 +52,20 @@ public class PreventRingingParentPreferenceControllerTest { private Context mContext; private PreventRingingParentPreferenceController mController; + private final String VIBRATE_SUMMARY = "On (vibrate)"; + private final String MUTE_SUMMARY = "On (mute)"; + private final String NONE_SUMMARY = "Off"; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - when(mContext.getResources()).thenReturn(mResources); - + mContext = spy(RuntimeEnvironment.application.getApplicationContext()); mController = new PreventRingingParentPreferenceController(mContext, "test_key"); } @Test public void testIsAvailable_configIsTrue_shouldAvailableUnSearchable() { + when(mContext.getResources()).thenReturn(mResources); when(mResources.getBoolean( com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(true); @@ -61,9 +74,28 @@ public class PreventRingingParentPreferenceControllerTest { @Test public void testIsAvailable_configIsFalse_shouldReturnFalse() { + when(mContext.getResources()).thenReturn(mResources); when(mResources.getBoolean( com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(false); assertThat(mController.isAvailable()).isFalse(); } + + @Test + public void updateState_summaryUpdated() { + Settings.Secure.putInt(mContext.getContentResolver(), VOLUME_HUSH_GESTURE, + VOLUME_HUSH_MUTE); + assertThat(mController.getSummary()).isEqualTo(mContext.getResources().getText( + R.string.prevent_ringing_option_mute_summary)); + + Settings.Secure.putInt(mContext.getContentResolver(), VOLUME_HUSH_GESTURE, + VOLUME_HUSH_VIBRATE); + assertThat(mController.getSummary()).isEqualTo(mContext.getResources().getText( + R.string.prevent_ringing_option_vibrate_summary)); + + Settings.Secure.putInt(mContext.getContentResolver(), VOLUME_HUSH_GESTURE, + VOLUME_HUSH_OFF); + assertThat(mController.getSummary()).isEqualTo(mContext.getResources().getText( + R.string.prevent_ringing_option_none_summary)); + } } diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java index 833a09d59b0..514bb58dc4d 100644 --- a/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java @@ -87,29 +87,6 @@ public class PreventRingingPreferenceControllerTest { assertThat(mController.isAvailable()).isFalse(); } - @Test - public void testGetSummary_mute() { - Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, - Settings.Secure.VOLUME_HUSH_MUTE); - assertEquals(mContext.getString(R.string.prevent_ringing_option_mute_summary), - mController.getSummary()); - } - - @Test - public void testGetSummary_vibrate() { - Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, - Settings.Secure.VOLUME_HUSH_VIBRATE); - assertEquals(mContext.getString(R.string.prevent_ringing_option_vibrate_summary), - mController.getSummary()); - } - @Test - public void testGetSummary_other() { - Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, - 7); - assertEquals(mContext.getString(R.string.prevent_ringing_option_none_summary), - mController.getSummary()); - } - @Test public void testUpdateState_mute() { ListPreference pref = mock(ListPreference.class); From 9ecf3e0c1110e6900f63a600e483f8925e366b4c Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Wed, 30 May 2018 09:50:52 -0700 Subject: [PATCH 3/8] Skip device index job if caller is not Settings app. Change-Id: I96184f111e83477b46ddf321ec74917bab330048 Fixes: 80437512 Fixes: 109713077 Test: robotests (cherry picked from commit 74ba1a51d74a4fb7fc2ccd62fd38087974c20020) --- .../search/DeviceIndexFeatureProvider.java | 30 +++++++++-- .../DeviceIndexFeatureProviderTest.java | 50 +++++++++++++------ 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/com/android/settings/search/DeviceIndexFeatureProvider.java b/src/com/android/settings/search/DeviceIndexFeatureProvider.java index c4d3abfcaa8..e6b3e937b85 100644 --- a/src/com/android/settings/search/DeviceIndexFeatureProvider.java +++ b/src/com/android/settings/search/DeviceIndexFeatureProvider.java @@ -21,7 +21,10 @@ import android.app.job.JobInfo; import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; import android.net.Uri; +import android.os.Binder; import android.os.Build; import android.provider.Settings; import android.text.TextUtils; @@ -36,7 +39,6 @@ import java.util.Locale; public interface DeviceIndexFeatureProvider { - String TAG = "DeviceIndex"; String INDEX_VERSION = "settings:index_version"; @@ -57,7 +59,7 @@ public interface DeviceIndexFeatureProvider { default void updateIndex(Context context, boolean force) { if (!isIndexingEnabled()) { - Log.w(TAG, "Skipping: device index is not enabled"); + Log.i(TAG, "Skipping: device index is not enabled"); return; } @@ -66,7 +68,29 @@ public interface DeviceIndexFeatureProvider { return; } + final ComponentName jobComponent = new ComponentName(context.getPackageName(), + DeviceIndexUpdateJobService.class.getName()); + + try { + final int callerUid = Binder.getCallingUid(); + final ServiceInfo si = context.getPackageManager().getServiceInfo(jobComponent, + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); + if (si == null) { + Log.w(TAG, "Skipping: No such service " + jobComponent); + return; + } + if (si.applicationInfo.uid != callerUid) { + Log.w(TAG, "Skipping: Uid cannot schedule DeviceIndexUpdate: " + callerUid); + return; + } + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Skipping: error finding DeviceIndexUpdateJobService from packageManager"); + return; + } + if (!force && skipIndex(context)) { + Log.i(TAG, "Skipping: already indexed."); // No need to update. return; } @@ -74,8 +98,6 @@ public interface DeviceIndexFeatureProvider { // Prevent scheduling multiple jobs setIndexState(context); - final ComponentName jobComponent = new ComponentName(context.getPackageName(), - DeviceIndexUpdateJobService.class.getName()); final int jobId = context.getResources().getInteger(R.integer.device_index_update); // Schedule a job so that we know it'll be able to complete, but try to run as // soon as possible. diff --git a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java index ebba3f310ce..b49ef1d0683 100644 --- a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java +++ b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java @@ -15,7 +15,6 @@ package com.android.settings.search; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -23,27 +22,42 @@ import static org.mockito.Mockito.when; import android.app.Activity; import android.app.job.JobScheduler; +import android.os.Binder; import android.provider.Settings; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; +import org.robolectric.shadows.ShadowBinder; @RunWith(SettingsRobolectricTestRunner.class) public class DeviceIndexFeatureProviderTest { + @Mock + private JobScheduler mJobScheduler; private DeviceIndexFeatureProvider mProvider; private Activity mActivity; @Before public void setUp() { + MockitoAnnotations.initMocks(this); + ShadowBinder.reset(); FakeFeatureFactory.setupForTest(); mActivity = spy(Robolectric.buildActivity(Activity.class).create().visible().get()); mProvider = spy(new DeviceIndexFeatureProviderImpl()); + when(mActivity.getSystemService(JobScheduler.class)).thenReturn(mJobScheduler); + } + + @After + public void tearDown() { + ShadowBinder.reset(); } @Test @@ -51,7 +65,7 @@ public class DeviceIndexFeatureProviderTest { when(mProvider.isIndexingEnabled()).thenReturn(false); mProvider.updateIndex(mActivity, false); - verify(mProvider, never()).index(any(), any(), any(), any(), any()); + verify(mJobScheduler, never()).schedule(any()); } @Test @@ -62,19 +76,17 @@ public class DeviceIndexFeatureProviderTest { mProvider.updateIndex(mActivity, false); - verify(mProvider, never()).index(any(), any(), any(), any(), any()); + verify(mJobScheduler, never()).schedule(any()); } @Test public void updateIndex_enabled_provisioned_shouldIndex() { Settings.Global.putInt(mActivity.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1); - JobScheduler jobScheduler = mock(JobScheduler.class); when(mProvider.isIndexingEnabled()).thenReturn(true); - when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler); mProvider.updateIndex(mActivity, false); - verify(jobScheduler).schedule(any()); + verify(mJobScheduler).schedule(any()); } @Test @@ -87,12 +99,22 @@ public class DeviceIndexFeatureProviderTest { Settings.Global.putString(mActivity.getContentResolver(), DeviceIndexFeatureProvider.LANGUAGE.toString(), DeviceIndexFeatureProvider.INDEX_LANGUAGE); - JobScheduler jobScheduler = mock(JobScheduler.class); when(mProvider.isIndexingEnabled()).thenReturn(true); - when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler); mProvider.updateIndex(mActivity, false); - verify(jobScheduler).schedule(any()); + verify(mJobScheduler).schedule(any()); + } + + @Test + public void updateIndex_enabled_provisioned_differentUid_shouldNotIndex() { + Settings.Global.putInt(mActivity.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 1); + when(mProvider.isIndexingEnabled()).thenReturn(true); + + ShadowBinder.setCallingUid(Binder.getCallingUid() + 2000); + + mProvider.updateIndex(mActivity, false); + verify(mJobScheduler, never()).schedule(any()); } @Test @@ -102,12 +124,11 @@ public class DeviceIndexFeatureProviderTest { DeviceIndexFeatureProvider.setIndexState(mActivity); Settings.Global.putString(mActivity.getContentResolver(), DeviceIndexFeatureProvider.INDEX_LANGUAGE, "new language"); - JobScheduler jobScheduler = mock(JobScheduler.class); + when(mProvider.isIndexingEnabled()).thenReturn(true); - when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler); mProvider.updateIndex(mActivity, false); - verify(jobScheduler).schedule(any()); + verify(mJobScheduler).schedule(any()); } @Test @@ -120,11 +141,8 @@ public class DeviceIndexFeatureProviderTest { // Same build and same language DeviceIndexFeatureProvider.setIndexState(mActivity); - final JobScheduler jobScheduler = mock(JobScheduler.class); - when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler); - mProvider.updateIndex(mActivity, false); - verify(jobScheduler, never()).schedule(any()); + verify(mJobScheduler, never()).schedule(any()); } } From cd21cb8def0d91b8dd068332e283782da71a8af0 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 11 Jun 2018 09:28:02 -0700 Subject: [PATCH 4/8] Remove DataSummaryUsageLegacy. Change-Id: I8da039530cafe547008b434b6016add5f9383e94 Fixes: 109943959 Test: robotest/atest --- AndroidManifest.xml | 25 +- res/menu/data_usage.xml | 21 - res/values/strings.xml | 8 - res/xml/data_usage_legacy.xml | 43 --- src/com/android/settings/Settings.java | 1 - .../android/settings/SettingsActivity.java | 10 +- .../android/settings/core/FeatureFlags.java | 1 - .../core/gateway/SettingsGateway.java | 2 - .../conditional/BackgroundDataCondition.java | 9 +- .../datausage/BillingCyclePreference.java | 18 +- .../datausage/BillingCycleSettings.java | 33 +- .../settings/datausage/DataUsageBase.java | 38 +- .../datausage/DataUsageBaseFragment.java | 41 +- .../datausage/DataUsagePreference.java | 34 +- .../settings/datausage/DataUsageSummary.java | 24 +- .../datausage/DataUsageSummaryLegacy.java | 359 ------------------ ...randfather_not_implementing_index_provider | 1 - .../BackgroundDataConditionTest.java | 21 +- .../datausage/BillingCycleSettingsTest.java | 13 +- .../datausage/DataUsageSummaryLegacyTest.java | 69 ---- .../inputmethods/DataSaverSummaryUITest.java | 2 +- 21 files changed, 44 insertions(+), 729 deletions(-) delete mode 100644 res/menu/data_usage.xml delete mode 100644 res/xml/data_usage_legacy.xml delete mode 100644 src/com/android/settings/datausage/DataUsageSummaryLegacy.java delete mode 100644 tests/robotests/src/com/android/settings/datausage/DataUsageSummaryLegacyTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 78f4e22d19a..4fa39649718 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2365,26 +2365,6 @@ android:enabled="false" android:taskAffinity="com.android.settings" android:parentActivityName="Settings"> - - - - - - - - - - - - - @@ -2398,11 +2378,10 @@ + android:value="com.android.settings.category.ia.wireless" /> + android:value="com.android.settings.datausage.DataUsageSummary" /> - - - - - - diff --git a/res/values/strings.xml b/res/values/strings.xml index eba90fd5383..51ec5901793 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6015,8 +6015,6 @@ Auto-sync data SIM cards - - Mobile networks Paused at limit @@ -9169,12 +9167,6 @@ ^1 ethernet data - - %1$s Data warning - - - %1$s Data warning / %2$s Data limit - Data warning & limit diff --git a/res/xml/data_usage_legacy.xml b/res/xml/data_usage_legacy.xml deleted file mode 100644 index bbe908a9a91..00000000000 --- a/res/xml/data_usage_legacy.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 651c3a7a790..0d8506275d0 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -76,7 +76,6 @@ public class Settings extends SettingsActivity { public static class CryptKeeperSettingsActivity extends SettingsActivity { /* empty */ } public static class DeviceAdminSettingsActivity extends SettingsActivity { /* empty */ } public static class DataUsageSummaryActivity extends SettingsActivity { /* empty */ } - public static class DataUsageSummaryLegacyActivity extends SettingsActivity { /* empty */ } public static class MobileDataUsageListActivity extends SettingsActivity { /* empty */ } public static class ConfigureWifiSettingsActivity extends SettingsActivity { /* empty */ } public static class SavedAccessPointsSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 5d6ea4dd6ee..8b9b912e88d 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -664,17 +664,9 @@ public class SettingsActivity extends SettingsDrawerActivity Settings.PowerUsageSummaryActivity.class.getName()), mBatteryPresent, isAdmin) || somethingChanged; - final boolean isDataUsageSettingsV2Enabled = - FeatureFlagUtils.isEnabled(this, FeatureFlags.DATA_USAGE_SETTINGS_V2); - // Enable new data usage page if v2 enabled somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, Settings.DataUsageSummaryActivity.class.getName()), - Utils.isBandwidthControlEnabled() && isDataUsageSettingsV2Enabled, isAdmin) - || somethingChanged; - // Enable legacy data usage page if v2 disabled - somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, - Settings.DataUsageSummaryLegacyActivity.class.getName()), - Utils.isBandwidthControlEnabled() && !isDataUsageSettingsV2Enabled, isAdmin) + Utils.isBandwidthControlEnabled(), isAdmin) || somethingChanged; somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java index a1bce23e4c0..47da6cfb2f0 100644 --- a/src/com/android/settings/core/FeatureFlags.java +++ b/src/com/android/settings/core/FeatureFlags.java @@ -23,6 +23,5 @@ public class FeatureFlags { public static final String BATTERY_DISPLAY_APP_LIST = "settings_battery_display_app_list"; public static final String ZONE_PICKER_V2 = "settings_zone_picker_v2"; public static final String BLUETOOTH_WHILE_DRIVING = "settings_bluetooth_while_driving"; - public static final String DATA_USAGE_SETTINGS_V2 = "settings_data_usage_v2"; public static final String AUDIO_SWITCHER_SETTINGS = "settings_audio_switcher"; } diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 6cf29597894..a050628d31e 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -59,7 +59,6 @@ import com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFr import com.android.settings.connecteddevice.usb.UsbDetailsFragment; import com.android.settings.datausage.DataUsageList; import com.android.settings.datausage.DataUsageSummary; -import com.android.settings.datausage.DataUsageSummaryLegacy; import com.android.settings.deletionhelper.AutomaticStorageManagerSettings; import com.android.settings.development.DevelopmentSettingsDashboardFragment; import com.android.settings.deviceinfo.PrivateVolumeForget; @@ -192,7 +191,6 @@ public class SettingsGateway { SwipeUpGestureSettings.class.getName(), CryptKeeperSettings.class.getName(), DataUsageSummary.class.getName(), - DataUsageSummaryLegacy.class.getName(), DreamSettings.class.getName(), UserSettings.class.getName(), NotificationAccessSettings.class.getName(), diff --git a/src/com/android/settings/dashboard/conditional/BackgroundDataCondition.java b/src/com/android/settings/dashboard/conditional/BackgroundDataCondition.java index a7e160fc68d..d5372a24c05 100644 --- a/src/com/android/settings/dashboard/conditional/BackgroundDataCondition.java +++ b/src/com/android/settings/dashboard/conditional/BackgroundDataCondition.java @@ -18,12 +18,10 @@ package com.android.settings.dashboard.conditional; import android.content.Intent; import android.graphics.drawable.Drawable; import android.net.NetworkPolicyManager; -import android.util.FeatureFlagUtils; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.Settings; -import com.android.settings.core.FeatureFlags; public class BackgroundDataCondition extends Condition { @@ -58,11 +56,8 @@ public class BackgroundDataCondition extends Condition { @Override public void onPrimaryClick() { - final Class activityClass = FeatureFlagUtils.isEnabled(mManager.getContext(), - FeatureFlags.DATA_USAGE_SETTINGS_V2) - ? Settings.DataUsageSummaryActivity.class - : Settings.DataUsageSummaryLegacyActivity.class; - mManager.getContext().startActivity(new Intent(mManager.getContext(), activityClass) + mManager.getContext().startActivity(new Intent(mManager.getContext(), + Settings.DataUsageSummaryActivity.class) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java index 7d454a1f8a0..70a123f9aa6 100644 --- a/src/com/android/settings/datausage/BillingCyclePreference.java +++ b/src/com/android/settings/datausage/BillingCyclePreference.java @@ -14,24 +14,20 @@ package com.android.settings.datausage; -import static android.net.NetworkPolicy.CYCLE_NONE; - import android.content.Context; import android.content.Intent; import android.net.NetworkTemplate; import android.os.Bundle; import android.os.RemoteException; -import androidx.preference.Preference; import android.util.AttributeSet; -import android.util.FeatureFlagUtils; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; - -import com.android.settings.core.FeatureFlags; import com.android.settings.core.SubSettingLauncher; import com.android.settings.datausage.CellDataPreference.DataStateListener; +import androidx.preference.Preference; + public class BillingCyclePreference extends Preference implements TemplatePreference { private NetworkTemplate mTemplate; @@ -60,14 +56,8 @@ public class BillingCyclePreference extends Preference implements TemplatePrefer mTemplate = template; mSubId = subId; mServices = services; - final int cycleDay = services.mPolicyEditor.getPolicyCycleDay(mTemplate); - if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.DATA_USAGE_SETTINGS_V2)) { - setSummary(null); - } else if (cycleDay != CYCLE_NONE) { - setSummary(getContext().getString(R.string.billing_cycle_fragment_summary, cycleDay)); - } else { - setSummary(null); - } + setSummary(null); + setIntent(getIntent()); } diff --git a/src/com/android/settings/datausage/BillingCycleSettings.java b/src/com/android/settings/datausage/BillingCycleSettings.java index 5cdf22a8970..8360df88a01 100644 --- a/src/com/android/settings/datausage/BillingCycleSettings.java +++ b/src/com/android/settings/datausage/BillingCycleSettings.java @@ -14,7 +14,6 @@ package com.android.settings.datausage; -import static android.net.NetworkPolicy.CYCLE_NONE; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED; @@ -27,10 +26,7 @@ import android.content.res.Resources; import android.net.NetworkPolicy; import android.net.NetworkTemplate; import android.os.Bundle; -import androidx.preference.SwitchPreference; -import androidx.preference.Preference; import android.text.format.Time; -import android.util.FeatureFlagUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -41,11 +37,13 @@ import android.widget.Spinner; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; -import com.android.settings.core.FeatureFlags; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.NetworkPolicyEditor; import com.android.settingslib.net.DataUsageController; +import androidx.preference.Preference; +import androidx.preference.SwitchPreference; + public class BillingCycleSettings extends DataUsageBase implements Preference.OnPreferenceChangeListener, DataUsageEditController { @@ -63,7 +61,8 @@ public class BillingCycleSettings extends DataUsageBase implements private static final String KEY_BILLING_CYCLE = "billing_cycle"; private static final String KEY_SET_DATA_WARNING = "set_data_warning"; private static final String KEY_DATA_WARNING = "data_warning"; - @VisibleForTesting static final String KEY_SET_DATA_LIMIT = "set_data_limit"; + @VisibleForTesting + static final String KEY_SET_DATA_LIMIT = "set_data_limit"; private static final String KEY_DATA_LIMIT = "data_limit"; private NetworkTemplate mNetworkTemplate; @@ -76,11 +75,11 @@ public class BillingCycleSettings extends DataUsageBase implements @VisibleForTesting void setUpForTest(NetworkPolicyEditor policyEditor, - Preference billingCycle, - Preference dataLimit, - Preference dataWarning, - SwitchPreference enableLimit, - SwitchPreference enableWarning) { + Preference billingCycle, + Preference dataLimit, + Preference dataWarning, + SwitchPreference enableLimit, + SwitchPreference enableWarning) { services.mPolicyEditor = policyEditor; mBillingCycle = billingCycle; mDataLimit = dataLimit; @@ -118,14 +117,7 @@ public class BillingCycleSettings extends DataUsageBase implements @VisibleForTesting void updatePrefs() { - final int cycleDay = services.mPolicyEditor.getPolicyCycleDay(mNetworkTemplate); - if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.DATA_USAGE_SETTINGS_V2)) { - mBillingCycle.setSummary(null); - } else if (cycleDay != CYCLE_NONE) { - mBillingCycle.setSummary(getString(R.string.billing_cycle_fragment_summary, cycleDay)); - } else { - mBillingCycle.setSummary(null); - } + mBillingCycle.setSummary(null); final long warningBytes = services.mPolicyEditor.getPolicyWarningBytes(mNetworkTemplate); if (warningBytes != WARNING_DISABLED) { mDataWarning.setSummary(DataUsageUtils.formatDataUsage(getContext(), warningBytes)); @@ -402,7 +394,8 @@ public class BillingCycleSettings extends DataUsageBase implements */ public static class ConfirmLimitFragment extends InstrumentedDialogFragment implements DialogInterface.OnClickListener { - @VisibleForTesting static final String EXTRA_LIMIT_BYTES = "limitBytes"; + @VisibleForTesting + static final String EXTRA_LIMIT_BYTES = "limitBytes"; public static final float FLOAT = 1.2f; public static void show(BillingCycleSettings parent) { diff --git a/src/com/android/settings/datausage/DataUsageBase.java b/src/com/android/settings/datausage/DataUsageBase.java index b889a2f5812..c5df0bb0795 100644 --- a/src/com/android/settings/datausage/DataUsageBase.java +++ b/src/com/android/settings/datausage/DataUsageBase.java @@ -14,25 +14,19 @@ package com.android.settings.datausage; -import static android.net.ConnectivityManager.TYPE_ETHERNET; - import android.content.Context; -import android.net.ConnectivityManager; import android.net.INetworkStatsService; -import android.net.INetworkStatsSession; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; -import android.net.NetworkTemplate; -import android.net.TrafficStats; import android.os.Bundle; import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemProperties; import android.os.UserManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; + import com.android.settings.SettingsPreferenceFragment; import com.android.settingslib.NetworkPolicyEditor; @@ -99,34 +93,4 @@ public abstract class DataUsageBase extends SettingsPreferenceFragment { return false; } } - - /** - * Test if device has an ethernet network connection. - */ - public boolean hasEthernet(Context context) { - if (DataUsageUtils.TEST_RADIOS) { - return SystemProperties.get(DataUsageUtils.TEST_RADIOS_PROP).contains(ETHERNET); - } - - final ConnectivityManager conn = ConnectivityManager.from(context); - final boolean hasEthernet = conn.isNetworkSupported(TYPE_ETHERNET); - - final long ethernetBytes; - try { - INetworkStatsSession statsSession = services.mStatsService.openSession(); - if (statsSession != null) { - ethernetBytes = statsSession.getSummaryForNetwork( - NetworkTemplate.buildTemplateEthernet(), Long.MIN_VALUE, Long.MAX_VALUE) - .getTotalBytes(); - TrafficStats.closeQuietly(statsSession); - } else { - ethernetBytes = 0; - } - } catch (RemoteException e) { - throw new RuntimeException(e); - } - - // only show ethernet when both hardware present and traffic has occurred - return hasEthernet && ethernetBytes > 0; - } } diff --git a/src/com/android/settings/datausage/DataUsageBaseFragment.java b/src/com/android/settings/datausage/DataUsageBaseFragment.java index e9c73ff8cc3..f6e88cc1024 100644 --- a/src/com/android/settings/datausage/DataUsageBaseFragment.java +++ b/src/com/android/settings/datausage/DataUsageBaseFragment.java @@ -14,27 +14,19 @@ package com.android.settings.datausage; -import static android.net.ConnectivityManager.TYPE_ETHERNET; - import android.content.Context; -import android.net.ConnectivityManager; import android.net.INetworkStatsService; -import android.net.INetworkStatsSession; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; -import android.net.NetworkTemplate; -import android.net.TrafficStats; import android.os.Bundle; import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemProperties; import android.os.UserManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; -import com.android.settings.SettingsPreferenceFragment; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.NetworkPolicyEditor; @@ -54,7 +46,7 @@ public abstract class DataUsageBaseFragment extends DashboardFragment { ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); services.mStatsService = INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); - services.mPolicyManager = (NetworkPolicyManager)context + services.mPolicyManager = (NetworkPolicyManager) context .getSystemService(Context.NETWORK_POLICY_SERVICE); services.mPolicyEditor = new NetworkPolicyEditor(services.mPolicyManager); @@ -98,35 +90,4 @@ public abstract class DataUsageBaseFragment extends DashboardFragment { return false; } } - - /** - * Test if device has an ethernet network connection. - * TODO(b/77590489): Remove this method when DataUsageSummaryLegacy is deprecated. - */ - public boolean hasEthernet(Context context) { - if (DataUsageUtils.TEST_RADIOS) { - return SystemProperties.get(DataUsageUtils.TEST_RADIOS_PROP).contains(ETHERNET); - } - - final ConnectivityManager conn = ConnectivityManager.from(context); - final boolean hasEthernet = conn.isNetworkSupported(TYPE_ETHERNET); - - final long ethernetBytes; - try { - INetworkStatsSession statsSession = services.mStatsService.openSession(); - if (statsSession != null) { - ethernetBytes = statsSession.getSummaryForNetwork( - NetworkTemplate.buildTemplateEthernet(), Long.MIN_VALUE, Long.MAX_VALUE) - .getTotalBytes(); - TrafficStats.closeQuietly(statsSession); - } else { - ethernetBytes = 0; - } - } catch (RemoteException e) { - throw new RuntimeException(e); - } - - // only show ethernet when both hardware present and traffic has occurred - return hasEthernet && ethernetBytes > 0; - } } diff --git a/src/com/android/settings/datausage/DataUsagePreference.java b/src/com/android/settings/datausage/DataUsagePreference.java index bb3902c851b..af8d6d46e73 100644 --- a/src/com/android/settings/datausage/DataUsagePreference.java +++ b/src/com/android/settings/datausage/DataUsagePreference.java @@ -19,17 +19,16 @@ import android.content.Intent; import android.content.res.TypedArray; import android.net.NetworkTemplate; import android.os.Bundle; -import androidx.core.content.res.TypedArrayUtils; -import androidx.preference.Preference; import android.util.AttributeSet; -import android.util.FeatureFlagUtils; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; -import com.android.settings.core.FeatureFlags; import com.android.settings.core.SubSettingLauncher; import com.android.settingslib.net.DataUsageController; +import androidx.core.content.res.TypedArrayUtils; +import androidx.preference.Preference; + public class DataUsagePreference extends Preference implements TemplatePreference { private NetworkTemplate mTemplate; @@ -54,20 +53,13 @@ public class DataUsagePreference extends Preference implements TemplatePreferenc mSubId = subId; DataUsageController controller = new DataUsageController(getContext()); DataUsageController.DataUsageInfo usageInfo = controller.getDataUsageInfo(mTemplate); - if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.DATA_USAGE_SETTINGS_V2)) { - if (mTemplate.isMatchRuleMobile()) { - setTitle(R.string.app_cellular_data_usage); - } else { - setTitle(mTitleRes); - setSummary(getContext().getString(R.string.data_usage_template, - DataUsageUtils.formatDataUsage(getContext(), usageInfo.usageLevel), - usageInfo.period)); - } + if (mTemplate.isMatchRuleMobile()) { + setTitle(R.string.app_cellular_data_usage); } else { setTitle(mTitleRes); setSummary(getContext().getString(R.string.data_usage_template, DataUsageUtils.formatDataUsage(getContext(), usageInfo.usageLevel), - usageInfo.period)); + usageInfo.period)); } setIntent(getIntent()); } @@ -81,18 +73,10 @@ public class DataUsagePreference extends Preference implements TemplatePreferenc .setArguments(args) .setDestination(DataUsageList.class.getName()) .setSourceMetricsCategory(MetricsProto.MetricsEvent.VIEW_UNKNOWN); - if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.DATA_USAGE_SETTINGS_V2)) { - if (mTemplate.isMatchRuleMobile()) { - launcher.setTitleRes(R.string.app_cellular_data_usage); - } else { - launcher.setTitleRes(mTitleRes); - } + if (mTemplate.isMatchRuleMobile()) { + launcher.setTitleRes(R.string.app_cellular_data_usage); } else { - if (mTitleRes > 0) { - launcher.setTitleRes(mTitleRes); - } else { - launcher.setTitleText(getTitle()); - } + launcher.setTitleRes(mTitleRes); } return launcher.toIntent(); } diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java index 1b012f1e845..58a5a8f1f95 100644 --- a/src/com/android/settings/datausage/DataUsageSummary.java +++ b/src/com/android/settings/datausage/DataUsageSummary.java @@ -15,15 +15,10 @@ package com.android.settings.datausage; import android.app.Activity; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.net.NetworkTemplate; import android.os.Bundle; import android.provider.SearchIndexableResource; -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionPlan; @@ -33,7 +28,6 @@ import android.text.SpannableString; import android.text.TextUtils; import android.text.format.Formatter; import android.text.style.RelativeSizeSpan; -import android.view.MenuItem; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; @@ -49,6 +43,10 @@ import com.android.settingslib.search.SearchIndexable; import java.util.ArrayList; import java.util.List; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + /** * Settings preference fragment that displays data usage summary. */ @@ -120,20 +118,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable setHasOptionsMenu(true); } - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.data_usage_menu_cellular_networks: { - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setComponent(new ComponentName("com.android.phone", - "com.android.phone.MobileNetworkSettings")); - startActivity(intent); - return true; - } - } - return false; - } - @Override public boolean onPreferenceTreeClick(Preference preference) { if (preference == findPreference(KEY_STATUS_HEADER)) { diff --git a/src/com/android/settings/datausage/DataUsageSummaryLegacy.java b/src/com/android/settings/datausage/DataUsageSummaryLegacy.java deleted file mode 100644 index f54d6ef3825..00000000000 --- a/src/com/android/settings/datausage/DataUsageSummaryLegacy.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (C) 2016 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.datausage; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.net.NetworkPolicyManager; -import android.net.NetworkTemplate; -import android.os.Bundle; -import android.os.UserManager; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.text.BidiFormatter; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.TextUtils; -import android.text.format.Formatter; -import android.text.style.RelativeSizeSpan; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.SummaryPreference; -import com.android.settings.Utils; -import com.android.settings.dashboard.SummaryLoader; -import com.android.settings.search.Indexable; -import com.android.settingslib.NetworkPolicyEditor; -import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.net.DataUsageController; - -import java.util.List; - -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -/** - * Legacy {@link DataUsageSummary} fragment. - */ -public class DataUsageSummaryLegacy extends DataUsageBaseFragment implements Indexable, - DataUsageEditController { - - private static final String TAG = "DataUsageSummaryLegacy"; - - static final boolean LOGD = false; - - public static final String KEY_RESTRICT_BACKGROUND = "restrict_background_legacy"; - - private static final String KEY_STATUS_HEADER = "status_header"; - private static final String KEY_LIMIT_SUMMARY = "limit_summary"; - - // Mobile data keys - public static final String KEY_MOBILE_USAGE_TITLE = "mobile_category"; - public static final String KEY_MOBILE_DATA_USAGE_TOGGLE = "data_usage_enable"; - public static final String KEY_MOBILE_DATA_USAGE = "cellular_data_usage"; - public static final String KEY_MOBILE_BILLING_CYCLE = "billing_preference"; - - // Wifi keys - public static final String KEY_WIFI_USAGE_TITLE = "wifi_category"; - public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage"; - - private DataUsageController mDataUsageController; - private DataUsageInfoController mDataInfoController; - private SummaryPreference mSummaryPreference; - private Preference mLimitPreference; - private NetworkTemplate mDefaultTemplate; - private int mDataUsageTemplate; - private NetworkPolicyEditor mPolicyEditor; - - @Override - public int getHelpResource() { - return R.string.help_url_data_usage; - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - final Context context = getContext(); - NetworkPolicyManager policyManager = NetworkPolicyManager.from(context); - mPolicyEditor = new NetworkPolicyEditor(policyManager); - - boolean hasMobileData = DataUsageUtils.hasMobileData(context); - mDataUsageController = new DataUsageController(context); - mDataInfoController = new DataUsageInfoController(); - - int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context); - if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - hasMobileData = false; - } - mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId); - mSummaryPreference = (SummaryPreference) findPreference(KEY_STATUS_HEADER); - - if (!hasMobileData || !isAdmin()) { - removePreference(KEY_RESTRICT_BACKGROUND); - } - if (hasMobileData) { - mLimitPreference = findPreference(KEY_LIMIT_SUMMARY); - List subscriptions = - services.mSubscriptionManager.getActiveSubscriptionInfoList(); - if (subscriptions == null || subscriptions.size() == 0) { - addMobileSection(defaultSubId); - } - for (int i = 0; subscriptions != null && i < subscriptions.size(); i++) { - SubscriptionInfo subInfo = subscriptions.get(i); - if (subscriptions.size() > 1) { - addMobileSection(subInfo.getSubscriptionId(), subInfo); - } else { - addMobileSection(subInfo.getSubscriptionId()); - } - } - mSummaryPreference.setSelectable(true); - } else { - removePreference(KEY_LIMIT_SUMMARY); - mSummaryPreference.setSelectable(false); - } - boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context); - if (hasWifiRadio) { - addWifiSection(); - } - if (hasEthernet(context)) { - addEthernetSection(); - } - mDataUsageTemplate = hasMobileData ? R.string.cell_data_template - : hasWifiRadio ? R.string.wifi_data_template - : R.string.ethernet_data_template; - - setHasOptionsMenu(true); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - if (UserManager.get(getContext()).isAdminUser()) { - inflater.inflate(R.menu.data_usage, menu); - } - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.data_usage_menu_cellular_networks: { - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setComponent(new ComponentName("com.android.phone", - "com.android.phone.MobileNetworkSettings")); - startActivity(intent); - return true; - } - } - return false; - } - - @Override - public boolean onPreferenceTreeClick(Preference preference) { - if (preference == findPreference(KEY_STATUS_HEADER)) { - BillingCycleSettings.BytesEditorFragment.show(this, false); - return false; - } - return super.onPreferenceTreeClick(preference); - } - - @Override - protected int getPreferenceScreenResId() { - return R.xml.data_usage_legacy; - } - - @Override - protected String getLogTag() { - return TAG; - } - - @Override - protected List createPreferenceControllers(Context context) { - return null; - } - - private void addMobileSection(int subId) { - addMobileSection(subId, null); - } - - private void addMobileSection(int subId, SubscriptionInfo subInfo) { - TemplatePreferenceCategory category = (TemplatePreferenceCategory) - inflatePreferences(R.xml.data_usage_cellular); - category.setTemplate(getNetworkTemplate(subId), subId, services); - category.pushTemplates(services); - if (subInfo != null && !TextUtils.isEmpty(subInfo.getDisplayName())) { - Preference title = category.findPreference(KEY_MOBILE_USAGE_TITLE); - title.setTitle(subInfo.getDisplayName()); - } - } - - private void addWifiSection() { - TemplatePreferenceCategory category = (TemplatePreferenceCategory) - inflatePreferences(R.xml.data_usage_wifi); - category.setTemplate(NetworkTemplate.buildTemplateWifiWildcard(), 0, services); - } - - private void addEthernetSection() { - TemplatePreferenceCategory category = (TemplatePreferenceCategory) - inflatePreferences(R.xml.data_usage_ethernet); - category.setTemplate(NetworkTemplate.buildTemplateEthernet(), 0, services); - } - - private Preference inflatePreferences(int resId) { - PreferenceScreen rootPreferences = getPreferenceManager().inflateFromResource( - getPrefContext(), resId, null); - Preference pref = rootPreferences.getPreference(0); - rootPreferences.removeAll(); - - PreferenceScreen screen = getPreferenceScreen(); - pref.setOrder(screen.getPreferenceCount()); - screen.addPreference(pref); - - return pref; - } - - private NetworkTemplate getNetworkTemplate(int subscriptionId) { - NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( - services.mTelephonyManager.getSubscriberId(subscriptionId)); - return NetworkTemplate.normalize(mobileAll, - services.mTelephonyManager.getMergedSubscriberIds()); - } - - @Override - public void onResume() { - super.onResume(); - updateState(); - } - - @VisibleForTesting - static CharSequence formatUsage(Context context, String template, long usageLevel) { - final float LARGER_SIZE = 1.25f * 1.25f; // (1/0.8)^2 - final float SMALLER_SIZE = 1.0f / LARGER_SIZE; // 0.8^2 - final int FLAGS = Spannable.SPAN_INCLUSIVE_INCLUSIVE; - - final Formatter.BytesResult usedResult = Formatter.formatBytes(context.getResources(), - usageLevel, Formatter.FLAG_CALCULATE_ROUNDED); - final SpannableString enlargedValue = new SpannableString(usedResult.value); - enlargedValue.setSpan(new RelativeSizeSpan(LARGER_SIZE), 0, enlargedValue.length(), FLAGS); - - final SpannableString amountTemplate = new SpannableString( - context.getString(com.android.internal.R.string.fileSizeSuffix) - .replace("%1$s", "^1").replace("%2$s", "^2")); - final CharSequence formattedUsage = TextUtils.expandTemplate(amountTemplate, - enlargedValue, usedResult.units); - - final SpannableString fullTemplate = new SpannableString(template); - fullTemplate.setSpan(new RelativeSizeSpan(SMALLER_SIZE), 0, fullTemplate.length(), FLAGS); - return TextUtils.expandTemplate(fullTemplate, - BidiFormatter.getInstance().unicodeWrap(formattedUsage.toString())); - } - - private void updateState() { - DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo( - mDefaultTemplate); - Context context = getContext(); - mDataInfoController.updateDataLimit(info, - services.mPolicyEditor.getPolicy(mDefaultTemplate)); - - if (mSummaryPreference != null) { - mSummaryPreference.setTitle( - formatUsage(context, getString(mDataUsageTemplate), info.usageLevel)); - final long limit = mDataInfoController.getSummaryLimit(info); - mSummaryPreference.setSummary(info.period); - if (limit <= 0) { - mSummaryPreference.setChartEnabled(false); - } else { - mSummaryPreference.setChartEnabled(true); - mSummaryPreference.setLabels(Formatter.formatFileSize(context, 0), - Formatter.formatFileSize(context, limit)); - mSummaryPreference.setRatios(info.usageLevel / (float) limit, 0, - (limit - info.usageLevel) / (float) limit); - } - } - if (mLimitPreference != null && (info.warningLevel > 0 || info.limitLevel > 0)) { - String warning = Formatter.formatFileSize(context, info.warningLevel); - String limit = Formatter.formatFileSize(context, info.limitLevel); - mLimitPreference.setSummary(getString(info.limitLevel <= 0 ? R.string.cell_warning_only - : R.string.cell_warning_and_limit, warning, limit)); - } else if (mLimitPreference != null) { - mLimitPreference.setSummary(null); - } - - PreferenceScreen screen = getPreferenceScreen(); - for (int i = 1; i < screen.getPreferenceCount(); i++) { - ((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services); - } - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.DATA_USAGE_SUMMARY; - } - - @Override - public NetworkPolicyEditor getNetworkPolicyEditor() { - return services.mPolicyEditor; - } - - @Override - public NetworkTemplate getNetworkTemplate() { - return mDefaultTemplate; - } - - @Override - public void updateDataUsage() { - updateState(); - } - - private static class SummaryProvider - implements SummaryLoader.SummaryProvider { - - private final Activity mActivity; - private final SummaryLoader mSummaryLoader; - private final DataUsageController mDataController; - - public SummaryProvider(Activity activity, SummaryLoader summaryLoader) { - mActivity = activity; - mSummaryLoader = summaryLoader; - mDataController = new DataUsageController(activity); - } - - @Override - public void setListening(boolean listening) { - if (listening) { - DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo(); - String used; - if (info == null) { - used = Formatter.formatFileSize(mActivity, 0); - } else if (info.limitLevel <= 0) { - used = Formatter.formatFileSize(mActivity, info.usageLevel); - } else { - used = Utils.formatPercentage(info.usageLevel, info.limitLevel); - } - mSummaryLoader.setSummary(this, - mActivity.getString(R.string.data_usage_summary_format, used)); - } - } - } - - public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY - = SummaryProvider::new; -} diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider index 655346b0a02..a55f02483c8 100644 --- a/tests/robotests/assets/grandfather_not_implementing_index_provider +++ b/tests/robotests/assets/grandfather_not_implementing_index_provider @@ -7,7 +7,6 @@ com.android.settings.accounts.AccountDetailDashboardFragment com.android.settings.accounts.ManagedProfileSettings com.android.settings.fuelgauge.PowerUsageAnomalyDetails com.android.settings.fuelgauge.AdvancedPowerUsageDetail -com.android.settings.datausage.DataUsageSummaryLegacy com.android.settings.development.featureflags.FeatureFlagsDashboard com.android.settings.development.qstile.DevelopmentTileConfigFragment com.android.settings.deviceinfo.StorageProfileFragment diff --git a/tests/robotests/src/com/android/settings/dashboard/conditional/BackgroundDataConditionTest.java b/tests/robotests/src/com/android/settings/dashboard/conditional/BackgroundDataConditionTest.java index 9b5bec359ad..725be7962d4 100644 --- a/tests/robotests/src/com/android/settings/dashboard/conditional/BackgroundDataConditionTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/conditional/BackgroundDataConditionTest.java @@ -22,10 +22,8 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; -import android.util.FeatureFlagUtils; import com.android.settings.Settings; -import com.android.settings.core.FeatureFlags; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; @@ -51,9 +49,7 @@ public class BackgroundDataConditionTest { } @Test - public void onPrimaryClick_v2enabled_shouldReturn2SummaryActivity() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.DATA_USAGE_SETTINGS_V2, true); - + public void onPrimaryClick_shouldReturn2SummaryActivity() { final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); BackgroundDataCondition backgroundDataCondition = new BackgroundDataCondition(mConditionManager); @@ -64,19 +60,4 @@ public class BackgroundDataConditionTest { assertThat(intent.getComponent().getClassName()).isEqualTo( Settings.DataUsageSummaryActivity.class.getName()); } - - @Test - public void onPrimaryClick_v2disabled_shouldReturnLegacySummaryActivity() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.DATA_USAGE_SETTINGS_V2, false); - - final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); - BackgroundDataCondition backgroundDataCondition - = new BackgroundDataCondition(mConditionManager); - backgroundDataCondition.onPrimaryClick(); - verify(mContext).startActivity(argumentCaptor.capture()); - Intent intent = argumentCaptor.getValue(); - - assertThat(intent.getComponent().getClassName()).isEqualTo( - Settings.DataUsageSummaryLegacyActivity.class.getName()); - } } diff --git a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java index e4ed8bf9721..2d446288947 100644 --- a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java +++ b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java @@ -31,12 +31,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; -import androidx.preference.Preference; -import androidx.preference.PreferenceManager; -import androidx.preference.SwitchPreference; -import android.util.FeatureFlagUtils; -import com.android.settings.core.FeatureFlags; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settingslib.NetworkPolicyEditor; @@ -47,6 +42,10 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; +import androidx.preference.Preference; +import androidx.preference.PreferenceManager; +import androidx.preference.SwitchPreference; + @RunWith(SettingsRobolectricTestRunner.class) public class BillingCycleSettingsTest { @@ -108,14 +107,12 @@ public class BillingCycleSettingsTest { } @Test - public void testDataUsageSummary_shouldBeNullWithV2() { + public void testDataUsageSummary_shouldBeNull() { final BillingCycleSettings billingCycleSettings = spy(new BillingCycleSettings()); when(billingCycleSettings.getContext()).thenReturn(mContext); billingCycleSettings.setUpForTest(mNetworkPolicyEditor, mBillingCycle, mDataLimit, mDataWarning, mEnableDataLimit, mEnableDataWarning); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.DATA_USAGE_SETTINGS_V2, true); - doReturn("some-string").when(billingCycleSettings).getString(anyInt(), anyInt()); when(mNetworkPolicyEditor.getPolicyCycleDay(anyObject())).thenReturn(CYCLE_NONE + 1); when(mNetworkPolicyEditor.getPolicyLimitBytes(anyObject())).thenReturn(2000L); diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryLegacyTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryLegacyTest.java deleted file mode 100644 index 2216792836c..00000000000 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryLegacyTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2016 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.datausage; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.text.format.Formatter; - -import com.android.settings.R; -import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settings.testutils.shadow.SettingsShadowResources; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.shadows.ShadowApplication; - -@RunWith(SettingsRobolectricTestRunner.class) -public class DataUsageSummaryLegacyTest { - - @Mock - private ConnectivityManager mManager; - private Context mContext; - - /** - * This set up is contrived to get a passing test so that the build doesn't block without tests. - * These tests should be updated as code gets refactored to improve testability. - */ - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - ShadowApplication shadowContext = ShadowApplication.getInstance(); - shadowContext.setSystemService(Context.CONNECTIVITY_SERVICE, mManager); - mContext = shadowContext.getApplicationContext(); - when(mManager.isNetworkSupported(anyInt())).thenReturn(true); - } - - @Test - public void formatUsage_shouldLookLikeFormatFileSize() { - SettingsShadowResources - .overrideResource(com.android.internal.R.string.fileSizeSuffix, "%1$s %2$s"); - final long usage = 2147483648L; // 2GB - final String formattedUsage = - DataUsageSummaryLegacy.formatUsage(mContext, "^1", usage).toString(); - final String formattedAsFileSize = Formatter.formatFileSize(mContext, usage); - assertThat(formattedUsage).isEqualTo(formattedAsFileSize); - } -} diff --git a/tests/uitests/src/com/android/settings/ui/inputmethods/DataSaverSummaryUITest.java b/tests/uitests/src/com/android/settings/ui/inputmethods/DataSaverSummaryUITest.java index f6f5d432bc7..45f757c2698 100644 --- a/tests/uitests/src/com/android/settings/ui/inputmethods/DataSaverSummaryUITest.java +++ b/tests/uitests/src/com/android/settings/ui/inputmethods/DataSaverSummaryUITest.java @@ -44,7 +44,7 @@ public class DataSaverSummaryUITest { mInstrumentation = InstrumentationRegistry.getInstrumentation(); mUiDevice = UiDevice.getInstance(mInstrumentation); mIntent = new Intent().setClassName("com.android.settings", - "com.android.settings.Settings$DataUsageSummaryLegacyActivity") + "com.android.settings.Settings$DataUsageSummaryActivity") .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } From cb691873fd85ba92cd0b978abfad2635559c5723 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Mon, 21 May 2018 14:17:26 -0400 Subject: [PATCH 5/8] Handle usageevents for work profile apps Test: robotests Change-Id: Ifdc6e456d76614220b2052e6ca8a8f3676d0e2ee Fixes: 79142791 --- .../AppStateNotificationBridge.java | 85 ++++++++++-- .../ManageApplications.java | 11 +- .../AppStateNotificationBridgeTest.java | 130 ++++++++++++++---- .../ManageApplicationsTest.java | 32 +++-- 4 files changed, 206 insertions(+), 52 deletions(-) diff --git a/src/com/android/settings/applications/AppStateNotificationBridge.java b/src/com/android/settings/applications/AppStateNotificationBridge.java index a96a3b1ad7b..6cf64c3e57b 100644 --- a/src/com/android/settings/applications/AppStateNotificationBridge.java +++ b/src/com/android/settings/applications/AppStateNotificationBridge.java @@ -15,9 +15,13 @@ */ package com.android.settings.applications; +import android.app.usage.IUsageStatsManager; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManager; import android.content.Context; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; import android.text.format.DateUtils; import android.util.ArrayMap; import android.view.View; @@ -25,6 +29,7 @@ import android.view.ViewGroup; import android.widget.Switch; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.notification.NotificationBackend; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; @@ -33,6 +38,7 @@ import com.android.settingslib.utils.StringUtil; import java.util.ArrayList; import java.util.Comparator; +import java.util.List; import java.util.Map; /** @@ -42,17 +48,24 @@ import java.util.Map; public class AppStateNotificationBridge extends AppStateBaseBridge { private final Context mContext; - private UsageStatsManager mUsageStatsManager; + private IUsageStatsManager mUsageStatsManager; + protected List mUserIds; private NotificationBackend mBackend; private static final int DAYS_TO_CHECK = 7; public AppStateNotificationBridge(Context context, ApplicationsState appState, - Callback callback, UsageStatsManager usageStatsManager, - NotificationBackend backend) { + Callback callback, IUsageStatsManager usageStatsManager, + UserManager userManager, NotificationBackend backend) { super(appState, callback); mContext = context; mUsageStatsManager = usageStatsManager; mBackend = backend; + mUserIds = new ArrayList<>(); + mUserIds.add(mContext.getUserId()); + int workUserId = Utils.getManagedProfileId(userManager, mContext.getUserId()); + if (workUserId != UserHandle.USER_NULL) { + mUserIds.add(workUserId); + } } @Override @@ -62,7 +75,8 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { final Map map = getAggregatedUsageEvents(); for (AppEntry entry : apps) { - NotificationsSentState stats = map.get(entry.info.packageName); + NotificationsSentState stats = + map.get(getKey(UserHandle.getUserId(entry.info.uid), entry.info.packageName)); calculateAvgSentCounts(stats); addBlockStatus(entry, stats); entry.extraInfo = stats; @@ -71,8 +85,8 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { @Override protected void updateExtraInfo(AppEntry entry, String pkg, int uid) { - Map map = getAggregatedUsageEvents(); - NotificationsSentState stats = map.get(entry.info.packageName); + NotificationsSentState stats = getAggregatedUsageEvents( + UserHandle.getUserId(entry.info.uid), entry.info.packageName); calculateAvgSentCounts(stats); addBlockStatus(entry, stats); entry.extraInfo = stats; @@ -116,18 +130,59 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { long now = System.currentTimeMillis(); long startTime = now - (DateUtils.DAY_IN_MILLIS * DAYS_TO_CHECK); - UsageEvents events = mUsageStatsManager.queryEvents(startTime, now); + for (int userId : mUserIds) { + UsageEvents events = null; + try { + events = mUsageStatsManager.queryEventsForUser( + startTime, now, userId, mContext.getPackageName()); + } catch (RemoteException e) { + e.printStackTrace(); + } + if (events != null) { + UsageEvents.Event event = new UsageEvents.Event(); + while (events.hasNextEvent()) { + events.getNextEvent(event); + NotificationsSentState stats = + aggregatedStats.get(getKey(userId, event.getPackageName())); + if (stats == null) { + stats = new NotificationsSentState(); + aggregatedStats.put(getKey(userId, event.getPackageName()), stats); + } + + if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) { + if (event.getTimeStamp() > stats.lastSent) { + stats.lastSent = event.getTimeStamp(); + } + stats.sentCount++; + } + + } + } + } + return aggregatedStats; + } + + protected NotificationsSentState getAggregatedUsageEvents(int userId, String pkg) { + NotificationsSentState stats = null; + + long now = System.currentTimeMillis(); + long startTime = now - (DateUtils.DAY_IN_MILLIS * DAYS_TO_CHECK); + UsageEvents events = null; + try { + events = mUsageStatsManager.queryEventsForPackageForUser( + startTime, now, userId, pkg, mContext.getPackageName()); + } catch (RemoteException e) { + e.printStackTrace(); + } if (events != null) { UsageEvents.Event event = new UsageEvents.Event(); while (events.hasNextEvent()) { events.getNextEvent(event); - NotificationsSentState stats = aggregatedStats.get(event.getPackageName()); - if (stats == null) { - stats = new NotificationsSentState(); - aggregatedStats.put(event.getPackageName(), stats); - } if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) { + if (stats == null) { + stats = new NotificationsSentState(); + } if (event.getTimeStamp() > stats.lastSent) { stats.lastSent = event.getTimeStamp(); } @@ -136,7 +191,7 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { } } - return aggregatedStats; + return stats; } private static NotificationsSentState getNotificationsSentState(AppEntry entry) { @@ -149,6 +204,10 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { return null; } + protected static String getKey(int userId, String pkg) { + return userId + "|" + pkg; + } + public View.OnClickListener getSwitchOnClickListener(final AppEntry entry) { if (entry != null) { return v -> { diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index 2250f285c23..dc9214e59b1 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -41,6 +41,7 @@ import static com.android.settings.applications.manageapplications.AppFilterRegi import android.annotation.Nullable; import android.annotation.StringRes; import android.app.Activity; +import android.app.usage.IUsageStatsManager; import android.app.usage.UsageStatsManager; import android.content.Context; import android.content.Intent; @@ -48,6 +49,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageItemInfo; import android.os.Bundle; import android.os.Environment; +import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.preference.PreferenceFrameLayout; @@ -224,7 +226,8 @@ public class ManageApplications extends InstrumentedFragment private View mSpinnerHeader; private Spinner mFilterSpinner; private FilterSpinnerAdapter mFilterAdapter; - private UsageStatsManager mUsageStatsManager; + private IUsageStatsManager mUsageStatsManager; + private UserManager mUserManager; private NotificationBackend mNotificationBackend; private ResetAppsHelper mResetAppsHelper; private String mVolumeUuid; @@ -294,8 +297,9 @@ public class ManageApplications extends InstrumentedFragment screenTitle = R.string.change_wifi_state_title; } else if (className.equals(Settings.NotificationAppListActivity.class.getName())) { mListType = LIST_TYPE_NOTIFICATION; - mUsageStatsManager = - (UsageStatsManager) getContext().getSystemService(Context.USAGE_STATS_SERVICE); + mUsageStatsManager = IUsageStatsManager.Stub.asInterface( + ServiceManager.getService(Context.USAGE_STATS_SERVICE)); + mUserManager = UserManager.get(getContext()); mNotificationBackend = new NotificationBackend(); mSortOrder = R.id.sort_order_recent_notification; screenTitle = R.string.app_notifications_title; @@ -889,6 +893,7 @@ public class ManageApplications extends InstrumentedFragment if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) { mExtraInfoBridge = new AppStateNotificationBridge(mContext, mState, this, manageApplications.mUsageStatsManager, + manageApplications.mUserManager, manageApplications.mNotificationBackend); } else if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) { mExtraInfoBridge = new AppStateUsageBridge(mContext, mState, this); diff --git a/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java b/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java index 9437a00766f..8e3bb4254a0 100644 --- a/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java +++ b/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java @@ -36,17 +36,21 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.usage.IUsageStatsManager; import android.app.usage.UsageEvents; import android.app.usage.UsageEvents.Event; -import android.app.usage.UsageStatsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Looper; import android.os.Parcel; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; import android.view.ViewGroup; import android.widget.Switch; @@ -79,7 +83,9 @@ public class AppStateNotificationBridgeTest { @Mock private ApplicationsState mState; @Mock - private UsageStatsManager mUsageStats; + private IUsageStatsManager mUsageStats; + @Mock + private UserManager mUserManager; @Mock private NotificationBackend mBackend; private Context mContext; @@ -92,10 +98,12 @@ public class AppStateNotificationBridgeTest { when(mState.getBackgroundLooper()).thenReturn(mock(Looper.class)); when(mBackend.getNotificationsBanned(anyString(), anyInt())).thenReturn(true); when(mBackend.isSystemApp(any(), any())).thenReturn(true); + // most tests assume no work profile + when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); mContext = RuntimeEnvironment.application.getApplicationContext(); mBridge = new AppStateNotificationBridge(mContext, mState, - mock(AppStateBaseBridge.Callback.class), mUsageStats, mBackend); + mock(AppStateBaseBridge.Callback.class), mUsageStats, mUserManager, mBackend); } private AppEntry getMockAppEntry(String pkg) { @@ -115,14 +123,15 @@ public class AppStateNotificationBridgeTest { } @Test - public void testGetAggregatedUsageEvents_noEvents() { - when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(mock(UsageEvents.class)); + public void testGetAggregatedUsageEvents_noEvents() throws Exception { + when(mUsageStats.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) + .thenReturn(mock(UsageEvents.class)); assertThat(mBridge.getAggregatedUsageEvents()).isEmpty(); } @Test - public void testGetAggregatedUsageEvents_onlyNotificationEvents() { + public void testGetAggregatedUsageEvents_onlyNotificationEvents() throws Exception { List events = new ArrayList<>(); Event good = new Event(); good.mEventType = Event.NOTIFICATION_INTERRUPTION; @@ -136,14 +145,15 @@ public class AppStateNotificationBridgeTest { events.add(bad); UsageEvents usageEvents = getUsageEvents(events); - when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + when(mUsageStats.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) + .thenReturn(usageEvents); Map map = mBridge.getAggregatedUsageEvents(); - assertThat(map.get(PKG1).sentCount).isEqualTo(1); + assertThat(map.get(mBridge.getKey(0, PKG1)).sentCount).isEqualTo(1); } @Test - public void testGetAggregatedUsageEvents_multipleEventsAgg() { + public void testGetAggregatedUsageEvents_multipleEventsAgg() throws Exception { List events = new ArrayList<>(); Event good = new Event(); good.mEventType = Event.NOTIFICATION_INTERRUPTION; @@ -157,15 +167,16 @@ public class AppStateNotificationBridgeTest { events.add(good1); UsageEvents usageEvents = getUsageEvents(events); - when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + when(mUsageStats.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) + .thenReturn(usageEvents); Map map = mBridge.getAggregatedUsageEvents(); - assertThat(map.get(PKG1).sentCount).isEqualTo(2); - assertThat(map.get(PKG1).lastSent).isEqualTo(6); + assertThat(map.get(mBridge.getKey(0, PKG1)).sentCount).isEqualTo(2); + assertThat(map.get(mBridge.getKey(0, PKG1)).lastSent).isEqualTo(6); } @Test - public void testGetAggregatedUsageEvents_multiplePkgs() { + public void testGetAggregatedUsageEvents_multiplePkgs() throws Exception { List events = new ArrayList<>(); Event good = new Event(); good.mEventType = Event.NOTIFICATION_INTERRUPTION; @@ -179,19 +190,21 @@ public class AppStateNotificationBridgeTest { events.add(good1); UsageEvents usageEvents = getUsageEvents(events); - when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + when(mUsageStats.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) + .thenReturn(usageEvents); Map map = mBridge.getAggregatedUsageEvents(); - assertThat(map.get(PKG1).sentCount).isEqualTo(1); - assertThat(map.get(PKG2).sentCount).isEqualTo(1); - assertThat(map.get(PKG1).lastSent).isEqualTo(6); - assertThat(map.get(PKG2).lastSent).isEqualTo(1); + assertThat(map.get(mBridge.getKey(0, PKG1)).sentCount).isEqualTo(1); + assertThat(map.get(mBridge.getKey(0, PKG2)).sentCount).isEqualTo(1); + assertThat(map.get(mBridge.getKey(0, PKG1)).lastSent).isEqualTo(6); + assertThat(map.get(mBridge.getKey(0, PKG2)).lastSent).isEqualTo(1); } @Test - public void testLoadAllExtraInfo_noEvents() { - when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(mock(UsageEvents.class)); + public void testLoadAllExtraInfo_noEvents() throws RemoteException { + when(mUsageStats.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) + .thenReturn(mock(UsageEvents.class)); ArrayList apps = new ArrayList<>(); apps.add(getMockAppEntry(PKG1)); when(mSession.getAllApps()).thenReturn(apps); @@ -201,7 +214,7 @@ public class AppStateNotificationBridgeTest { } @Test - public void testLoadAllExtraInfo_multipleEventsAgg() { + public void testLoadAllExtraInfo_multipleEventsAgg() throws RemoteException { List events = new ArrayList<>(); for (int i = 0; i < 7; i++) { Event good = new Event(); @@ -212,7 +225,8 @@ public class AppStateNotificationBridgeTest { } UsageEvents usageEvents = getUsageEvents(events); - when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + when(mUsageStats.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) + .thenReturn(usageEvents); ArrayList apps = new ArrayList<>(); apps.add(getMockAppEntry(PKG1)); @@ -229,7 +243,7 @@ public class AppStateNotificationBridgeTest { } @Test - public void testLoadAllExtraInfo_multiplePkgs() { + public void testLoadAllExtraInfo_multiplePkgs() throws RemoteException { List events = new ArrayList<>(); for (int i = 0; i < 8; i++) { Event good = new Event(); @@ -245,7 +259,8 @@ public class AppStateNotificationBridgeTest { events.add(good1); UsageEvents usageEvents = getUsageEvents(events); - when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + when(mUsageStats.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) + .thenReturn(usageEvents); ArrayList apps = new ArrayList<>(); apps.add(getMockAppEntry(PKG1)); @@ -265,8 +280,66 @@ public class AppStateNotificationBridgeTest { } @Test - public void testUpdateExtraInfo_noEvents() { - when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(mock(UsageEvents.class)); + public void testLoadAllExtraInfo_multipleUsers() throws RemoteException { + // has work profile + when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{1}); + mBridge = new AppStateNotificationBridge(mContext, mState, + mock(AppStateBaseBridge.Callback.class), mUsageStats, mUserManager, mBackend); + + List eventsProfileOwner = new ArrayList<>(); + for (int i = 0; i < 8; i++) { + Event good = new Event(); + good.mEventType = Event.NOTIFICATION_INTERRUPTION; + good.mPackage = PKG1; + good.mTimeStamp = i; + eventsProfileOwner.add(good); + } + + List eventsProfile = new ArrayList<>(); + for (int i = 0; i < 4; i++) { + Event good = new Event(); + good.mEventType = Event.NOTIFICATION_INTERRUPTION; + good.mPackage = PKG1; + good.mTimeStamp = i; + eventsProfile.add(good); + } + + UsageEvents usageEventsOwner = getUsageEvents(eventsProfileOwner); + when(mUsageStats.queryEventsForUser(anyLong(), anyLong(), eq(0), anyString())) + .thenReturn(usageEventsOwner); + + UsageEvents usageEventsProfile = getUsageEvents(eventsProfile); + when(mUsageStats.queryEventsForUser(anyLong(), anyLong(), eq(1), anyString())) + .thenReturn(usageEventsProfile); + + ArrayList apps = new ArrayList<>(); + AppEntry owner = getMockAppEntry(PKG1); + owner.info.uid = 1; + apps.add(owner); + + AppEntry profile = getMockAppEntry(PKG1); + profile.info.uid = UserHandle.PER_USER_RANGE + 1; + apps.add(profile); + when(mSession.getAllApps()).thenReturn(apps); + + mBridge.loadAllExtraInfo(); + + assertThat(((NotificationsSentState) apps.get(0).extraInfo).sentCount).isEqualTo(8); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).lastSent).isEqualTo(7); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentWeekly).isEqualTo(0); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentDaily).isEqualTo(1); + + assertThat(((NotificationsSentState) apps.get(1).extraInfo).sentCount).isEqualTo(4); + assertThat(((NotificationsSentState) apps.get(1).extraInfo).lastSent).isEqualTo(3); + assertThat(((NotificationsSentState) apps.get(1).extraInfo).avgSentWeekly).isEqualTo(4); + assertThat(((NotificationsSentState) apps.get(1).extraInfo).avgSentDaily).isEqualTo(1); + } + + @Test + public void testUpdateExtraInfo_noEvents() throws RemoteException { + when(mUsageStats.queryEventsForPackageForUser( + anyLong(), anyLong(), anyInt(), anyString(), anyString())) + .thenReturn(mock(UsageEvents.class)); AppEntry entry = getMockAppEntry(PKG1); mBridge.updateExtraInfo(entry, "", 0); @@ -274,7 +347,7 @@ public class AppStateNotificationBridgeTest { } @Test - public void testUpdateExtraInfo_multipleEventsAgg() { + public void testUpdateExtraInfo_multipleEventsAgg() throws RemoteException { List events = new ArrayList<>(); for (int i = 0; i < 13; i++) { Event good = new Event(); @@ -285,7 +358,8 @@ public class AppStateNotificationBridgeTest { } UsageEvents usageEvents = getUsageEvents(events); - when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + when(mUsageStats.queryEventsForPackageForUser( + anyLong(), anyLong(), anyInt(), anyString(), anyString())).thenReturn(usageEvents); AppEntry entry = getMockAppEntry(PKG1); mBridge.updateExtraInfo(entry, "", 0); diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java index af297c4d9c2..8943d72ad33 100644 --- a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java +++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java @@ -16,14 +16,14 @@ package com.android.settings.applications.manageapplications; -import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING; -import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; -import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL; -import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN; -import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NOTIFICATION; -import static com.google.common.truth.Truth.assertThat; +import static com.android.settings.applications.manageapplications.AppFilterRegistry + .FILTER_APPS_ALL; +import static com.android.settings.applications.manageapplications.ManageApplications + .LIST_TYPE_MAIN; +import static com.android.settings.applications.manageapplications.ManageApplications + .LIST_TYPE_NOTIFICATION; -import static junit.framework.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Matchers.any; @@ -36,11 +36,14 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING; +import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; + import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.os.Looper; -import androidx.recyclerview.widget.RecyclerView; +import android.os.UserManager; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -63,6 +66,8 @@ import org.robolectric.util.ReflectionHelpers; import java.util.ArrayList; +import androidx.recyclerview.widget.RecyclerView; + @RunWith(SettingsRobolectricTestRunner.class) public class ManageApplicationsTest { @@ -272,6 +277,10 @@ public class ManageApplicationsTest { @Test public void applicationsAdapter_onBindViewHolder_updateSwitch_notifications() { ManageApplications manageApplications = mock(ManageApplications.class); + when(manageApplications.getActivity()).thenReturn(mock(Activity.class)); + UserManager um = mock(UserManager.class); + when(um.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); + ReflectionHelpers.setField(manageApplications, "mUserManager", um); manageApplications.mListType = LIST_TYPE_NOTIFICATION; ApplicationViewHolder holder = mock(ApplicationViewHolder.class); ReflectionHelpers.setField(holder, "itemView", mock(View.class)); @@ -293,6 +302,9 @@ public class ManageApplicationsTest { manageApplications.mListType = LIST_TYPE_MAIN; ApplicationViewHolder holder = mock(ApplicationViewHolder.class); ReflectionHelpers.setField(holder, "itemView", mock(View.class)); + UserManager um = mock(UserManager.class); + when(um.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); + ReflectionHelpers.setField(manageApplications, "mUserManager", um); ManageApplications.ApplicationsAdapter adapter = new ManageApplications.ApplicationsAdapter(mState, manageApplications, mock(AppFilterItem.class), @@ -308,6 +320,10 @@ public class ManageApplicationsTest { @Test public void sortOrderSavedOnRebuild() { ManageApplications manageApplications = mock(ManageApplications.class); + when(manageApplications.getActivity()).thenReturn(mock(Activity.class)); + UserManager um = mock(UserManager.class); + when(um.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); + ReflectionHelpers.setField(manageApplications, "mUserManager", um); manageApplications.mListType = LIST_TYPE_NOTIFICATION; manageApplications.mSortOrder = -1; ManageApplications.ApplicationsAdapter adapter = From c39238c63fffdc29aa4f43c9d3e27bc62ca3428a Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Tue, 5 Jun 2018 15:36:40 -0700 Subject: [PATCH 6/8] Add a switchbar to turn off multi-user feature entirely Change-Id: Ibf88bf37899af5065c68aeb2337acd4ee48bc13c Fixes: 72319180 Test: robotest on new controller. Manual test on UserSettings fragment. --- res/xml/security_lockscreen_settings.xml | 3 +- .../android/settings/core/FeatureFlags.java | 1 - .../security/LockscreenDashboardFragment.java | 5 -- ...AddUserWhenLockedPreferenceController.java | 69 +++++++---------- .../MultiUserFooterPreferenceController.java | 60 +++++++++++++++ .../users/MultiUserSwitchBarController.java | 73 ++++++++++++++++++ .../settings/users/UserCapabilities.java | 15 ++-- .../android/settings/users/UserSettings.java | 74 ++++++++++++++----- .../testutils/shadow/ShadowUserManager.java | 12 +++ ...serWhenLockedPreferenceControllerTest.java | 29 ++++---- ...ltiUserFooterPreferenceControllerTest.java | 59 +++++++++++++++ .../settings/users/UserCapabilitiesTest.java | 52 ++++++++++--- 12 files changed, 352 insertions(+), 100 deletions(-) create mode 100644 src/com/android/settings/users/MultiUserFooterPreferenceController.java create mode 100644 src/com/android/settings/users/MultiUserSwitchBarController.java create mode 100644 tests/robotests/src/com/android/settings/users/MultiUserFooterPreferenceControllerTest.java diff --git a/res/xml/security_lockscreen_settings.xml b/res/xml/security_lockscreen_settings.xml index a3fcaee83c2..2cd92c55df9 100644 --- a/res/xml/security_lockscreen_settings.xml +++ b/res/xml/security_lockscreen_settings.xml @@ -31,7 +31,8 @@ + android:title="@string/user_add_on_lockscreen_menu" + settings:controller="com.android.settings.users.AddUserWhenLockedPreferenceController" /> controllers = new ArrayList<>(); controllers.add(new LockScreenNotificationPreferenceController(context)); - controllers.add(new AddUserWhenLockedPreferenceController(context, - KEY_ADD_USER_FROM_LOCK_SCREEN, null /* lifecycle */)); controllers.add(new OwnerInfoPreferenceController( context, null /* fragment */, null /* lifecycle */)); return controllers; diff --git a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java index bebc2d73b06..2a61cac882f 100644 --- a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java +++ b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java @@ -16,72 +16,53 @@ package com.android.settings.users; import android.content.Context; -import android.provider.Settings.Global; +import android.provider.Settings; + +import com.android.settings.core.TogglePreferenceController; +import com.android.settingslib.RestrictedSwitchPreference; + import androidx.preference.Preference; -import com.android.settings.core.PreferenceControllerMixin; -import com.android.settingslib.RestrictedSwitchPreference; -import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.lifecycle.Lifecycle; -import com.android.settingslib.core.lifecycle.LifecycleObserver; -import com.android.settingslib.core.lifecycle.events.OnPause; -import com.android.settingslib.core.lifecycle.events.OnResume; +public class AddUserWhenLockedPreferenceController extends TogglePreferenceController { -public class AddUserWhenLockedPreferenceController extends AbstractPreferenceController - implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener, - LifecycleObserver, OnPause, OnResume { - - private final String mPrefKey; private final UserCapabilities mUserCaps; - private boolean mShouldUpdateUserList; - public AddUserWhenLockedPreferenceController(Context context, String key, Lifecycle lifecycle) { - super(context); - mPrefKey = key; + public AddUserWhenLockedPreferenceController(Context context, String key) { + super(context, key); mUserCaps = UserCapabilities.create(context); - if (lifecycle != null) { - lifecycle.addObserver(this); - } } @Override public void updateState(Preference preference) { - RestrictedSwitchPreference restrictedSwitchPreference = + super.updateState(preference); + mUserCaps.updateAddUserCapabilities(mContext); + final RestrictedSwitchPreference restrictedSwitchPreference = (RestrictedSwitchPreference) preference; - int value = Global.getInt(mContext.getContentResolver(), Global.ADD_USERS_WHEN_LOCKED, 0); - restrictedSwitchPreference.setChecked(value == 1); restrictedSwitchPreference.setDisabledByAdmin( mUserCaps.disallowAddUser() ? mUserCaps.getEnforcedAdmin() : null); + restrictedSwitchPreference.setVisible(mUserCaps.mUserSwitcherEnabled); } @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - Boolean value = (Boolean) newValue; - Global.putInt(mContext.getContentResolver(), - Global.ADD_USERS_WHEN_LOCKED, value != null && value ? 1 : 0); - return true; - } - - @Override - public void onPause() { - mShouldUpdateUserList = true; - } - - @Override - public void onResume() { - if (mShouldUpdateUserList) { - mUserCaps.updateAddUserCapabilities(mContext); + public int getAvailabilityStatus() { + if (!mUserCaps.isAdmin()) { + return DISABLED_FOR_USER; + } else if (mUserCaps.disallowAddUser() || mUserCaps.disallowAddUserSetByAdmin()) { + return DISABLED_FOR_USER; + } else { + return mUserCaps.mUserSwitcherEnabled ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } } @Override - public boolean isAvailable() { - return mUserCaps.isAdmin() && - (!mUserCaps.disallowAddUser() || mUserCaps.disallowAddUserSetByAdmin()); + public boolean isChecked() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.ADD_USERS_WHEN_LOCKED, 0) == 1; } @Override - public String getPreferenceKey() { - return mPrefKey; + public boolean setChecked(boolean isChecked) { + return Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.ADD_USERS_WHEN_LOCKED, isChecked ? 1 : 0); } } diff --git a/src/com/android/settings/users/MultiUserFooterPreferenceController.java b/src/com/android/settings/users/MultiUserFooterPreferenceController.java new file mode 100644 index 00000000000..877df581ee8 --- /dev/null +++ b/src/com/android/settings/users/MultiUserFooterPreferenceController.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.users; + +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.FooterPreferenceMixin; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; + +public class MultiUserFooterPreferenceController extends BasePreferenceController { + + @VisibleForTesting + final UserCapabilities mUserCaps; + + private FooterPreferenceMixin mFooterMixin; + + public MultiUserFooterPreferenceController(Context context) { + super(context, "dummy_key"); + mUserCaps = UserCapabilities.create(context); + } + + public MultiUserFooterPreferenceController setFooterMixin(FooterPreferenceMixin footerMixin) { + mFooterMixin = footerMixin; + return this; + } + + @Override + public int getAvailabilityStatus() { + return (mUserCaps.mEnabled && !mUserCaps.mUserSwitcherEnabled) + ? AVAILABLE_UNSEARCHABLE + : DISABLED_FOR_USER; + } + + @Override + public void updateState(Preference preference) { + mUserCaps.updateAddUserCapabilities(mContext); + final FooterPreference pref = mFooterMixin.createFooterPreference(); + pref.setTitle(R.string.user_settings_footer_text); + pref.setVisible(isAvailable()); + } +} diff --git a/src/com/android/settings/users/MultiUserSwitchBarController.java b/src/com/android/settings/users/MultiUserSwitchBarController.java new file mode 100644 index 00000000000..9588f714648 --- /dev/null +++ b/src/com/android/settings/users/MultiUserSwitchBarController.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.users; + +import android.content.Context; +import android.provider.Settings; +import android.util.Log; + +import com.android.settings.widget.SwitchWidgetController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; + +public class MultiUserSwitchBarController implements SwitchWidgetController.OnSwitchChangeListener, + LifecycleObserver, OnStart, OnStop { + + interface OnMultiUserSwitchChangedListener { + void onMultiUserSwitchChanged(boolean newState); + } + + private static final String TAG = "MultiUserSwitchBarCtrl"; + private final Context mContext; + private final SwitchWidgetController mSwitchBar; + private final UserCapabilities mUserCapabilities; + private final OnMultiUserSwitchChangedListener mListener; + + MultiUserSwitchBarController(Context context, SwitchWidgetController switchBar, + OnMultiUserSwitchChangedListener listener) { + mContext = context; + mSwitchBar = switchBar; + mListener = listener; + mUserCapabilities = UserCapabilities.create(context); + mSwitchBar.setChecked(mUserCapabilities.mUserSwitcherEnabled); + mSwitchBar.setEnabled(!mUserCapabilities.mDisallowSwitchUser + && !mUserCapabilities.mIsGuest && mUserCapabilities.isAdmin()); + mSwitchBar.setListener(this); + } + + @Override + public void onStart() { + mSwitchBar.startListening(); + } + + @Override + public void onStop() { + mSwitchBar.stopListening(); + } + + @Override + public boolean onSwitchToggled(boolean isChecked) { + Log.d(TAG, "Toggling multi-user feature enabled state to: " + isChecked); + final boolean success = Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.USER_SWITCHER_ENABLED, isChecked ? 1 : 0); + if (success && mListener != null) { + mListener.onMultiUserSwitchChanged(isChecked); + } + return success; + } +} diff --git a/src/com/android/settings/users/UserCapabilities.java b/src/com/android/settings/users/UserCapabilities.java index f1bfae90c97..b9a22288d92 100644 --- a/src/com/android/settings/users/UserCapabilities.java +++ b/src/com/android/settings/users/UserCapabilities.java @@ -22,6 +22,7 @@ import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; + import com.android.settings.Utils; import com.android.settingslib.RestrictedLockUtils; @@ -31,13 +32,15 @@ public class UserCapabilities { boolean mCanAddRestrictedProfile = true; boolean mIsAdmin; boolean mIsGuest; + boolean mUserSwitcherEnabled; boolean mCanAddGuest; boolean mDisallowAddUser; boolean mDisallowAddUserSetByAdmin; boolean mDisallowSwitchUser; RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin; - private UserCapabilities() {} + private UserCapabilities() { + } public static UserCapabilities create(Context context) { UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); @@ -62,14 +65,15 @@ public class UserCapabilities { } public void updateAddUserCapabilities(Context context) { + final UserManager userManager = + (UserManager) context.getSystemService(Context.USER_SERVICE); mEnforcedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(context, UserManager.DISALLOW_ADD_USER, UserHandle.myUserId()); final boolean hasBaseUserRestriction = RestrictedLockUtils.hasBaseUserRestriction( context, UserManager.DISALLOW_ADD_USER, UserHandle.myUserId()); - mDisallowAddUserSetByAdmin = - mEnforcedAdmin != null && !hasBaseUserRestriction; - mDisallowAddUser = - (mEnforcedAdmin != null || hasBaseUserRestriction); + mDisallowAddUserSetByAdmin = mEnforcedAdmin != null && !hasBaseUserRestriction; + mDisallowAddUser = (mEnforcedAdmin != null || hasBaseUserRestriction); + mUserSwitcherEnabled = userManager.isUserSwitcherEnabled(); mCanAddUser = true; if (!mIsAdmin || UserManager.getMaxSupportedUsers() < 2 || !UserManager.supportsMultipleUsers() @@ -81,7 +85,6 @@ public class UserCapabilities { context.getContentResolver(), Settings.Global.ADD_USERS_WHEN_LOCKED, 0) == 1; mCanAddGuest = !mIsGuest && !mDisallowAddUser && canAddUsersWhenLocked; - UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mDisallowSwitchUser = userManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH); } diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index a33561b3bbe..c57d959c0dc 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -48,13 +48,13 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.view.View.OnClickListener; import android.widget.SimpleAdapter; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.UserIcons; import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; +import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; import com.android.settings.core.SubSettingLauncher; @@ -62,6 +62,8 @@ import com.android.settings.dashboard.SummaryLoader; import com.android.settings.password.ChooseLockGeneric; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; +import com.android.settings.widget.SwitchBar; +import com.android.settings.widget.SwitchBarController; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedPreference; @@ -78,7 +80,6 @@ import java.util.List; import androidx.annotation.VisibleForTesting; import androidx.annotation.WorkerThread; import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceClickListener; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; @@ -92,7 +93,9 @@ import androidx.preference.PreferenceScreen; */ @SearchIndexable public class UserSettings extends SettingsPreferenceFragment - implements OnPreferenceClickListener, OnClickListener, DialogInterface.OnDismissListener, + implements Preference.OnPreferenceClickListener, View.OnClickListener, + MultiUserSwitchBarController.OnMultiUserSwitchChangedListener, + DialogInterface.OnDismissListener, EditUserInfoController.OnContentChangedCallback, Indexable { private static final String TAG = "UserSettings"; @@ -155,8 +158,10 @@ public class UserSettings extends SettingsPreferenceFragment private SparseArray mUserIcons = new SparseArray<>(); private static SparseArray sDarkDefaultUserBitmapCache = new SparseArray<>(); + private MultiUserSwitchBarController mSwitchBarController; private EditUserInfoController mEditUserInfoController = new EditUserInfoController(); private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController; + private MultiUserFooterPreferenceController mMultiUserFooterPreferenceController; // A place to cache the generated default avatar private Drawable mDefaultIconDrawable; @@ -198,20 +203,37 @@ public class UserSettings extends SettingsPreferenceFragment return MetricsEvent.USER; } + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + // Assume we are in a SettingsActivity. This is only safe because we currently use + // SettingsActivity as base for all preference fragments. + final SettingsActivity activity = (SettingsActivity) getActivity(); + final SwitchBar switchBar = activity.getSwitchBar(); + mSwitchBarController = new MultiUserSwitchBarController(activity, + new SwitchBarController(switchBar), this /* listener */); + getLifecycle().addObserver(mSwitchBarController); + switchBar.show(); + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.user_settings); final Activity activity = getActivity(); - if (!Utils.isDeviceProvisioned(getActivity())) { + if (!Utils.isDeviceProvisioned(activity)) { activity.finish(); return; } mAddUserWhenLockedPreferenceController = new AddUserWhenLockedPreferenceController( - activity, KEY_ADD_USER_WHEN_LOCKED, getLifecycle()); + activity, KEY_ADD_USER_WHEN_LOCKED); + mMultiUserFooterPreferenceController = new MultiUserFooterPreferenceController(activity) + .setFooterMixin(mFooterPreferenceMixin); + final PreferenceScreen screen = getPreferenceScreen(); mAddUserWhenLockedPreferenceController.displayPreference(screen); + mMultiUserFooterPreferenceController.displayPreference(screen); screen.findPreference(mAddUserWhenLockedPreferenceController.getPreferenceKey()) .setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController); @@ -246,7 +268,7 @@ public class UserSettings extends SettingsPreferenceFragment mAddUser = (RestrictedPreference) findPreference(KEY_ADD_USER); mAddUser.useAdminDisabledSummary(false); // Determine if add user/profile button should be visible - if (mUserCaps.mCanAddUser && Utils.isDeviceProvisioned(getActivity())) { + if (mUserCaps.mCanAddUser && Utils.isDeviceProvisioned(activity)) { mAddUser.setVisible(true); mAddUser.setOnPreferenceClickListener(this); // change label to only mention user, if restricted profiles are not supported @@ -260,8 +282,7 @@ public class UserSettings extends SettingsPreferenceFragment activity.registerReceiverAsUser( mUserChangeReceiver, UserHandle.ALL, USER_REMOVED_INTENT_FILTER, null, mHandler); - loadProfile(); - updateUserList(); + updateUI(); mShouldUpdateUserList = false; } @@ -280,9 +301,7 @@ public class UserSettings extends SettingsPreferenceFragment } if (mShouldUpdateUserList) { - mUserCaps.updateAddUserCapabilities(getActivity()); - loadProfile(); - updateUserList(); + updateUI(); } } @@ -343,6 +362,17 @@ public class UserSettings extends SettingsPreferenceFragment } } + @Override + public void onMultiUserSwitchChanged(boolean newState) { + updateUI(); + } + + private void updateUI() { + mUserCaps.updateAddUserCapabilities(getActivity()); + loadProfile(); + updateUserList(); + } + /** * Loads profile information for the current user. */ @@ -909,8 +939,6 @@ public class UserSettings extends SettingsPreferenceFragment loadIconsAsync(missingIcons); } - // Remove everything from mUserListCategory and add new users. - mUserListCategory.removeAll(); // If profiles are supported, mUserListCategory will have a special title if (mUserCaps.mCanAddRestrictedProfile) { mUserListCategory.setTitle(R.string.user_list_title); @@ -918,6 +946,20 @@ public class UserSettings extends SettingsPreferenceFragment mUserListCategory.setTitle(null); } + // Remove everything from mUserListCategory and add new users. + mUserListCategory.removeAll(); + + // If multi-user is disabled, just show footer and return. + final Preference addUserOnLockScreen = getPreferenceScreen().findPreference( + mAddUserWhenLockedPreferenceController.getPreferenceKey()); + mAddUserWhenLockedPreferenceController.updateState(addUserOnLockScreen); + mMultiUserFooterPreferenceController.updateState(null /* preference */); + mAddUser.setVisible(mUserCaps.mUserSwitcherEnabled); + mUserListCategory.setVisible(mUserCaps.mUserSwitcherEnabled); + if (!mUserCaps.mUserSwitcherEnabled) { + return; + } + for (UserPreference userPreference : userPreferences) { userPreference.setOrder(Preference.DEFAULT_ORDER); mUserListCategory.addPreference(userPreference); @@ -925,7 +967,7 @@ public class UserSettings extends SettingsPreferenceFragment // Append Add user to the end of the list if ((mUserCaps.mCanAddUser || mUserCaps.mDisallowAddUserSetByAdmin) && - Utils.isDeviceProvisioned(getActivity())) { + Utils.isDeviceProvisioned(context)) { boolean moreUsers = mUserManager.canAddMoreUsers(); mAddUser.setEnabled(moreUsers && !mAddingUser); if (!moreUsers) { @@ -938,7 +980,6 @@ public class UserSettings extends SettingsPreferenceFragment mUserCaps.mDisallowAddUser ? mUserCaps.mEnforcedAdmin : null); } } - } private int getMaxRealUsers() { @@ -1190,8 +1231,7 @@ public class UserSettings extends SettingsPreferenceFragment @Override public List getNonIndexableKeysFromXml(Context context, int xmlResId) { final List niks = super.getNonIndexableKeysFromXml(context, xmlResId); - new AddUserWhenLockedPreferenceController( - context, KEY_ADD_USER_WHEN_LOCKED, null /* lifecycle */) + new AddUserWhenLockedPreferenceController(context, KEY_ADD_USER_WHEN_LOCKED) .updateNonIndexableKeys(niks); new AutoSyncDataPreferenceController(context, null /* parent */) .updateNonIndexableKeys(niks); diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java index df87536d33b..753d15916b7 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java @@ -47,6 +47,8 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager private final Set mManagedProfiles = new HashSet<>(); private boolean mIsQuietModeEnabled = false; private int[] profileIdsForUser; + private boolean mUserSwitchEnabled; + @Resetter public void reset() { @@ -56,6 +58,7 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager mRestrictionSources.clear(); mManagedProfiles.clear(); mIsQuietModeEnabled = false; + mUserSwitchEnabled = false; } public void setUserInfo(int userHandle, UserInfo userInfo) { @@ -136,4 +139,13 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager public void setProfileIdsWithDisabled(int[] profileIds) { profileIdsForUser = profileIds; } + + @Implementation + public boolean isUserSwitcherEnabled() { + return mUserSwitchEnabled; + } + + public void setUserSwitcherEnabled(boolean userSwitchEnabled) { + mUserSwitchEnabled = userSwitchEnabled; + } } diff --git a/tests/robotests/src/com/android/settings/users/AddUserWhenLockedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/users/AddUserWhenLockedPreferenceControllerTest.java index 10b2acb9ed0..c2b1c9ff59e 100644 --- a/tests/robotests/src/com/android/settings/users/AddUserWhenLockedPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/users/AddUserWhenLockedPreferenceControllerTest.java @@ -17,58 +17,59 @@ package com.android.settings.users; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Answers.RETURNS_DEEP_STUBS; -import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import androidx.lifecycle.LifecycleOwner; import android.content.Context; import android.content.pm.UserInfo; -import android.os.UserManager; import android.provider.Settings.Global; -import androidx.preference.PreferenceScreen; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.RestrictedSwitchPreference; -import com.android.settingslib.core.lifecycle.Lifecycle; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplication; +import androidx.preference.PreferenceScreen; + @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = {ShadowUserManager.class}) public class AddUserWhenLockedPreferenceControllerTest { @Mock(answer = RETURNS_DEEP_STUBS) private PreferenceScreen mScreen; @Mock(answer = RETURNS_DEEP_STUBS) private UserInfo mUserInfo; - @Mock(answer = RETURNS_DEEP_STUBS) - private UserManager mUserManager; - private LifecycleOwner mLifecycleOwner; - private Lifecycle mLifecycle; private Context mContext; + private ShadowUserManager mUserManager; private AddUserWhenLockedPreferenceController mController; @Before public void setUp() { MockitoAnnotations.initMocks(this); ShadowApplication shadowContext = ShadowApplication.getInstance(); - shadowContext.setSystemService(Context.USER_SERVICE, mUserManager); + mUserManager = ShadowUserManager.getShadow(); mContext = shadowContext.getApplicationContext(); - mLifecycleOwner = () -> mLifecycle; - mLifecycle = new Lifecycle(mLifecycleOwner); - mController = new AddUserWhenLockedPreferenceController(mContext, "fake_key", mLifecycle); + mController = new AddUserWhenLockedPreferenceController(mContext, "fake_key"); + } + + @After + public void tearDown() { + mUserManager.reset(); } @Test public void displayPref_NotAdmin_shouldNotDisplay() { - when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo); + mUserManager.setUserInfo(0, mUserInfo); when(mUserInfo.isAdmin()).thenReturn(false); final RestrictedSwitchPreference preference = mock(RestrictedSwitchPreference.class); when(preference.getKey()).thenReturn(mController.getPreferenceKey()); diff --git a/tests/robotests/src/com/android/settings/users/MultiUserFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/users/MultiUserFooterPreferenceControllerTest.java new file mode 100644 index 00000000000..f74de7a5452 --- /dev/null +++ b/tests/robotests/src/com/android/settings/users/MultiUserFooterPreferenceControllerTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.users; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_FOR_USER; +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class MultiUserFooterPreferenceControllerTest { + + private Context mContext; + private MultiUserFooterPreferenceController mController; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mController = new MultiUserFooterPreferenceController(mContext); + } + + @Test + public void getAvailabilityStatus_multiUserOff_shouldReturnEnabled() { + mController.mUserCaps.mEnabled = true; + mController.mUserCaps.mUserSwitcherEnabled = false; + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); + } + + @Test + public void getAvailabilityStatus_multiUserOn_shouldReturnDisabled() { + mController.mUserCaps.mEnabled = true; + mController.mUserCaps.mUserSwitcherEnabled = true; + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_USER); + } +} diff --git a/tests/robotests/src/com/android/settings/users/UserCapabilitiesTest.java b/tests/robotests/src/com/android/settings/users/UserCapabilitiesTest.java index d85f2fa8732..c8d36857e57 100644 --- a/tests/robotests/src/com/android/settings/users/UserCapabilitiesTest.java +++ b/tests/robotests/src/com/android/settings/users/UserCapabilitiesTest.java @@ -17,36 +17,43 @@ package com.android.settings.users; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.when; import android.content.Context; +import android.os.UserHandle; import android.os.UserManager; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowUserManager; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = {ShadowUserManager.class}) public class UserCapabilitiesTest { - @Mock private Context mContext; - @Mock - private UserManager mUserManager; + private ShadowUserManager mUserManager; @Before public void setUp() { - MockitoAnnotations.initMocks(this); - when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + mContext = RuntimeEnvironment.application; + mUserManager = ShadowUserManager.getShadow(); + } + + @After + public void tearDown() { + mUserManager.reset(); } @Test - public void disallowUserSwitchWhenRestrictionIsSet() { - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(true); + public void disallowUserSwitch_restrictionIsSet_true() { + mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()), + UserManager.DISALLOW_USER_SWITCH, true); UserCapabilities userCapabilities = UserCapabilities.create(mContext); userCapabilities.updateAddUserCapabilities(mContext); @@ -55,12 +62,33 @@ public class UserCapabilitiesTest { } @Test - public void allowUserSwitchWhenRestrictionIsNotSet() { - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(false); + public void disallowUserSwitch_restrictionIsNotSet_false() { + mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()), + UserManager.DISALLOW_USER_SWITCH, false); UserCapabilities userCapabilities = UserCapabilities.create(mContext); userCapabilities.updateAddUserCapabilities(mContext); assertThat(userCapabilities.mDisallowSwitchUser).isFalse(); } + + @Test + public void userSwitchEnabled_off() { + mUserManager.setUserSwitcherEnabled(false); + + final UserCapabilities userCapabilities = UserCapabilities.create(mContext); + userCapabilities.updateAddUserCapabilities(mContext); + + assertThat(userCapabilities.mUserSwitcherEnabled).isFalse(); + } + + @Test + public void userSwitchEnabled_on() { + mUserManager.setUserSwitcherEnabled(true); + + final UserCapabilities userCapabilities = UserCapabilities.create(mContext); + userCapabilities.updateAddUserCapabilities(mContext); + + assertThat(userCapabilities.mUserSwitcherEnabled).isTrue(); + } } From c8f021a288f7a30093a6518b905d8bc9211e8988 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 11 Jun 2018 15:35:03 -0700 Subject: [PATCH 7/8] Suppress "see all" from settings search. Bug: 109894919 Test: reindex search Change-Id: I009c5d2f366af402dcbfd2eb75b56bfcbb9217a6 --- .../android/settings/location/LocationSettings.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java index 9f23396a127..638518c7eee 100644 --- a/src/com/android/settings/location/LocationSettings.java +++ b/src/com/android/settings/location/LocationSettings.java @@ -21,8 +21,7 @@ import android.content.Context; import android.location.SettingInjectorService; import android.os.Bundle; import android.provider.SearchIndexableResource; -import androidx.preference.Preference; -import androidx.preference.PreferenceGroup; + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsActivity; @@ -42,6 +41,9 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import androidx.preference.Preference; +import androidx.preference.PreferenceGroup; + /** * System location settings (Settings > Location). The screen has three parts: *
    @@ -177,5 +179,12 @@ public class LocationSettings extends DashboardFragment { return buildPreferenceControllers(context, null /* fragment */, null /* lifecycle */); } + + @Override + public List getNonIndexableKeys(Context context) { + final List niks = super.getNonIndexableKeys(context); + niks.add("recent_location_requests_see_all_button"); // 'See all' button + return niks; + } }; } From 670ce333ae4845901390a5068b5273097580b9aa Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 11 Jun 2018 16:00:09 -0700 Subject: [PATCH 8/8] Misc clean up. move widgets from graph to widget package. Bug: n/a Test: robotests, rebuild Change-Id: I910f355312d52e81a0bf57b46a3f267e1eb9882a --- res/layout/battery_history_detail.xml | 2 +- res/layout/battery_usage_graph.xml | 2 +- res/layout/data_usage_graph.xml | 2 +- res/layout/usage_view.xml | 6 +++--- .../datausage/ChartDataUsagePreference.java | 9 +++++---- .../fuelgauge/BatteryHistoryDetail.java | 5 +++-- .../fuelgauge/BatteryHistoryPreference.java | 10 ++++++---- .../android/settings/fuelgauge/BatteryInfo.java | 9 +++++---- .../{graph => widget}/BottomLabelLayout.java | 5 ++--- .../settings/{graph => widget}/UsageGraph.java | 16 +++++++++------- .../settings/{graph => widget}/UsageView.java | 17 ++++++++++------- .../datausage/ChartDataUsagePreferenceTest.java | 13 ++++++++----- .../fuelgauge/BatteryHistoryPreferenceTest.java | 7 ++++--- .../settings/fuelgauge/BatteryInfoTest.java | 6 +++--- .../BottomLabelLayoutTest.java | 5 ++--- .../{graph => widget}/UsageGraphTest.java | 5 ++--- 16 files changed, 65 insertions(+), 54 deletions(-) rename src/com/android/settings/{graph => widget}/BottomLabelLayout.java (98%) rename src/com/android/settings/{graph => widget}/UsageGraph.java (96%) rename src/com/android/settings/{graph => widget}/UsageView.java (92%) rename tests/robotests/src/com/android/settings/{graph => widget}/BottomLabelLayoutTest.java (98%) rename tests/robotests/src/com/android/settings/{graph => widget}/UsageGraphTest.java (99%) diff --git a/res/layout/battery_history_detail.xml b/res/layout/battery_history_detail.xml index ea758655231..ff838019682 100644 --- a/res/layout/battery_history_detail.xml +++ b/res/layout/battery_history_detail.xml @@ -49,7 +49,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="?android:attr/textColorSecondary"/> - - - - - - + diff --git a/src/com/android/settings/datausage/ChartDataUsagePreference.java b/src/com/android/settings/datausage/ChartDataUsagePreference.java index d02aa88944a..92d5cc80110 100644 --- a/src/com/android/settings/datausage/ChartDataUsagePreference.java +++ b/src/com/android/settings/datausage/ChartDataUsagePreference.java @@ -18,9 +18,6 @@ import android.content.Context; import android.net.NetworkPolicy; import android.net.NetworkStatsHistory; import android.net.TrafficStats; -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.format.Formatter; @@ -30,7 +27,11 @@ import android.util.SparseIntArray; import com.android.settings.R; import com.android.settings.Utils; -import com.android.settings.graph.UsageView; +import com.android.settings.widget.UsageView; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; public class ChartDataUsagePreference extends Preference { diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java b/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java index 3661467887b..1343fefca60 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java +++ b/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java @@ -25,12 +25,13 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.fuelgauge.BatteryActiveView.BatteryActiveProvider; -import com.android.settings.graph.UsageView; +import com.android.settings.widget.UsageView; public class BatteryHistoryDetail extends SettingsPreferenceFragment { public static final String EXTRA_STATS = "stats"; @@ -76,7 +77,7 @@ public class BatteryHistoryDetail extends SettingsPreferenceFragment { mPhoneParser = new BatteryCellParser(); setHasOptionsMenu(true); } - + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java index 6ef09570b6e..89b3eddb1b2 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java +++ b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java @@ -17,15 +17,17 @@ package com.android.settings.fuelgauge; import android.content.Context; -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; import android.util.AttributeSet; import android.view.View; import android.widget.TextView; + import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; -import com.android.settings.graph.UsageView; +import com.android.settings.widget.UsageView; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; /** * Custom preference for displaying power consumption as a bar and an icon on the left for the diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java index 9afaabad395..f642d30fd49 100644 --- a/src/com/android/settings/fuelgauge/BatteryInfo.java +++ b/src/com/android/settings/fuelgauge/BatteryInfo.java @@ -24,18 +24,19 @@ import android.os.BatteryStats; import android.os.BatteryStats.HistoryItem; import android.os.Bundle; import android.os.SystemClock; -import androidx.annotation.WorkerThread; import android.text.format.Formatter; import android.util.SparseIntArray; import com.android.internal.os.BatteryStatsHelper; import com.android.settings.Utils; -import com.android.settings.graph.UsageView; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.widget.UsageView; import com.android.settingslib.R; import com.android.settingslib.utils.PowerUtil; import com.android.settingslib.utils.StringUtil; +import androidx.annotation.WorkerThread; + public class BatteryInfo { public CharSequence chargeLabel; @@ -129,7 +130,7 @@ public class BatteryInfo { remaining = context.getString(R.string.remaining_length_format, Formatter.formatShortElapsedTime(context, remainingTimeUs / 1000)); } - view.setBottomLabels(new CharSequence[]{timeString, remaining}); + view.setBottomLabels(new CharSequence[] {timeString, remaining}); } public static void getBatteryInfo(final Context context, final Callback callback) { @@ -173,7 +174,7 @@ public class BatteryInfo { if (discharging && provider != null && provider.isEnhancedBatteryPredictionEnabled(context)) { Estimate estimate = provider.getEnhancedBatteryPrediction(context); - if(estimate != null) { + if (estimate != null) { BatteryUtils .logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime); return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, diff --git a/src/com/android/settings/graph/BottomLabelLayout.java b/src/com/android/settings/widget/BottomLabelLayout.java similarity index 98% rename from src/com/android/settings/graph/BottomLabelLayout.java rename to src/com/android/settings/widget/BottomLabelLayout.java index 20d97e5e4d0..dca528f94c0 100644 --- a/src/com/android/settings/graph/BottomLabelLayout.java +++ b/src/com/android/settings/widget/BottomLabelLayout.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2017 The Android Open Source Project + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -11,11 +12,9 @@ * 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.graph; +package com.android.settings.widget; import android.annotation.Nullable; import android.content.Context; diff --git a/src/com/android/settings/graph/UsageGraph.java b/src/com/android/settings/widget/UsageGraph.java similarity index 96% rename from src/com/android/settings/graph/UsageGraph.java rename to src/com/android/settings/widget/UsageGraph.java index b9d517d5e8d..da61607278f 100644 --- a/src/com/android/settings/graph/UsageGraph.java +++ b/src/com/android/settings/widget/UsageGraph.java @@ -1,18 +1,20 @@ /* * Copyright (C) 2016 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 + * 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. + * 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.graph; +package com.android.settings.widget; import android.annotation.Nullable; import android.content.Context; diff --git a/src/com/android/settings/graph/UsageView.java b/src/com/android/settings/widget/UsageView.java similarity index 92% rename from src/com/android/settings/graph/UsageView.java rename to src/com/android/settings/widget/UsageView.java index bcf04414cfe..54e75b39c14 100644 --- a/src/com/android/settings/graph/UsageView.java +++ b/src/com/android/settings/widget/UsageView.java @@ -1,18 +1,20 @@ /* * Copyright (C) 2016 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 + * 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. + * 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.graph; +package com.android.settings.widget; import android.content.Context; import android.content.res.TypedArray; @@ -24,6 +26,7 @@ import android.view.View; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; + import com.android.settingslib.R; public class UsageView extends FrameLayout { diff --git a/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java index 00d02a3d90b..e053e161a45 100644 --- a/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java +++ b/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java @@ -25,8 +25,10 @@ import android.content.Context; import android.net.NetworkStatsHistory; import android.net.NetworkStatsHistory.Entry; import android.util.SparseIntArray; -import com.android.settings.graph.UsageView; + import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.widget.UsageView; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -65,7 +67,7 @@ public class ChartDataUsagePreferenceTest { when(mNetworkStatsHistory.getIndexAfter(end)).thenReturn(7); final UsageView usageView = mock(UsageView.class); final ArgumentCaptor pointsCaptor = - ArgumentCaptor.forClass(SparseIntArray.class); + ArgumentCaptor.forClass(SparseIntArray.class); mPreference.calcPoints(usageView); @@ -84,7 +86,7 @@ public class ChartDataUsagePreferenceTest { when(mNetworkStatsHistory.getIndexAfter(end)).thenReturn(5); final UsageView usageView = mock(UsageView.class); final ArgumentCaptor pointsCaptor = - ArgumentCaptor.forClass(SparseIntArray.class); + ArgumentCaptor.forClass(SparseIntArray.class); mPreference.calcPoints(usageView); @@ -113,9 +115,10 @@ public class ChartDataUsagePreferenceTest { * Create a network entry to be used to calculate the usage chart. In the calculation, we only * need bucketStart, total bytes (rx + tx), and bucketDuration (which is set when we create * the NetworkStatsHistory object). Other fields are ignored, so we don't initialize here. + * * @param start the timestamp when this entry begins - * @param rx the total number of received bytes - * @param tx the total number of transmitted bytes + * @param rx the total number of received bytes + * @param tx the total number of transmitted bytes * @return the network entry with the corresponding start time and data usage */ private Entry createEntry(long start, long rx, long tx) { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java index 0da118abc79..d9e5bc0bc89 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java @@ -23,15 +23,14 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import androidx.preference.PreferenceViewHolder; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; import com.android.settings.R; -import com.android.settings.graph.UsageView; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; +import com.android.settings.widget.UsageView; import org.junit.Before; import org.junit.Test; @@ -41,6 +40,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import androidx.preference.PreferenceViewHolder; + @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = SettingsShadowResources.SettingsShadowTheme.class) public class BatteryHistoryPreferenceTest { @@ -63,7 +64,7 @@ public class BatteryHistoryPreferenceTest { MockitoAnnotations.initMocks(this); final Context context = RuntimeEnvironment.application; final View itemView = - LayoutInflater.from(context).inflate(R.layout.battery_usage_graph, null); + LayoutInflater.from(context).inflate(R.layout.battery_usage_graph, null); mBatteryHistoryPreference = new BatteryHistoryPreference(context, null); mBatteryHistoryPreference.mBatteryInfo = mBatteryInfo; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java index 99967f78370..44486f80d46 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java @@ -36,12 +36,11 @@ import android.os.BatteryStats; import android.os.SystemClock; import android.util.SparseIntArray; -import com.android.settings.graph.UsageView; import com.android.settings.testutils.BatteryTestUtils; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.widget.UsageView; import com.android.settingslib.R; -import com.android.settingslib.utils.PowerUtil; import org.junit.Before; import org.junit.Test; @@ -172,7 +171,8 @@ public class BatteryInfoTest { } @Test - public void testGetBatteryInfo_basedOnUsageTrueBetweenSevenAndFifteenMinutes_usesCorrectString() { + public void + testGetBatteryInfo_basedOnUsageTrueBetweenSevenAndFifteenMinutes_usesCorrectString() { Estimate estimate = new Estimate(Duration.ofMinutes(10).toMillis(), true /* isBasedOnUsage */, 1000 /* averageDischargeTime */); diff --git a/tests/robotests/src/com/android/settings/graph/BottomLabelLayoutTest.java b/tests/robotests/src/com/android/settings/widget/BottomLabelLayoutTest.java similarity index 98% rename from tests/robotests/src/com/android/settings/graph/BottomLabelLayoutTest.java rename to tests/robotests/src/com/android/settings/widget/BottomLabelLayoutTest.java index 6ba22d1b73d..ea0d89ad81f 100644 --- a/tests/robotests/src/com/android/settings/graph/BottomLabelLayoutTest.java +++ b/tests/robotests/src/com/android/settings/widget/BottomLabelLayoutTest.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2017 The Android Open Source Project + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -11,11 +12,9 @@ * 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.graph; +package com.android.settings.widget; import static com.google.common.truth.Truth.assertThat; diff --git a/tests/robotests/src/com/android/settings/graph/UsageGraphTest.java b/tests/robotests/src/com/android/settings/widget/UsageGraphTest.java similarity index 99% rename from tests/robotests/src/com/android/settings/graph/UsageGraphTest.java rename to tests/robotests/src/com/android/settings/widget/UsageGraphTest.java index 788d130d3d8..15658d5aca4 100644 --- a/tests/robotests/src/com/android/settings/graph/UsageGraphTest.java +++ b/tests/robotests/src/com/android/settings/widget/UsageGraphTest.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2017 The Android Open Source Project + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -11,11 +12,9 @@ * 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.graph; +package com.android.settings.widget; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn;