diff --git a/aconfig/settings_security_flag_declarations.aconfig b/aconfig/settings_security_flag_declarations.aconfig new file mode 100644 index 00000000000..42ef4d03e5b --- /dev/null +++ b/aconfig/settings_security_flag_declarations.aconfig @@ -0,0 +1,8 @@ +package: "com.android.settings.flags" + +flag { + name: "protect_lock_after_timeout_with_auth" + namespace: "safety_center" + description: "Require an auth challenge to open Lock after timeout page" + bug: "315937886" +} diff --git a/res/xml/app_ops_permissions_details.xml b/res/xml/app_ops_permissions_details.xml index eb8188bad6b..3cbe009fc06 100644 --- a/res/xml/app_ops_permissions_details.xml +++ b/res/xml/app_ops_permissions_details.xml @@ -17,7 +17,7 @@ - - { return new UserHandle(getUserIdFromDeviceAdminInfo(mInfo)); } + public int getUid() { + return mInfo.getActivityInfo().applicationInfo.uid; + } + + public String getPackageName() { + return mInfo.getPackageName(); + } + public Intent getLaunchIntent(Context context) { return new Intent(context, DeviceAdminAdd.class) .putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mInfo.getComponent()); diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java index 1184d8e41c5..55ba8acafad 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java @@ -18,6 +18,7 @@ package com.android.settings.applications.specialaccess.deviceadmin; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; +import android.Manifest; import android.app.AppGlobals; import android.app.admin.DeviceAdminInfo; import android.app.admin.DeviceAdminReceiver; @@ -45,12 +46,13 @@ import androidx.preference.PreferenceScreen; import com.android.settings.core.BasePreferenceController; import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; -import com.android.settingslib.widget.AppSwitchPreference; import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.TwoTargetPreference; import org.xmlpull.v1.XmlPullParserException; @@ -167,35 +169,35 @@ public class DeviceAdminListPreferenceController extends BasePreferenceControlle if (mFooterPreference != null) { mFooterPreference.setVisible(mAdmins.isEmpty()); } - final Map preferenceCache = new ArrayMap<>(); + final Map preferenceCache = new ArrayMap<>(); final Context prefContext = mPreferenceGroup.getContext(); final int childrenCount = mPreferenceGroup.getPreferenceCount(); for (int i = 0; i < childrenCount; i++) { final Preference pref = mPreferenceGroup.getPreference(i); - if (!(pref instanceof AppSwitchPreference)) { + if (!(pref instanceof RestrictedSwitchPreference switchPref)) { continue; } - final AppSwitchPreference appSwitch = (AppSwitchPreference) pref; - preferenceCache.put(appSwitch.getKey(), appSwitch); + preferenceCache.put(switchPref.getKey(), switchPref); } for (DeviceAdminListItem item : mAdmins) { final String key = item.getKey(); - AppSwitchPreference pref = preferenceCache.remove(key); + RestrictedSwitchPreference pref = preferenceCache.remove(key); if (pref == null) { - pref = new AppSwitchPreference(prefContext); + pref = new RestrictedSwitchPreference(prefContext); mPreferenceGroup.addPreference(pref); } bindPreference(item, pref); } - for (AppSwitchPreference unusedCacheItem : preferenceCache.values()) { + for (RestrictedSwitchPreference unusedCacheItem : preferenceCache.values()) { mPreferenceGroup.removePreference(unusedCacheItem); } } - private void bindPreference(DeviceAdminListItem item, AppSwitchPreference pref) { + private void bindPreference(DeviceAdminListItem item, RestrictedSwitchPreference pref) { pref.setKey(item.getKey()); pref.setTitle(item.getName()); pref.setIcon(item.getIcon()); + pref.setIconSize(TwoTargetPreference.ICON_SIZE_DEFAULT); pref.setChecked(item.isActive()); pref.setSummary(item.getDescription()); pref.setEnabled(item.isEnabled()); @@ -207,6 +209,8 @@ public class DeviceAdminListPreferenceController extends BasePreferenceControlle }); pref.setOnPreferenceChangeListener((preference, newValue) -> false); pref.setSingleLineTitle(true); + pref.checkEcmRestrictionAndSetDisabled(Manifest.permission.BIND_DEVICE_ADMIN, + item.getPackageName(), item.getUid()); } /** diff --git a/src/com/android/settings/datetime/TimeZonePreferenceController.java b/src/com/android/settings/datetime/TimeZonePreferenceController.java index 913640db16a..d45173f48cc 100644 --- a/src/com/android/settings/datetime/TimeZonePreferenceController.java +++ b/src/com/android/settings/datetime/TimeZonePreferenceController.java @@ -26,6 +26,7 @@ import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.RestrictedPreference; import com.android.settingslib.datetime.ZoneGetter; import java.util.Calendar; @@ -52,6 +53,12 @@ public class TimeZonePreferenceController extends BasePreferenceController { @Override public void updateState(Preference preference) { super.updateState(preference); + + if (preference instanceof RestrictedPreference + && ((RestrictedPreference) preference).isDisabledByAdmin()) { + return; + } + preference.setEnabled(shouldEnableManualTimeZoneSelection()); } diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java index abe640bcadb..05dc5bea33a 100644 --- a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java +++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java @@ -105,8 +105,13 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment public void onActivityCreated(final Bundle icicle) { super.onActivityCreated(icicle); Bundle arguments = getArguments(); + if (arguments == null) { + Log.e(TAG, "Arguments should not be null"); + return; + } mInputDeviceIdentifier = - arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER); + arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER, + InputDeviceIdentifier.class); if (mInputDeviceIdentifier == null) { Log.e(TAG, "The inputDeviceIdentifier should not be null"); return; @@ -128,6 +133,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment InputDevice inputDevice = NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier); if (inputDevice == null) { + Log.e(TAG, "Unable to start: input device is null"); getActivity().finish(); return; } diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java index 38de93ea2d2..7de505edbca 100644 --- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java @@ -151,7 +151,8 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment mKeyboardA11yCategory.removePreference(mAccessibilityStickyKeys); } InputDeviceIdentifier inputDeviceIdentifier = activity.getIntent().getParcelableExtra( - KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER); + KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER, + InputDeviceIdentifier.class); int intentFromWhere = activity.getIntent().getIntExtra(android.provider.Settings.EXTRA_ENTRYPOINT, -1); if (intentFromWhere != -1) { @@ -168,7 +169,8 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment } private static boolean isAutoSelection(Bundle bundle, InputDeviceIdentifier identifier) { - if (bundle != null && bundle.getParcelable(EXTRA_AUTO_SELECTION) != null) { + if (bundle != null && bundle.getParcelable(EXTRA_AUTO_SELECTION, + InputDeviceIdentifier.class) != null) { return false; } return identifier != null; @@ -446,7 +448,8 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment if (mIntentWaitingForResult != null) { InputDeviceIdentifier inputDeviceIdentifier = mIntentWaitingForResult - .getParcelableExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER); + .getParcelableExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER, + InputDeviceIdentifier.class); mIntentWaitingForResult = null; showKeyboardLayoutDialog(inputDeviceIdentifier); } diff --git a/src/com/android/settings/security/screenlock/ProtectedTimeoutListPreference.java b/src/com/android/settings/security/screenlock/ProtectedTimeoutListPreference.java new file mode 100644 index 00000000000..26d914c6fd4 --- /dev/null +++ b/src/com/android/settings/security/screenlock/ProtectedTimeoutListPreference.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 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.security.screenlock; + +import android.content.Context; +import android.util.AttributeSet; + +import com.android.settings.display.TimeoutListPreference; +import com.android.settings.flags.Flags; +import com.android.settings.wifi.dpp.WifiDppUtils; + +/** Wraps {@link TimeoutListPreference} with an authentication challenge for user. */ +public class ProtectedTimeoutListPreference extends TimeoutListPreference { + public ProtectedTimeoutListPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void performClick() { + if (Flags.protectLockAfterTimeoutWithAuth()) { + WifiDppUtils.showLockScreen(getContext(), super::performClick); + } else { + super.performClick(); + } + } +} diff --git a/src/com/android/settings/spa/app/appinfo/AppForceStopButton.kt b/src/com/android/settings/spa/app/appinfo/AppForceStopButton.kt index 345d931f9c0..c3183a7494f 100644 --- a/src/com/android/settings/spa/app/appinfo/AppForceStopButton.kt +++ b/src/com/android/settings/spa/app/appinfo/AppForceStopButton.kt @@ -19,6 +19,7 @@ package com.android.settings.spa.app.appinfo import android.app.settings.SettingsEnums import android.content.pm.ApplicationInfo import android.os.UserManager +import androidx.annotation.VisibleForTesting import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Report import androidx.compose.material3.Text @@ -87,9 +88,10 @@ class AppForceStopButton( dialogPresenter.open() } - private fun getAdminRestriction(app: ApplicationInfo): EnforcedAdmin? = when { + @VisibleForTesting + fun getAdminRestriction(app: ApplicationInfo): EnforcedAdmin? = when { packageManager.isPackageStateProtected(app.packageName, app.userId) -> { - RestrictedLockUtilsInternal.getDeviceOwner(context) + RestrictedLockUtilsInternal.getDeviceOwner(context) ?: EnforcedAdmin() } else -> RestrictedLockUtilsInternal.checkIfRestrictionEnforced( diff --git a/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java index 6bf83c6126a..cf12e341337 100644 --- a/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java @@ -23,9 +23,13 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_ import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import android.app.settings.SettingsEnums; import android.content.Context; import android.content.res.Resources; import android.os.vibrator.Flags; @@ -37,6 +41,7 @@ import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; +import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; import org.junit.Rule; @@ -49,7 +54,6 @@ import org.robolectric.RobolectricTestRunner; /** Tests for {@link KeyboardVibrationTogglePreferenceController}. */ @RunWith(RobolectricTestRunner.class) public class KeyboardVibrationTogglePreferenceControllerTest { - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -59,8 +63,8 @@ public class KeyboardVibrationTogglePreferenceControllerTest { private Context mContext; private Resources mResources; private KeyboardVibrationTogglePreferenceController mController; - private SwitchPreference mPreference; + private FakeFeatureFactory mFeatureFactory; @Before public void setUp() { @@ -68,6 +72,7 @@ public class KeyboardVibrationTogglePreferenceControllerTest { mContext = spy(ApplicationProvider.getApplicationContext()); mResources = spy(mContext.getResources()); when(mContext.getResources()).thenReturn(mResources); + mFeatureFactory = FakeFeatureFactory.setupForTest(); mController = new KeyboardVibrationTogglePreferenceController(mContext, "preferenceKey"); mPreference = new SwitchPreference(mContext); when(mPreferenceScreen.findPreference( @@ -148,6 +153,8 @@ public class KeyboardVibrationTogglePreferenceControllerTest { mController.setChecked(true); assertThat(readSystemSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED)).isEqualTo(ON); + verify(mFeatureFactory.metricsFeatureProvider).action(any(), + eq(SettingsEnums.ACTION_KEYBOARD_VIBRATION_CHANGED), eq(true)); } @Test @@ -160,6 +167,8 @@ public class KeyboardVibrationTogglePreferenceControllerTest { mController.setChecked(false); assertThat(readSystemSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED)).isEqualTo(OFF); + verify(mFeatureFactory.metricsFeatureProvider).action(any(), + eq(SettingsEnums.ACTION_KEYBOARD_VIBRATION_CHANGED), eq(false)); } private void updateSystemSetting(String key, int value) { diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragmentTest.java index 42e5ef60cdf..31741012d47 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragmentTest.java @@ -19,8 +19,10 @@ package com.android.settings.accessibility; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; @@ -32,6 +34,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; +import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -45,7 +48,9 @@ import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; +import com.android.settings.SettingsActivity; import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType; +import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment; import com.android.settings.widget.SettingsMainSwitchPreference; import org.junit.Before; @@ -53,6 +58,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; @@ -298,7 +304,9 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { @Test @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) - public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning() + @RequiresFlagsDisabled( + com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN) + public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_showDialog() throws Throwable { setupServiceWarningRequired(false); mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null); @@ -309,6 +317,23 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { AccessibilityDialogUtils.DialogEnums.EDIT_SHORTCUT); } + @Test + @RequiresFlagsEnabled({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, + com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN}) + public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_launchActivity() + throws Throwable { + setupServiceWarningRequired(false); + mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null); + doNothing().when(mContext).startActivity(any()); + + mFragment.onSettingsClicked(mFragment.mShortcutPreference); + + ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class); + verify(mContext).startActivity(captor.capture()); + assertThat(captor.getValue().getExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) + .isEqualTo(EditShortcutsPreferenceFragment.class.getName()); + } + private void setupTileService(String packageName, String name, String tileName) { final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE); final ResolveInfo info = new ResolveInfo(); diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/VrListenerScreenPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/VrListenerScreenPreferenceControllerTest.java index 1e5e235e1cf..7405980ffda 100644 --- a/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/VrListenerScreenPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/VrListenerScreenPreferenceControllerTest.java @@ -23,15 +23,15 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import com.android.settings.testutils.shadow.ShadowActivityManager; +import androidx.test.core.app.ApplicationProvider; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowActivityManager; @RunWith(RobolectricTestRunner.class) @Config(shadows = { @@ -45,7 +45,7 @@ public class VrListenerScreenPreferenceControllerTest { @Before public void setUp() { - mContext = RuntimeEnvironment.application; + mContext = ApplicationProvider.getApplicationContext(); mController = new VrListenerScreenPreferenceController(mContext, "key"); mActivityManager = Shadow.extract(mContext.getSystemService(Context.ACTIVITY_SERVICE)); } diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessControllerTest.java index bf112a6c255..badc5dbb0bd 100644 --- a/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessControllerTest.java @@ -25,23 +25,20 @@ import static org.mockito.Mockito.verify; import android.app.NotificationManager; import android.content.Context; +import androidx.test.core.app.ApplicationProvider; + import com.android.internal.logging.nano.MetricsProto; import com.android.settings.testutils.FakeFeatureFactory; -import com.android.settings.testutils.shadow.ShadowActivityManager; import com.android.settings.testutils.shadow.ShadowNotificationManager; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; @RunWith(RobolectricTestRunner.class) -@Config(shadows = { - ShadowActivityManager.class, -}) public class ZenAccessControllerTest { private static final String TEST_PKG = "com.test.package"; @@ -49,15 +46,12 @@ public class ZenAccessControllerTest { private FakeFeatureFactory mFeatureFactory; private Context mContext; private ZenAccessController mController; - private ShadowActivityManager mActivityManager; - @Before public void setUp() { - mContext = RuntimeEnvironment.application; + mContext = ApplicationProvider.getApplicationContext(); mFeatureFactory = FakeFeatureFactory.setupForTest(); mController = new ZenAccessController(mContext, "key"); - mActivityManager = Shadow.extract(mContext.getSystemService(Context.ACTIVITY_SERVICE)); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java index c6a9a718d69..583db5e1d50 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java @@ -46,6 +46,7 @@ import android.os.UserHandle; import androidx.fragment.app.FragmentActivity; import androidx.loader.app.LoaderManager; +import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.SettingsActivity; @@ -53,7 +54,6 @@ import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry; import com.android.settings.fuelgauge.batteryusage.BatteryEntry; import com.android.settings.fuelgauge.batteryusage.ConvertUtils; import com.android.settings.testutils.FakeFeatureFactory; -import com.android.settings.testutils.shadow.ShadowActivityManager; import com.android.settings.testutils.shadow.ShadowEntityHeaderController; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.PrimarySwitchPreference; @@ -65,15 +65,16 @@ import com.android.settingslib.widget.LayoutPreference; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; @@ -83,10 +84,13 @@ import java.util.concurrent.TimeUnit; @Config( shadows = { ShadowEntityHeaderController.class, - ShadowActivityManager.class, com.android.settings.testutils.shadow.ShadowFragment.class, }) public class AdvancedPowerUsageDetailTest { + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + private static final String APP_LABEL = "app label"; private static final String SUMMARY = "summary"; private static final String[] PACKAGE_NAME = {"com.android.app"}; @@ -125,9 +129,7 @@ public class AdvancedPowerUsageDetailTest { @Before public void setUp() { - MockitoAnnotations.initMocks(this); - - mContext = spy(RuntimeEnvironment.application); + mContext = spy(ApplicationProvider.getApplicationContext()); when(mContext.getPackageName()).thenReturn("foo"); mFeatureFactory = FakeFeatureFactory.setupForTest(); mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java index 6edbafacf9a..b6caa7f2061 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java @@ -47,11 +47,11 @@ import android.widget.CompoundButton; import androidx.fragment.app.FragmentActivity; import androidx.loader.app.LoaderManager; +import androidx.test.core.app.ApplicationProvider; import com.android.settings.SettingsActivity; import com.android.settings.fuelgauge.batteryusage.BatteryEntry; import com.android.settings.testutils.FakeFeatureFactory; -import com.android.settings.testutils.shadow.ShadowActivityManager; import com.android.settings.testutils.shadow.ShadowEntityHeaderController; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.applications.AppUtils; @@ -65,15 +65,16 @@ import com.android.settingslib.widget.SelectorWithWidgetPreference; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; @@ -83,10 +84,13 @@ import java.util.concurrent.TimeUnit; @Config( shadows = { ShadowEntityHeaderController.class, - ShadowActivityManager.class, com.android.settings.testutils.shadow.ShadowFragment.class, }) public class PowerBackgroundUsageDetailTest { + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + private static final String APP_LABEL = "app label"; private static final String SUMMARY = "summary"; private static final int ICON_ID = 123; @@ -123,9 +127,7 @@ public class PowerBackgroundUsageDetailTest { @Before public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - - mContext = spy(RuntimeEnvironment.application); + mContext = spy(ApplicationProvider.getApplicationContext()); when(mContext.getPackageName()).thenReturn("foo"); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo); diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java index 27a85fd3d4e..6cd4f167692 100644 --- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java +++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java @@ -45,29 +45,30 @@ import android.view.WindowManager; import android.widget.FrameLayout; import androidx.fragment.app.Fragment; +import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl; import com.android.settings.testutils.shadow.ShadowActivityEmbeddingUtils; -import com.android.settings.testutils.shadow.ShadowActivityManager; import com.android.settings.testutils.shadow.ShadowPasswordUtils; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; import org.junit.After; -import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowActivityManager; import org.robolectric.util.ReflectionHelpers; @RunWith(RobolectricTestRunner.class) @@ -77,11 +78,8 @@ import org.robolectric.util.ReflectionHelpers; ShadowActivityManager.class, }) public class SettingsHomepageActivityTest { - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - } + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @After public void tearDown() { @@ -120,7 +118,8 @@ public class SettingsHomepageActivityTest { @Config(qualifiers = "mcc999") public void launch_LowRamDevice_shouldHideAvatar() { final ShadowActivityManager activityManager = Shadow.extract( - RuntimeEnvironment.application.getSystemService(ActivityManager.class)); + ApplicationProvider.getApplicationContext().getSystemService( + ActivityManager.class)); activityManager.setIsLowRamDevice(true); final SettingsHomepageActivity activity = Robolectric.buildActivity( diff --git a/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java index b2759767112..ea0b2a06d2f 100644 --- a/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java @@ -34,21 +34,23 @@ import android.provider.Settings; import android.widget.Switch; import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; -import com.android.settings.testutils.shadow.ShadowActivityManager; import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor; import com.android.settingslib.widget.MainSwitchPreference; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowActivityManager; @RunWith(RobolectricTestRunner.class) @Config(shadows = { @@ -56,7 +58,10 @@ import org.robolectric.shadow.api.Shadow; ShadowActivityManager.class, }) public class BubbleNotificationPreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + private static final String KEY_NOTIFICATION_BUBBLES = "notification_bubbles"; private Context mContext; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private PreferenceScreen mScreen; @@ -67,33 +72,29 @@ public class BubbleNotificationPreferenceControllerTest { private BubbleNotificationPreferenceController mController; private MainSwitchPreference mPreference; - private static final String KEY_NOTIFICATION_BUBBLES = "notification_bubbles"; + private ShadowActivityManager mActivityManager; @Before public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = ApplicationProvider.getApplicationContext(); mController = new BubbleNotificationPreferenceController(mContext, KEY_NOTIFICATION_BUBBLES); - mPreference = new MainSwitchPreference(RuntimeEnvironment.application); + mPreference = new MainSwitchPreference(mContext); mPreference.setKey(mController.getPreferenceKey()); when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference); mController.displayPreference(mScreen); + mActivityManager = Shadow.extract(mContext.getSystemService(ActivityManager.class)); } @Test public void isAvailable_lowRam_returnsUnsupported() { - final ShadowActivityManager activityManager = - Shadow.extract(mContext.getSystemService(ActivityManager.class)); - activityManager.setIsLowRamDevice(true); + mActivityManager.setIsLowRamDevice(true); assertEquals(UNSUPPORTED_ON_DEVICE, mController.getAvailabilityStatus()); } @Test public void isAvailable_notLowRam_returnsAvailable() { - final ShadowActivityManager activityManager = - Shadow.extract(mContext.getSystemService(ActivityManager.class)); - activityManager.setIsLowRamDevice(false); + mActivityManager.setIsLowRamDevice(false); assertEquals(AVAILABLE, mController.getAvailabilityStatus()); } diff --git a/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java index e80fbc839d4..a201fdb4cb9 100644 --- a/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java @@ -30,17 +30,17 @@ import android.content.Context; import android.provider.Settings; import androidx.preference.Preference; +import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; -import com.android.settings.testutils.shadow.ShadowActivityManager; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowActivityManager; @RunWith(RobolectricTestRunner.class) @Config(shadows = { @@ -48,19 +48,23 @@ import org.robolectric.shadow.api.Shadow; }) public class BubbleSummaryNotificationPreferenceControllerTest { + private static final String KEY_NOTIFICATION_BUBBLES = "notification_bubbles"; private Context mContext; private BubbleSummaryNotificationPreferenceController mController; private Preference mPreference; - private static final String KEY_NOTIFICATION_BUBBLES = "notification_bubbles"; + private ShadowActivityManager mActivityManager; + @Before public void setUp() { - mContext = RuntimeEnvironment.application; + mContext = ApplicationProvider.getApplicationContext(); mController = new BubbleSummaryNotificationPreferenceController(mContext, KEY_NOTIFICATION_BUBBLES); - mPreference = new Preference(RuntimeEnvironment.application); + mPreference = new Preference(mContext); + mActivityManager = + Shadow.extract(mContext.getSystemService(ActivityManager.class)); } @Test @@ -80,17 +84,13 @@ public class BubbleSummaryNotificationPreferenceControllerTest { @Test public void isAvailable_lowRam_returnsUnsupported() { - final ShadowActivityManager activityManager = - Shadow.extract(mContext.getSystemService(ActivityManager.class)); - activityManager.setIsLowRamDevice(true); + mActivityManager.setIsLowRamDevice(true); assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } @Test public void isAvailable_notLowRam_returnsAvailable() { - final ShadowActivityManager activityManager = - Shadow.extract(mContext.getSystemService(ActivityManager.class)); - activityManager.setIsLowRamDevice(false); + mActivityManager.setIsLowRamDevice(false); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } } diff --git a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java index 487ba769972..893695cb2e4 100644 --- a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java @@ -55,24 +55,26 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; import com.android.settings.notification.NotificationBackend; -import com.android.settings.testutils.shadow.ShadowActivityManager; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedSwitchPreference; import com.google.common.collect.ImmutableList; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowActivityManager; import org.robolectric.shadows.ShadowApplication; import java.util.ArrayList; @@ -83,6 +85,8 @@ import java.util.List; ShadowActivityManager.class, }) public class BubblePreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private Context mContext; @Mock @@ -103,11 +107,10 @@ public class BubblePreferenceControllerTest { @Before public void setUp() { - MockitoAnnotations.initMocks(this); ShadowApplication shadowApplication = ShadowApplication.getInstance(); shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm); shadowApplication.setSystemService(Context.USER_SERVICE, mUm); - mContext = RuntimeEnvironment.application; + mContext = ApplicationProvider.getApplicationContext(); when(mFragmentManager.beginTransaction()).thenReturn(mock(FragmentTransaction.class)); mController = spy(new BubblePreferenceController(mContext, mFragmentManager, mBackend, false /* isAppPage */, mListener)); diff --git a/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java index 7db308e173e..6fbe40e22e0 100644 --- a/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java @@ -43,27 +43,30 @@ import android.content.Context; import android.provider.Settings; import androidx.preference.Preference; +import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.notification.NotificationBackend; -import com.android.settings.testutils.shadow.ShadowActivityManager; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -import org.robolectric.shadows.ShadowApplication; +import org.robolectric.shadows.ShadowActivityManager; @RunWith(RobolectricTestRunner.class) @Config(shadows = { ShadowActivityManager.class, }) public class BubbleSummaryPreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private Context mContext; @Mock @@ -72,16 +75,17 @@ public class BubbleSummaryPreferenceControllerTest { private BubbleSummaryPreferenceController mController; + private ShadowActivityManager mActivityManager; + @Before public void setUp() { - MockitoAnnotations.initMocks(this); - ShadowApplication shadowApplication = ShadowApplication.getInstance(); - mContext = RuntimeEnvironment.application; + mContext = ApplicationProvider.getApplicationContext(); when(mBackend.hasSentValidBubble(anyString(), anyInt())).thenReturn(true); mAppRow = new NotificationBackend.AppRow(); mAppRow.pkg = "pkg"; mAppRow.uid = 0; mController = spy(new BubbleSummaryPreferenceController(mContext, mBackend)); + mActivityManager = Shadow.extract(mContext.getSystemService(ActivityManager.class)); } @Test @@ -151,9 +155,7 @@ public class BubbleSummaryPreferenceControllerTest { Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); mController.onResume(mAppRow, null, null, null, null, null, null); - final ShadowActivityManager activityManager = - Shadow.extract(mContext.getSystemService(ActivityManager.class)); - activityManager.setIsLowRamDevice(true); + mActivityManager.setIsLowRamDevice(true); assertFalse(mController.isAvailable()); } @@ -162,9 +164,7 @@ public class BubbleSummaryPreferenceControllerTest { Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); mController.onResume(mAppRow, null, null, null, null, null, null); - final ShadowActivityManager activityManager = - Shadow.extract(mContext.getSystemService(ActivityManager.class)); - activityManager.setIsLowRamDevice(false); + mActivityManager.setIsLowRamDevice(false); assertTrue(mController.isAvailable()); } diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppForceStopButtonTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppForceStopButtonTest.kt index c093863bcb1..84d6651c396 100644 --- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppForceStopButtonTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppForceStopButtonTest.kt @@ -17,79 +17,82 @@ package com.android.settings.spa.app.appinfo import android.app.admin.DevicePolicyManager +import android.content.ComponentName import android.content.Context import android.content.pm.ApplicationInfo import android.content.pm.PackageManager +import android.os.UserHandle +import android.os.UserManager +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.ui.test.assertIsEnabled +import androidx.compose.ui.test.assertIsNotEnabled import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.android.settingslib.spa.widget.button.ActionButton +import com.android.settings.R +import com.android.settingslib.spa.testutils.delay import com.android.settingslib.spaprivileged.framework.common.devicePolicyManager import com.android.settingslib.spaprivileged.model.app.userId import com.google.common.truth.Truth.assertThat -import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.MockitoJUnit -import org.mockito.junit.MockitoRule -import org.mockito.Mockito.`when` as whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.stub @RunWith(AndroidJUnit4::class) class AppForceStopButtonTest { @get:Rule val composeTestRule = createComposeRule() - @get:Rule - val mockito: MockitoRule = MockitoJUnit.rule() + private val mockPackageManager = mock() - @Spy - private val context: Context = ApplicationProvider.getApplicationContext() + private val mockDevicePolicyManager = mock() - @Mock - private lateinit var packageInfoPresenter: PackageInfoPresenter - - @Mock - private lateinit var packageManager: PackageManager - - @Mock - private lateinit var devicePolicyManager: DevicePolicyManager - - private lateinit var appForceStopButton: AppForceStopButton - - @Before - fun setUp() { - whenever(packageInfoPresenter.context).thenReturn(context) - whenever(context.packageManager).thenReturn(packageManager) - whenever(context.devicePolicyManager).thenReturn(devicePolicyManager) - appForceStopButton = AppForceStopButton(packageInfoPresenter) + private val mockUserManager = mock { + on { getUserRestrictionSources(any(), any()) } doReturn emptyList() } - @Test - fun getActionButton() { + private val context: Context = spy(ApplicationProvider.getApplicationContext()) { + on { packageManager } doReturn mockPackageManager + on { devicePolicyManager } doReturn mockDevicePolicyManager + on { getSystemService(Context.DEVICE_POLICY_SERVICE) } doReturn mockDevicePolicyManager + on { getSystemService(Context.USER_SERVICE) } doReturn mockUserManager } + private val packageInfoPresenter = mock { + on { context } doReturn context + } + + private val appForceStopButton = AppForceStopButton(packageInfoPresenter) + @Test fun getActionButton_isActiveAdmin_buttonDisabled() { val app = createApp() - whenever(devicePolicyManager.packageHasActiveAdmins(PACKAGE_NAME, app.userId)) - .thenReturn(true) + mockDevicePolicyManager.stub { + on { packageHasActiveAdmins(PACKAGE_NAME, app.userId) } doReturn true + } - val actionButton = setForceStopButton(app) + setForceStopButton(app) - assertThat(actionButton.enabled).isFalse() + composeTestRule.onNodeWithText(context.getString(R.string.force_stop)).assertIsNotEnabled() } @Test fun getActionButton_isUninstallInQueue_buttonDisabled() { val app = createApp() - whenever(devicePolicyManager.isUninstallInQueue(PACKAGE_NAME)).thenReturn(true) + mockDevicePolicyManager.stub { + on { isUninstallInQueue(PACKAGE_NAME) } doReturn true + } - val actionButton = setForceStopButton(app) + setForceStopButton(app) - assertThat(actionButton.enabled).isFalse() + composeTestRule.onNodeWithText(context.getString(R.string.force_stop)).assertIsNotEnabled() } @Test @@ -98,35 +101,79 @@ class AppForceStopButtonTest { flags = ApplicationInfo.FLAG_STOPPED } - val actionButton = setForceStopButton(app) + setForceStopButton(app) - assertThat(actionButton.enabled).isFalse() + composeTestRule.onNodeWithText(context.getString(R.string.force_stop)).assertIsNotEnabled() } @Test fun getActionButton_regularApp_buttonEnabled() { val app = createApp() - val actionButton = setForceStopButton(app) + setForceStopButton(app) - assertThat(actionButton.enabled).isTrue() + composeTestRule.onNodeWithText(context.getString(R.string.force_stop)).assertIsEnabled() } - private fun setForceStopButton(app: ApplicationInfo): ActionButton { - lateinit var actionButton: ActionButton - composeTestRule.setContent { - actionButton = appForceStopButton.getActionButton(app) + @Test + fun getAdminRestriction_packageNotProtected() { + mockPackageManager.stub { + on { isPackageStateProtected(PACKAGE_NAME, UserHandle.getUserId(UID)) } doReturn false } - return actionButton + + val admin = appForceStopButton.getAdminRestriction(createApp()) + + assertThat(admin).isNull() + } + + @Test + fun getAdminRestriction_packageProtectedAndHaveOwner() { + mockPackageManager.stub { + on { isPackageStateProtected(PACKAGE_NAME, UserHandle.getUserId(UID)) } doReturn true + } + mockDevicePolicyManager.stub { + on { deviceOwnerComponentOnAnyUser } doReturn DEVICE_OWNER + } + + val admin = appForceStopButton.getAdminRestriction(createApp())!! + + assertThat(admin.component).isEqualTo(DEVICE_OWNER) + } + + @Test + fun getAdminRestriction_packageProtectedAndNotHaveOwner() { + mockPackageManager.stub { + on { isPackageStateProtected(PACKAGE_NAME, UserHandle.getUserId(UID)) } doReturn true + } + mockDevicePolicyManager.stub { + on { deviceOwnerComponentOnAnyUser } doReturn null + } + + val admin = appForceStopButton.getAdminRestriction(createApp())!! + + assertThat(admin.component).isNull() + } + + private fun setForceStopButton(app: ApplicationInfo) { + composeTestRule.setContent { + val actionButton = appForceStopButton.getActionButton(app) + Button(onClick = {}, enabled = actionButton.enabled) { + Text(actionButton.text) + } + } + composeTestRule.delay() } private fun createApp(builder: ApplicationInfo.() -> Unit = {}) = ApplicationInfo().apply { packageName = PACKAGE_NAME + uid = UID enabled = true }.apply(builder) private companion object { const val PACKAGE_NAME = "package.name" + const val UID = 10000 + val DEVICE_OWNER = ComponentName("device", "Owner") } -} \ No newline at end of file +}