Merge "Fixes SelectLongPressTimeoutPreferenceControllerTest summary check." into udc-dev
diff --git a/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridge.java b/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridge.java
index ffe8767..c96e8fb 100644
--- a/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridge.java
+++ b/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridge.java
@@ -18,11 +18,11 @@
 
 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;
 
@@ -32,8 +32,6 @@
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
 import com.android.settingslib.applications.ApplicationsState.AppFilter;
 
-import libcore.util.EmptyArray;
-
 import java.util.List;
 
 /**
@@ -42,26 +40,24 @@
  * 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) {
@@ -69,6 +65,22 @@
                 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.
@@ -76,10 +88,17 @@
     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
@@ -113,26 +132,32 @@
     };
 
     /**
-     * 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;
+        private boolean mSeaPermissionRequested;
+        private boolean mUeaPermissionRequested;
+        private boolean mSeaPermissionGranted;
+        private boolean mAllowListed;
 
-        AlarmsAndRemindersState(boolean permissionRequested, boolean permissionGranted) {
-            mPermissionRequested = permissionRequested;
-            mPermissionGranted = permissionGranted;
+        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;
         }
     }
 }
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index 3186a56..398e4b0 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -816,6 +816,14 @@
         }
 
         @Override
+        public void onStop() {
+            super.onStop();
+            if (!getActivity().isChangingConfigurations() && !mWaitingForConfirmation) {
+                getActivity().finish();
+            }
+        }
+
+        @Override
         public void onDestroy() {
             super.onDestroy();
             if (mUserPassword != null) {
diff --git a/tests/unit/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridgeTest.java b/tests/unit/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridgeTest.java
index f56da05..cd38767 100644
--- a/tests/unit/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridgeTest.java
+++ b/tests/unit/src/com/android/settings/applications/AppStateAlarmsAndRemindersBridgeTest.java
@@ -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;
@@ -34,13 +43,15 @@
 
 @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;
 
@@ -50,65 +61,168 @@
     }
 
     @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 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 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() {
+    public void createPermissionState_SeaGrantedNoUeaNoAllowlist() throws Exception {
         AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext,
                 null, null);
         bridge.mAlarmManager = mAlarmManager;
-        bridge.mRequesterPackages = new String[]{TEST_PACKAGE_1, "some.other.package"};
+        bridge.mPackageManager = mPackageManager;
+        bridge.mPowerExemptionManager = mPowerExemptionManager;
 
-        doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE_1,
-                UserHandle.getUserId(UID_1));
-        doReturn(true).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE_2,
-                UserHandle.getUserId(UID_2));
+        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 state1 =
-                bridge.createPermissionState(TEST_PACKAGE_1, UID_1);
-        assertThat(state1.shouldBeVisible()).isTrue();
-        assertThat(state1.isAllowed()).isFalse();
+        AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state =
+                bridge.createPermissionState(TEST_PACKAGE, TEST_UID);
+        assertThat(state.shouldBeVisible()).isTrue();
+        assertThat(state.isAllowed()).isTrue();
+    }
 
-        AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state2 =
-                bridge.createPermissionState(TEST_PACKAGE_2, UID_2);
-        assertThat(state2.shouldBeVisible()).isFalse();
-        assertThat(state2.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();
     }
 }