Files
app_Settings/tests/unit/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridgeTest.java
Suprabh Shukla 5aeef97cae Handle corner cases in "Alarms and Reminders" page
There are few corner cases and new updates that need to be incorporated:
1. Apps that declare USE_EXACT_ALARM, do not need SCHEDULE_EXACT_ALARM.
   So these should be filtered out, regardless of whather they declared
   the latter.
2. Apps that are in the power allowlist do not need either of the
   permission, and so these should be filtered out as well.

In either case, if the user somehow ends up in the app detail page for
this setting, the switch should get disabled based on existing logic.

Test: make -j RunSettingsRoboTests
Test: Manually by UI inspection:
Settings -> Apps -> Special App access -> Alarms and Reminders
or by running:
adb shell am start -a android.settings.REQUEST_SCHEDULE_EXACT_ALARM

Bug: 232460265
Change-Id: I5aeab49f95260218878bc36f5a4d73a49e5082e4
2023-04-12 19:17:57 -07:00

229 lines
9.7 KiB
Java

/*
* Copyright (C) 2021 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.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;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class AppStateAlarmsAndRemindersBridgeTest {
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;
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
@Test
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 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_requestsBothSeaDeniedNoAllowlist() 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.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();
}
}