Loading src/com/android/settings/applications/AppStateAlarmsAndRemindersBridge.java +52 −27 Original line number Diff line number Diff line Loading @@ -18,11 +18,11 @@ package com.android.settings.applications; import android.Manifest; import android.app.AlarmManager; import android.app.AppGlobals; import android.app.compat.CompatChanges; import android.content.Context; import android.content.pm.IPackageManager; import android.os.RemoteException; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.PowerExemptionManager; import android.os.UserHandle; import android.util.Log; Loading @@ -32,8 +32,6 @@ import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; import libcore.util.EmptyArray; import java.util.List; /** Loading @@ -42,26 +40,24 @@ import java.util.List; * Also provides app filters that can use the info. */ public class AppStateAlarmsAndRemindersBridge extends AppStateBaseBridge { private static final String PERMISSION = Manifest.permission.SCHEDULE_EXACT_ALARM; private static final String SEA_PERMISSION = Manifest.permission.SCHEDULE_EXACT_ALARM; private static final String UEA_PERMISSION = Manifest.permission.USE_EXACT_ALARM; private static final String TAG = "AlarmsAndRemindersBridge"; @VisibleForTesting AlarmManager mAlarmManager; @VisibleForTesting String[] mRequesterPackages; PowerExemptionManager mPowerExemptionManager; @VisibleForTesting PackageManager mPackageManager; public AppStateAlarmsAndRemindersBridge(Context context, ApplicationsState appState, Callback callback) { super(appState, callback); mPowerExemptionManager = context.getSystemService(PowerExemptionManager.class); mAlarmManager = context.getSystemService(AlarmManager.class); final IPackageManager iPm = AppGlobals.getPackageManager(); try { mRequesterPackages = iPm.getAppOpPermissionPackages(PERMISSION, context.getUserId()); } catch (RemoteException re) { Log.e(TAG, "Cannot reach package manager", re); mRequesterPackages = EmptyArray.STRING; } mPackageManager = context.getPackageManager(); } private boolean isChangeEnabled(String packageName, int userId) { Loading @@ -69,6 +65,22 @@ public class AppStateAlarmsAndRemindersBridge extends AppStateBaseBridge { packageName, UserHandle.of(userId)); } private boolean isUeaChangeEnabled(String packageName, int userId) { return CompatChanges.isChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, packageName, UserHandle.of(userId)); } private String[] getRequestedPermissions(String packageName, int userId) { try { final PackageInfo info = mPackageManager.getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId); return info.requestedPermissions; } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Could not find package " + packageName, e); } return null; } /** * Returns information regarding {@link Manifest.permission#SCHEDULE_EXACT_ALARM} for the given * package and uid. Loading @@ -76,10 +88,17 @@ public class AppStateAlarmsAndRemindersBridge extends AppStateBaseBridge { public AlarmsAndRemindersState createPermissionState(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); final boolean permissionRequested = ArrayUtils.contains(mRequesterPackages, packageName) final String[] requestedPermissions = getRequestedPermissions(packageName, userId); final boolean seaRequested = ArrayUtils.contains(requestedPermissions, SEA_PERMISSION) && isChangeEnabled(packageName, userId); final boolean permissionGranted = mAlarmManager.hasScheduleExactAlarm(packageName, userId); return new AlarmsAndRemindersState(permissionRequested, permissionGranted); final boolean ueaRequested = ArrayUtils.contains(requestedPermissions, UEA_PERMISSION) && isUeaChangeEnabled(packageName, userId); final boolean seaGranted = mAlarmManager.hasScheduleExactAlarm(packageName, userId); final boolean allowListed = mPowerExemptionManager.isAllowListed(packageName, true); return new AlarmsAndRemindersState(seaRequested, ueaRequested, seaGranted, allowListed); } @Override Loading Loading @@ -113,26 +132,32 @@ public class AppStateAlarmsAndRemindersBridge extends AppStateBaseBridge { }; /** * Class to denote the state of an app regarding * {@link Manifest.permission#SCHEDULE_EXACT_ALARM}. * Class to denote the state of an app regarding "Alarms and Reminders" permission. * This permission state is a combination of {@link Manifest.permission#SCHEDULE_EXACT_ALARM}, * {@link Manifest.permission#USE_EXACT_ALARM} and the power allowlist state. */ public static class AlarmsAndRemindersState { private boolean mPermissionRequested; private boolean mPermissionGranted; AlarmsAndRemindersState(boolean permissionRequested, boolean permissionGranted) { mPermissionRequested = permissionRequested; mPermissionGranted = permissionGranted; private boolean mSeaPermissionRequested; private boolean mUeaPermissionRequested; private boolean mSeaPermissionGranted; private boolean mAllowListed; AlarmsAndRemindersState(boolean seaPermissionRequested, boolean ueaPermissionRequested, boolean seaPermissionGranted, boolean allowListed) { mSeaPermissionRequested = seaPermissionRequested; mUeaPermissionRequested = ueaPermissionRequested; mSeaPermissionGranted = seaPermissionGranted; mAllowListed = allowListed; } /** Should the app associated with this state appear on the Settings screen */ public boolean shouldBeVisible() { return mPermissionRequested; return mSeaPermissionRequested && !mUeaPermissionRequested && !mAllowListed; } /** Is the permission granted to the app associated with this state */ public boolean isAllowed() { return mPermissionGranted; return mSeaPermissionGranted || mUeaPermissionRequested || mAllowListed; } } } tests/unit/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridgeTest.java +169 −55 Original line number Diff line number Diff line Loading @@ -16,15 +16,24 @@ package com.android.settings.applications; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import android.Manifest; import android.app.AlarmManager; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.PowerExemptionManager; import android.os.UserHandle; import androidx.test.ext.junit.runners.AndroidJUnit4; import libcore.util.EmptyArray; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -34,13 +43,15 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class AppStateAlarmsAndRemindersBridgeTest { private static final String TEST_PACKAGE_1 = "com.example.test.1"; private static final String TEST_PACKAGE_2 = "com.example.test.2"; private static final int UID_1 = 12345; private static final int UID_2 = 7654321; private static final String TEST_PACKAGE = "com.example.test.1"; private static final int TEST_UID = 12345; @Mock private AlarmManager mAlarmManager; @Mock private PowerExemptionManager mPowerExemptionManager; @Mock private PackageManager mPackageManager; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; Loading @@ -50,65 +61,168 @@ public class AppStateAlarmsAndRemindersBridgeTest { } @Test public void shouldBeVisible_permissionRequestedIsTrue_isTrue() { assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( true /* permissionRequested */, true /* permissionGranted */) .shouldBeVisible()).isTrue(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( true /* permissionRequested */, false /* permissionGranted */) .shouldBeVisible()).isTrue(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( false /* permissionRequested */, true /* permissionGranted */) .shouldBeVisible()).isFalse(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( false /* permissionRequested */, false /* permissionGranted */) .shouldBeVisible()).isFalse(); public void alarmsAndRemindersState_shouldBeVisible() { boolean seaPermissionRequested; boolean ueaPermissionRequested; boolean seaPermissionGranted; boolean allowListed; for (int i = 0; i < (1 << 4); i++) { seaPermissionRequested = (i & 1) != 0; ueaPermissionRequested = (i & (1 << 1)) != 0; seaPermissionGranted = (i & (1 << 2)) != 0; allowListed = (i & (1 << 3)) != 0; final boolean visible = new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( seaPermissionRequested, ueaPermissionRequested, seaPermissionGranted, allowListed).shouldBeVisible(); assertWithMessage("Wrong return value " + visible + " for {seaPermissionRequested = " + seaPermissionRequested + ", ueaPermissionRequested = " + ueaPermissionRequested + ", seaPermissionGranted = " + seaPermissionGranted + ", allowListed = " + allowListed + "}") .that(visible) .isEqualTo(seaPermissionRequested && !ueaPermissionRequested && !allowListed); } } @Test public void alarmsAndRemindersState_isAllowed() { boolean seaPermissionRequested; boolean ueaPermissionRequested; boolean seaPermissionGranted; boolean allowListed; for (int i = 0; i < (1 << 4); i++) { seaPermissionRequested = (i & 1) != 0; ueaPermissionRequested = (i & (1 << 1)) != 0; seaPermissionGranted = (i & (1 << 2)) != 0; allowListed = (i & (1 << 3)) != 0; final boolean allowed = new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( seaPermissionRequested, ueaPermissionRequested, seaPermissionGranted, allowListed).isAllowed(); assertWithMessage("Wrong return value " + allowed + " for {seaPermissionRequested = " + seaPermissionRequested + ", ueaPermissionRequested = " + ueaPermissionRequested + ", seaPermissionGranted = " + seaPermissionGranted + ", allowListed = " + allowListed + "}") .that(allowed) .isEqualTo(seaPermissionGranted || ueaPermissionRequested || allowListed); } } private PackageInfo createPackageInfoWithPermissions(String... requestedPermissions) { final PackageInfo info = new PackageInfo(); info.requestedPermissions = requestedPermissions; return info; } @Test public void isAllowed_permissionGrantedIsTrue_isTrue() { assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( true /* permissionRequested */, true /* permissionGranted */) .isAllowed()).isTrue(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( true /* permissionRequested */, false /* permissionGranted */) .isAllowed()).isFalse(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( false /* permissionRequested */, true /* permissionGranted */) .isAllowed()).isTrue(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( false /* permissionRequested */, false /* permissionGranted */) .isAllowed()).isFalse(); public void createPermissionState_SeaGrantedNoUeaNoAllowlist() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(true).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions(Manifest.permission.SCHEDULE_EXACT_ALARM)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(false).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isTrue(); assertThat(state.isAllowed()).isTrue(); } @Test public void createPermissionState() { public void createPermissionState_requestsBothSeaDeniedNoAllowlist() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mRequesterPackages = new String[]{TEST_PACKAGE_1, "some.other.package"}; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE_1, UserHandle.getUserId(UID_1)); doReturn(true).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE_2, UserHandle.getUserId(UID_2)); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state1 = bridge.createPermissionState(TEST_PACKAGE_1, UID_1); assertThat(state1.shouldBeVisible()).isTrue(); assertThat(state1.isAllowed()).isFalse(); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state2 = bridge.createPermissionState(TEST_PACKAGE_2, UID_2); assertThat(state2.shouldBeVisible()).isFalse(); assertThat(state2.isAllowed()).isTrue(); bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions( Manifest.permission.SCHEDULE_EXACT_ALARM, Manifest.permission.USE_EXACT_ALARM)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(false).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isFalse(); assertThat(state.isAllowed()).isTrue(); } @Test public void createPermissionState_requestsNoneNoAllowlist() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions(EmptyArray.STRING)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(false).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isFalse(); assertThat(state.isAllowed()).isFalse(); } @Test public void createPermissionState_requestsOnlyUeaNoAllowlist() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions(Manifest.permission.USE_EXACT_ALARM)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(false).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isFalse(); assertThat(state.isAllowed()).isTrue(); } @Test public void createPermissionState_requestsNoneButAllowlisted() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions(EmptyArray.STRING)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(true).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isFalse(); assertThat(state.isAllowed()).isTrue(); } } Loading
src/com/android/settings/applications/AppStateAlarmsAndRemindersBridge.java +52 −27 Original line number Diff line number Diff line Loading @@ -18,11 +18,11 @@ package com.android.settings.applications; import android.Manifest; import android.app.AlarmManager; import android.app.AppGlobals; import android.app.compat.CompatChanges; import android.content.Context; import android.content.pm.IPackageManager; import android.os.RemoteException; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.PowerExemptionManager; import android.os.UserHandle; import android.util.Log; Loading @@ -32,8 +32,6 @@ import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; import libcore.util.EmptyArray; import java.util.List; /** Loading @@ -42,26 +40,24 @@ import java.util.List; * Also provides app filters that can use the info. */ public class AppStateAlarmsAndRemindersBridge extends AppStateBaseBridge { private static final String PERMISSION = Manifest.permission.SCHEDULE_EXACT_ALARM; private static final String SEA_PERMISSION = Manifest.permission.SCHEDULE_EXACT_ALARM; private static final String UEA_PERMISSION = Manifest.permission.USE_EXACT_ALARM; private static final String TAG = "AlarmsAndRemindersBridge"; @VisibleForTesting AlarmManager mAlarmManager; @VisibleForTesting String[] mRequesterPackages; PowerExemptionManager mPowerExemptionManager; @VisibleForTesting PackageManager mPackageManager; public AppStateAlarmsAndRemindersBridge(Context context, ApplicationsState appState, Callback callback) { super(appState, callback); mPowerExemptionManager = context.getSystemService(PowerExemptionManager.class); mAlarmManager = context.getSystemService(AlarmManager.class); final IPackageManager iPm = AppGlobals.getPackageManager(); try { mRequesterPackages = iPm.getAppOpPermissionPackages(PERMISSION, context.getUserId()); } catch (RemoteException re) { Log.e(TAG, "Cannot reach package manager", re); mRequesterPackages = EmptyArray.STRING; } mPackageManager = context.getPackageManager(); } private boolean isChangeEnabled(String packageName, int userId) { Loading @@ -69,6 +65,22 @@ public class AppStateAlarmsAndRemindersBridge extends AppStateBaseBridge { packageName, UserHandle.of(userId)); } private boolean isUeaChangeEnabled(String packageName, int userId) { return CompatChanges.isChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, packageName, UserHandle.of(userId)); } private String[] getRequestedPermissions(String packageName, int userId) { try { final PackageInfo info = mPackageManager.getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId); return info.requestedPermissions; } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Could not find package " + packageName, e); } return null; } /** * Returns information regarding {@link Manifest.permission#SCHEDULE_EXACT_ALARM} for the given * package and uid. Loading @@ -76,10 +88,17 @@ public class AppStateAlarmsAndRemindersBridge extends AppStateBaseBridge { public AlarmsAndRemindersState createPermissionState(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); final boolean permissionRequested = ArrayUtils.contains(mRequesterPackages, packageName) final String[] requestedPermissions = getRequestedPermissions(packageName, userId); final boolean seaRequested = ArrayUtils.contains(requestedPermissions, SEA_PERMISSION) && isChangeEnabled(packageName, userId); final boolean permissionGranted = mAlarmManager.hasScheduleExactAlarm(packageName, userId); return new AlarmsAndRemindersState(permissionRequested, permissionGranted); final boolean ueaRequested = ArrayUtils.contains(requestedPermissions, UEA_PERMISSION) && isUeaChangeEnabled(packageName, userId); final boolean seaGranted = mAlarmManager.hasScheduleExactAlarm(packageName, userId); final boolean allowListed = mPowerExemptionManager.isAllowListed(packageName, true); return new AlarmsAndRemindersState(seaRequested, ueaRequested, seaGranted, allowListed); } @Override Loading Loading @@ -113,26 +132,32 @@ public class AppStateAlarmsAndRemindersBridge extends AppStateBaseBridge { }; /** * Class to denote the state of an app regarding * {@link Manifest.permission#SCHEDULE_EXACT_ALARM}. * Class to denote the state of an app regarding "Alarms and Reminders" permission. * This permission state is a combination of {@link Manifest.permission#SCHEDULE_EXACT_ALARM}, * {@link Manifest.permission#USE_EXACT_ALARM} and the power allowlist state. */ public static class AlarmsAndRemindersState { private boolean mPermissionRequested; private boolean mPermissionGranted; AlarmsAndRemindersState(boolean permissionRequested, boolean permissionGranted) { mPermissionRequested = permissionRequested; mPermissionGranted = permissionGranted; private boolean mSeaPermissionRequested; private boolean mUeaPermissionRequested; private boolean mSeaPermissionGranted; private boolean mAllowListed; AlarmsAndRemindersState(boolean seaPermissionRequested, boolean ueaPermissionRequested, boolean seaPermissionGranted, boolean allowListed) { mSeaPermissionRequested = seaPermissionRequested; mUeaPermissionRequested = ueaPermissionRequested; mSeaPermissionGranted = seaPermissionGranted; mAllowListed = allowListed; } /** Should the app associated with this state appear on the Settings screen */ public boolean shouldBeVisible() { return mPermissionRequested; return mSeaPermissionRequested && !mUeaPermissionRequested && !mAllowListed; } /** Is the permission granted to the app associated with this state */ public boolean isAllowed() { return mPermissionGranted; return mSeaPermissionGranted || mUeaPermissionRequested || mAllowListed; } } }
tests/unit/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridgeTest.java +169 −55 Original line number Diff line number Diff line Loading @@ -16,15 +16,24 @@ package com.android.settings.applications; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import android.Manifest; import android.app.AlarmManager; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.PowerExemptionManager; import android.os.UserHandle; import androidx.test.ext.junit.runners.AndroidJUnit4; import libcore.util.EmptyArray; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -34,13 +43,15 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class AppStateAlarmsAndRemindersBridgeTest { private static final String TEST_PACKAGE_1 = "com.example.test.1"; private static final String TEST_PACKAGE_2 = "com.example.test.2"; private static final int UID_1 = 12345; private static final int UID_2 = 7654321; private static final String TEST_PACKAGE = "com.example.test.1"; private static final int TEST_UID = 12345; @Mock private AlarmManager mAlarmManager; @Mock private PowerExemptionManager mPowerExemptionManager; @Mock private PackageManager mPackageManager; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; Loading @@ -50,65 +61,168 @@ public class AppStateAlarmsAndRemindersBridgeTest { } @Test public void shouldBeVisible_permissionRequestedIsTrue_isTrue() { assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( true /* permissionRequested */, true /* permissionGranted */) .shouldBeVisible()).isTrue(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( true /* permissionRequested */, false /* permissionGranted */) .shouldBeVisible()).isTrue(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( false /* permissionRequested */, true /* permissionGranted */) .shouldBeVisible()).isFalse(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( false /* permissionRequested */, false /* permissionGranted */) .shouldBeVisible()).isFalse(); public void alarmsAndRemindersState_shouldBeVisible() { boolean seaPermissionRequested; boolean ueaPermissionRequested; boolean seaPermissionGranted; boolean allowListed; for (int i = 0; i < (1 << 4); i++) { seaPermissionRequested = (i & 1) != 0; ueaPermissionRequested = (i & (1 << 1)) != 0; seaPermissionGranted = (i & (1 << 2)) != 0; allowListed = (i & (1 << 3)) != 0; final boolean visible = new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( seaPermissionRequested, ueaPermissionRequested, seaPermissionGranted, allowListed).shouldBeVisible(); assertWithMessage("Wrong return value " + visible + " for {seaPermissionRequested = " + seaPermissionRequested + ", ueaPermissionRequested = " + ueaPermissionRequested + ", seaPermissionGranted = " + seaPermissionGranted + ", allowListed = " + allowListed + "}") .that(visible) .isEqualTo(seaPermissionRequested && !ueaPermissionRequested && !allowListed); } } @Test public void alarmsAndRemindersState_isAllowed() { boolean seaPermissionRequested; boolean ueaPermissionRequested; boolean seaPermissionGranted; boolean allowListed; for (int i = 0; i < (1 << 4); i++) { seaPermissionRequested = (i & 1) != 0; ueaPermissionRequested = (i & (1 << 1)) != 0; seaPermissionGranted = (i & (1 << 2)) != 0; allowListed = (i & (1 << 3)) != 0; final boolean allowed = new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( seaPermissionRequested, ueaPermissionRequested, seaPermissionGranted, allowListed).isAllowed(); assertWithMessage("Wrong return value " + allowed + " for {seaPermissionRequested = " + seaPermissionRequested + ", ueaPermissionRequested = " + ueaPermissionRequested + ", seaPermissionGranted = " + seaPermissionGranted + ", allowListed = " + allowListed + "}") .that(allowed) .isEqualTo(seaPermissionGranted || ueaPermissionRequested || allowListed); } } private PackageInfo createPackageInfoWithPermissions(String... requestedPermissions) { final PackageInfo info = new PackageInfo(); info.requestedPermissions = requestedPermissions; return info; } @Test public void isAllowed_permissionGrantedIsTrue_isTrue() { assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( true /* permissionRequested */, true /* permissionGranted */) .isAllowed()).isTrue(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( true /* permissionRequested */, false /* permissionGranted */) .isAllowed()).isFalse(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( false /* permissionRequested */, true /* permissionGranted */) .isAllowed()).isTrue(); assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState( false /* permissionRequested */, false /* permissionGranted */) .isAllowed()).isFalse(); public void createPermissionState_SeaGrantedNoUeaNoAllowlist() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(true).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions(Manifest.permission.SCHEDULE_EXACT_ALARM)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(false).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isTrue(); assertThat(state.isAllowed()).isTrue(); } @Test public void createPermissionState() { public void createPermissionState_requestsBothSeaDeniedNoAllowlist() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mRequesterPackages = new String[]{TEST_PACKAGE_1, "some.other.package"}; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE_1, UserHandle.getUserId(UID_1)); doReturn(true).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE_2, UserHandle.getUserId(UID_2)); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state1 = bridge.createPermissionState(TEST_PACKAGE_1, UID_1); assertThat(state1.shouldBeVisible()).isTrue(); assertThat(state1.isAllowed()).isFalse(); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state2 = bridge.createPermissionState(TEST_PACKAGE_2, UID_2); assertThat(state2.shouldBeVisible()).isFalse(); assertThat(state2.isAllowed()).isTrue(); bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions( Manifest.permission.SCHEDULE_EXACT_ALARM, Manifest.permission.USE_EXACT_ALARM)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(false).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isFalse(); assertThat(state.isAllowed()).isTrue(); } @Test public void createPermissionState_requestsNoneNoAllowlist() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions(EmptyArray.STRING)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(false).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isFalse(); assertThat(state.isAllowed()).isFalse(); } @Test public void createPermissionState_requestsOnlyUeaNoAllowlist() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions(Manifest.permission.USE_EXACT_ALARM)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(false).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isFalse(); assertThat(state.isAllowed()).isTrue(); } @Test public void createPermissionState_requestsNoneButAllowlisted() throws Exception { AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext, null, null); bridge.mAlarmManager = mAlarmManager; bridge.mPackageManager = mPackageManager; bridge.mPowerExemptionManager = mPowerExemptionManager; doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE, UserHandle.getUserId(TEST_UID)); doReturn(createPackageInfoWithPermissions(EmptyArray.STRING)) .when(mPackageManager).getPackageInfoAsUser(eq(TEST_PACKAGE), anyInt(), anyInt()); doReturn(true).when(mPowerExemptionManager).isAllowListed(TEST_PACKAGE, true); AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state = bridge.createPermissionState(TEST_PACKAGE, TEST_UID); assertThat(state.shouldBeVisible()).isFalse(); assertThat(state.isAllowed()).isTrue(); } }