Merge "Fixing wrong arguments used for permission check" into qt-dev
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index ab174f4..f16fb1c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -712,11 +712,25 @@
     public boolean matches(WifiConfiguration config) {
         if (config.isPasspoint()) {
             return (isPasspoint() && config.FQDN.equals(mConfig.FQDN));
-        } else {
-            // Normal non-Passpoint network
-            return ssid.equals(removeDoubleQuotes(config.SSID))
-                    && security == getSecurity(config)
-                    && (mConfig == null || mConfig.shared == config.shared);
+        }
+
+        if (!ssid.equals(removeDoubleQuotes(config.SSID))
+                || (mConfig != null && mConfig.shared != config.shared)) {
+            return false;
+        }
+
+        final int configSecurity = getSecurity(config);
+        final WifiManager wifiManager = getWifiManager();
+        switch (security) {
+            case SECURITY_PSK_SAE_TRANSITION:
+                return configSecurity == SECURITY_PSK
+                        || (wifiManager.isWpa3SaeSupported() && configSecurity == SECURITY_SAE);
+            case SECURITY_OWE_TRANSITION:
+                return configSecurity == SECURITY_NONE
+                        || (wifiManager.isEnhancedOpenSupported()
+                                && configSecurity == SECURITY_OWE);
+            default:
+                return security == configSecurity;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 909b68b..0af333e 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -57,8 +57,8 @@
     private static final String LEARNING_EVENT_COUNT_KEY = "reminder_exp_learning_event_count";
     private static final String LEARNED_HINT_LAST_SHOWN_KEY =
             "reminder_exp_learned_hint_last_shown";
-    private static final long DEFAULT_LEARNING_TIME_MS = TimeUnit.DAYS.toMillis(200);
-    private static final int DEFAULT_LEARNING_COUNT = 30000;
+    private static final long DEFAULT_LEARNING_TIME_MS = TimeUnit.DAYS.toMillis(10);
+    private static final int DEFAULT_LEARNING_COUNT = 10;
     private static final long DEFAULT_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS = 150;
     private static final long DEFAULT_SHOW_AND_GO_DELAYED_LONG_DELAY_MS =
             TimeUnit.SECONDS.toMillis(1);
@@ -66,7 +66,7 @@
             TimeUnit.SECONDS.toMillis(3);
     private static final boolean DEFAULT_SUPPRESS_ON_LOCKSCREEN = false;
     private static final boolean DEFAULT_SUPPRESS_ON_LAUNCHER = false;
-    private static final boolean DEFAULT_SUPPRESS_ON_APPS = false;
+    private static final boolean DEFAULT_SUPPRESS_ON_APPS = true;
 
     private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
             PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
index 6bbeffa..deb314b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
@@ -115,7 +115,6 @@
             return false;
         }
         mWindowManager.removeViewImmediate(mKeyButtonView);
-        mRotationButtonController.cleanUp();
         mIsShowing = false;
         return true;
     }
@@ -141,10 +140,7 @@
 
     @Override
     public void setOnClickListener(View.OnClickListener onClickListener) {
-        mKeyButtonView.setOnClickListener(view -> {
-            hide();
-            onClickListener.onClick(view);
-        });
+        mKeyButtonView.setOnClickListener(onClickListener);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 5708c1b..b56abcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -871,9 +871,6 @@
         boolean[] feedbackEnabled = new boolean[1];
         int a11yFlags = getA11yButtonState(feedbackEnabled);
 
-        mNavigationBarView.getRotationButtonController().setAccessibilityFeedbackEnabled(
-                feedbackEnabled[0]);
-
         boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
         boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
         mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index ed486cd..9919abd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -1040,6 +1040,9 @@
         reorient();
         onNavigationModeChanged(mNavBarMode);
         setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
+        if (mRotationButtonController != null) {
+            mRotationButtonController.registerListeners();
+        }
 
         mEdgeBackGestureHandler.onNavBarAttached();
         getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
@@ -1053,6 +1056,10 @@
         for (int i = 0; i < mButtonDispatchers.size(); ++i) {
             mButtonDispatchers.valueAt(i).onDestroy();
         }
+        if (mRotationButtonController != null) {
+            mRotationButtonController.unregisterListeners();
+        }
+
         mEdgeBackGestureHandler.onNavBarDetached();
         getViewTreeObserver().removeOnComputeInternalInsetsListener(
                 mOnComputeInternalInsetsListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
index 1e5406f..0147e7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
@@ -26,7 +26,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Handler;
-import android.os.Message;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.view.IRotationWatcher.Stub;
@@ -34,6 +34,7 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.WindowManagerGlobal;
+import android.view.accessibility.AccessibilityManager;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -42,6 +43,7 @@
 import com.android.systemui.R;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 import com.android.systemui.statusbar.policy.RotationLockController;
 
@@ -64,8 +66,10 @@
     private boolean mPendingRotationSuggestion;
     private boolean mHoveringRotationSuggestion;
     private RotationLockController mRotationLockController;
+    private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
     private TaskStackListenerImpl mTaskStackListener;
     private Consumer<Integer> mRotWatcherListener;
+    private boolean mListenersRegistered = false;
     private boolean mIsNavigationBarShowing;
 
     private final Runnable mRemoveRotationProposal =
@@ -73,22 +77,17 @@
     private final Runnable mCancelPendingRotationProposal =
             () -> mPendingRotationSuggestion = false;
     private Animator mRotateHideAnimator;
-    private boolean mAccessibilityFeedbackEnabled;
 
     private final Context mContext;
     private final RotationButton mRotationButton;
+    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
 
     private final Stub mRotationWatcher = new Stub() {
         @Override
         public void onRotationChanged(final int rotation) throws RemoteException {
-            if (mRotationButton.getCurrentView() == null) {
-                return;
-            }
-
             // We need this to be scheduled as early as possible to beat the redrawing of
             // window in response to the orientation change.
-            Handler h = mRotationButton.getCurrentView().getHandler();
-            Message msg = Message.obtain(h, () -> {
+            mMainThreadHandler.postAtFrontOfQueue(() -> {
                 // If the screen rotation changes while locked, potentially update lock to flow with
                 // new screen rotation and hide any showing suggestions.
                 if (mRotationLockController.isRotationLocked()) {
@@ -102,8 +101,6 @@
                     mRotWatcherListener.accept(rotation);
                 }
             });
-            msg.setAsynchronous(true);
-            h.sendMessageAtFrontOfQueue(msg);
         }
     };
 
@@ -124,40 +121,49 @@
         mStyleRes = style;
         mIsNavigationBarShowing = true;
         mRotationLockController = Dependency.get(RotationLockController.class);
+        mAccessibilityManagerWrapper = Dependency.get(AccessibilityManagerWrapper.class);
 
         // Register the task stack listener
         mTaskStackListener = new TaskStackListenerImpl();
-        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
         mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
         mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
+    }
 
+    void registerListeners() {
+        if (mListenersRegistered) {
+            return;
+        }
+
+        mListenersRegistered = true;
         try {
             WindowManagerGlobal.getWindowManagerService()
                     .watchRotation(mRotationWatcher, mContext.getDisplay().getDisplayId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
+
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
     }
 
-    void cleanUp() {
-        // Unregister the task stack listener
-        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
+    void unregisterListeners() {
+        if (!mListenersRegistered) {
+            return;
+        }
 
+        mListenersRegistered = false;
         try {
             WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mRotationWatcher);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
+
+        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
     }
 
     void addRotationCallback(Consumer<Integer> watcher) {
         mRotWatcherListener = watcher;
     }
 
-    void setAccessibilityFeedbackEnabled(boolean flag) {
-        mAccessibilityFeedbackEnabled = flag;
-    }
-
     void setRotationLockedAtAngle(int rotationSuggestion) {
         mRotationLockController.setRotationLockedAtAngle(true /* locked */, rotationSuggestion);
     }
@@ -185,7 +191,7 @@
 
         // Clear any pending suggestion flag as it has either been nullified or is being shown
         mPendingRotationSuggestion = false;
-        view.removeCallbacks(mCancelPendingRotationProposal);
+        mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);
 
         // Handle the visibility change and animation
         if (visible) { // Appear and change (cannot force)
@@ -255,13 +261,9 @@
             return;
         }
 
-        final View currentView = mRotationButton.getCurrentView();
-
         // If window rotation matches suggested rotation, remove any current suggestions
         if (rotation == windowRotation) {
-            if (currentView != null) {
-                currentView.removeCallbacks(mRemoveRotationProposal);
-            }
+            mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
             setRotateSuggestionButtonState(false /* visible */);
             return;
         }
@@ -285,11 +287,9 @@
             // If the navbar isn't shown, flag the rotate icon to be shown should the navbar become
             // visible given some time limit.
             mPendingRotationSuggestion = true;
-            if (currentView != null) {
-                currentView.removeCallbacks(mCancelPendingRotationProposal);
-                currentView.postDelayed(mCancelPendingRotationProposal,
-                        NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
-            }
+            mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);
+            mMainThreadHandler.postDelayed(mCancelPendingRotationProposal,
+                    NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
         }
     }
 
@@ -334,9 +334,7 @@
     private void onRotationSuggestionsDisabled() {
         // Immediately hide the rotate button and clear any planned removal
         setRotateSuggestionButtonState(false /* visible */, true /* force */);
-        if (mRotationButton.getCurrentView() != null) {
-            mRotationButton.getCurrentView().removeCallbacks(mRemoveRotationProposal);
-        }
+        mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
     }
 
     private void showAndLogRotationSuggestion() {
@@ -369,10 +367,6 @@
     }
 
     private void rescheduleRotationTimeout(final boolean reasonHover) {
-        if (mRotationButton.getCurrentView() == null) {
-            return;
-        }
-
         // May be called due to a new rotation proposal or a change in hover state
         if (reasonHover) {
             // Don't reschedule if a hide animator is running
@@ -382,16 +376,16 @@
         }
 
         // Stop any pending removal
-        mRotationButton.getCurrentView().removeCallbacks(mRemoveRotationProposal);
+        mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
         // Schedule timeout
-        mRotationButton.getCurrentView().postDelayed(mRemoveRotationProposal,
+        mMainThreadHandler.postDelayed(mRemoveRotationProposal,
                 computeRotationProposalTimeout());
     }
 
     private int computeRotationProposalTimeout() {
-        if (mAccessibilityFeedbackEnabled) return 10000;
-        if (mHoveringRotationSuggestion) return 8000;
-        return 5000;
+        return mAccessibilityManagerWrapper.getRecommendedTimeoutMillis(
+                mHoveringRotationSuggestion ? 16000 : 5000,
+                AccessibilityManager.FLAG_CONTENT_CONTROLS);
     }
 
     private boolean isRotateSuggestionIntroduced() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
index 24e7336..bd96752 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
@@ -64,13 +64,6 @@
     }
 
     @Override
-    public void onDestroy() {
-        if (mRotationButtonController != null) {
-            mRotationButtonController.cleanUp();
-        }
-    }
-
-    @Override
     public void onNavigationModeChanged(int mode) {
         mNavBarMode = mode;
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5f4d113..d2031b6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -111,9 +111,6 @@
 import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
 import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
-import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
-import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
-import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
 
 import android.Manifest;
 import android.annotation.IntDef;
@@ -294,6 +291,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.IntPair;
 import com.android.internal.util.Preconditions;
 import com.android.server.AttributeCache;
 import com.android.server.DeviceIdleController;
@@ -19801,6 +19799,8 @@
             return;
         }
 
+        final String packageName = ps.pkg.packageName;
+
         // These are flags that can change base on user actions.
         final int userSettableMask = FLAG_PERMISSION_USER_SET
                 | FLAG_PERMISSION_USER_FIXED
@@ -19810,8 +19810,59 @@
         final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
                 | FLAG_PERMISSION_POLICY_FIXED;
 
-        boolean writeInstallPermissions = false;
-        boolean writeRuntimePermissions = false;
+        // Delay and combine non-async permission callbacks
+        final boolean[] permissionRemoved = new boolean[1];
+        final ArraySet<Long> revokedPermissions = new ArraySet<>();
+        final SparseBooleanArray updatedUsers = new SparseBooleanArray();
+
+        PermissionCallback delayingPermCallback = new PermissionCallback() {
+            public void onGidsChanged(int appId, int userId) {
+                mPermissionCallback.onGidsChanged(appId, userId);
+            }
+
+            public void onPermissionChanged() {
+                mPermissionCallback.onPermissionChanged();
+            }
+
+            public void onPermissionGranted(int uid, int userId) {
+                mPermissionCallback.onPermissionGranted(uid, userId);
+            }
+
+            public void onInstallPermissionGranted() {
+                mPermissionCallback.onInstallPermissionGranted();
+            }
+
+            public void onPermissionRevoked(int uid, int userId) {
+                revokedPermissions.add(IntPair.of(uid, userId));
+
+                updatedUsers.put(userId, true);
+            }
+
+            public void onInstallPermissionRevoked() {
+                mPermissionCallback.onInstallPermissionRevoked();
+            }
+
+            public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
+                for (int userId : updatedUserIds) {
+                    if (sync) {
+                        updatedUsers.put(userId, true);
+                    } else {
+                        // Don't override sync=true by sync=false
+                        if (!updatedUsers.get(userId)) {
+                            updatedUsers.put(userId, false);
+                        }
+                    }
+                }
+            }
+
+            public void onPermissionRemoved() {
+                permissionRemoved[0] = true;
+            }
+
+            public void onInstallPermissionUpdated() {
+                mPermissionCallback.onInstallPermissionUpdated();
+            }
+        };
 
         final int permissionCount = ps.pkg.requestedPermissions.size();
         for (int i = 0; i < permissionCount; i++) {
@@ -19843,26 +19894,20 @@
                 }
             }
 
-            final PermissionsState permissionsState = ps.getPermissionsState();
-
-            final int oldFlags = permissionsState.getPermissionFlags(permName, userId);
+            final int oldFlags = mPermissionManager.getPermissionFlags(permName, packageName,
+                    Process.SYSTEM_UID, userId);
 
             // Always clear the user settable flags.
-            final boolean hasInstallState =
-                    permissionsState.getInstallPermissionState(permName) != null;
             // If permission review is enabled and this is a legacy app, mark the
             // permission as requiring a review as this is the initial state.
             int flags = 0;
             if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) {
                 flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
             }
-            if (permissionsState.updatePermissionFlags(bp, userId, userSettableMask, flags)) {
-                if (hasInstallState) {
-                    writeInstallPermissions = true;
-                } else {
-                    writeRuntimePermissions = true;
-                }
-            }
+
+            mPermissionManager.updatePermissionFlags(permName, packageName,
+                    userSettableMask, flags, Process.SYSTEM_UID, userId, false,
+                    delayingPermCallback);
 
             // Below is only runtime permission handling.
             if (!bp.isRuntime()) {
@@ -19876,35 +19921,42 @@
 
             // If this permission was granted by default, make sure it is.
             if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
-                if (permissionsState.grantRuntimePermission(bp, userId)
-                        != PERMISSION_OPERATION_FAILURE) {
-                    writeRuntimePermissions = true;
-                }
+                mPermissionManager.grantRuntimePermission(permName, packageName, false,
+                        Process.SYSTEM_UID, userId, delayingPermCallback);
             // If permission review is enabled the permissions for a legacy apps
             // are represented as constantly granted runtime ones, so don't revoke.
             } else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
                 // Otherwise, reset the permission.
-                final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId);
-                switch (revokeResult) {
-                    case PERMISSION_OPERATION_SUCCESS:
-                    case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
-                        writeRuntimePermissions = true;
-                        final int appId = ps.appId;
-                        mHandler.post(
-                                () -> killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED));
-                    } break;
-                }
+                mPermissionManager.revokeRuntimePermission(permName, packageName, false, userId,
+                        delayingPermCallback);
             }
         }
 
-        // Synchronously write as we are taking permissions away.
-        if (writeRuntimePermissions) {
-            mSettings.writeRuntimePermissionsForUserLPr(userId, true);
+        // Execute delayed callbacks
+        if (permissionRemoved[0]) {
+            mPermissionCallback.onPermissionRemoved();
         }
 
-        // Synchronously write as we are taking permissions away.
-        if (writeInstallPermissions) {
-            mSettings.writeLPr();
+        // Slight variation on the code in mPermissionCallback.onPermissionRevoked() as we cannot
+        // kill uid while holding mPackages-lock
+        if (!revokedPermissions.isEmpty()) {
+            int numRevokedPermissions = revokedPermissions.size();
+            for (int i = 0; i < numRevokedPermissions; i++) {
+                int revocationUID = IntPair.first(revokedPermissions.valueAt(i));
+                int revocationUserId = IntPair.second(revokedPermissions.valueAt(i));
+
+                mOnPermissionChangeListeners.onPermissionsChanged(revocationUID);
+
+                // Kill app later as we are holding mPackages
+                mHandler.post(() -> killUid(UserHandle.getAppId(revocationUID), revocationUserId,
+                        KILL_APP_REASON_PERMISSIONS_REVOKED));
+            }
+        }
+
+        int numUpdatedUsers = updatedUsers.size();
+        for (int i = 0; i < numUpdatedUsers; i++) {
+            mSettings.writeRuntimePermissionsForUserLPr(updatedUsers.keyAt(i),
+                    updatedUsers.valueAt(i));
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index e5f914d..a7da3ec 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3127,6 +3127,27 @@
         }
 
         @Override
+        public @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtectionLevel(
+                @PermissionInfo.Protection int protectionLevel) {
+            ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
+
+            synchronized (PermissionManagerService.this.mLock) {
+                int numTotalPermissions = mSettings.mPermissions.size();
+
+                for (int i = 0; i < numTotalPermissions; i++) {
+                    BasePermission bp = mSettings.mPermissions.valueAt(i);
+
+                    if (bp.perm != null && bp.perm.info != null
+                            && bp.protectionLevel == protectionLevel) {
+                        matchingPermissions.add(bp.perm.info);
+                    }
+                }
+            }
+
+            return matchingPermissions;
+        }
+
+        @Override
         public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
             return PermissionManagerService.this.backupRuntimePermissions(user);
         }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 313de3d..e5e9598 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -195,4 +195,8 @@
 
     /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
     public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
+
+    /** Get all permission that have a certain protection level */
+    public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtectionLevel(
+            @PermissionInfo.Protection int protectionLevel);
 }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 93b11bef..68feb4a 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -23,6 +23,7 @@
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 
 import android.annotation.NonNull;
@@ -41,20 +42,27 @@
 import android.content.pm.PermissionInfo;
 import android.os.Build;
 import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.permission.PermissionControllerManager;
-import android.permission.PermissionManagerInternal;
 import android.provider.Telephony;
 import android.telecom.TelecomManager;
+import android.util.ArraySet;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
@@ -76,6 +84,13 @@
     @GuardedBy("mLock")
     private final SparseBooleanArray mIsStarted = new SparseBooleanArray();
 
+    /**
+     * Whether an async {@link #synchronizePackagePermissionsAndAppOpsForUser} is currently
+     * scheduled for a package/user.
+     */
+    @GuardedBy("mLock")
+    private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>();
+
     public PermissionPolicyService(@NonNull Context context) {
         super(context);
 
@@ -86,8 +101,10 @@
     public void onStart() {
         final PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
-        final PermissionManagerInternal permManagerInternal = LocalServices.getService(
-                PermissionManagerInternal.class);
+        final PermissionManagerServiceInternal permManagerInternal = LocalServices.getService(
+                PermissionManagerServiceInternal.class);
+        final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_OPS_SERVICE));
 
         packageManagerInternal.getPackageList(new PackageListObserver() {
             @Override
@@ -111,11 +128,62 @@
         });
 
         permManagerInternal.addOnRuntimePermissionStateChangedListener(
-                (packageName, changedUserId) -> {
-                    if (isStarted(changedUserId)) {
-                        synchronizePackagePermissionsAndAppOpsForUser(packageName, changedUserId);
+                this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
+
+        IAppOpsCallback appOpsListener = new IAppOpsCallback.Stub() {
+            public void opChanged(int op, int uid, String packageName) {
+                synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
+                        UserHandle.getUserId(uid));
+            }
+        };
+
+        final ArrayList<PermissionInfo> dangerousPerms =
+                permManagerInternal.getAllPermissionWithProtectionLevel(
+                        PermissionInfo.PROTECTION_DANGEROUS);
+
+        try {
+            int numDangerousPerms = dangerousPerms.size();
+            for (int i = 0; i < numDangerousPerms; i++) {
+                PermissionInfo perm = dangerousPerms.get(i);
+
+                if (perm.isHardRestricted() || perm.backgroundPermission != null) {
+                    appOpsService.startWatchingMode(AppOpsManager.permissionToOpCode(perm.name),
+                            null, appOpsListener);
+                } else if (perm.isSoftRestricted()) {
+                    appOpsService.startWatchingMode(AppOpsManager.permissionToOpCode(perm.name),
+                            null, appOpsListener);
+
+                    SoftRestrictedPermissionPolicy policy =
+                            SoftRestrictedPermissionPolicy.forPermission(null, null, null,
+                                    perm.name);
+                    if (policy.resolveAppOp() != OP_NONE) {
+                        appOpsService.startWatchingMode(policy.resolveAppOp(), null,
+                                appOpsListener);
                     }
-                });
+                }
+            }
+        } catch (RemoteException doesNotHappen) {
+            Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
+        }
+    }
+
+    private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName,
+            @UserIdInt int changedUserId) {
+        if (isStarted(changedUserId)) {
+            synchronized (mLock) {
+                if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
+                    FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+                            PermissionPolicyService
+                                    ::synchronizePackagePermissionsAndAppOpsForUser,
+                            this, packageName, changedUserId));
+                } else {
+                    if (DEBUG) {
+                        Slog.v(LOG_TAG, "sync for " + packageName + "/" + changedUserId
+                                + " already scheduled");
+                    }
+                }
+            }
+        }
     }
 
     @Override
@@ -230,10 +298,14 @@
      */
     private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName,
             @UserIdInt int userId) {
+        synchronized (mLock) {
+            mIsPackageSyncsScheduled.remove(new Pair<>(packageName, userId));
+        }
+
         if (DEBUG) {
             Slog.v(LOG_TAG,
-                    "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", " + userId
-                            + ")");
+                    "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", "
+                            + userId + ")");
         }
 
         final PackageManagerInternal packageManagerInternal = LocalServices.getService(
@@ -336,6 +408,16 @@
          */
         private final @NonNull ArrayList<OpToUnrestrict> mOpsToForeground = new ArrayList<>();
 
+        /**
+         * All ops that need to be flipped to foreground if allow.
+         *
+         * Currently, only used by the foreground/background permissions logic.
+         *
+         * @see #syncPackages
+         */
+        private final @NonNull ArrayList<OpToUnrestrict> mOpsToForegroundIfAllow =
+                new ArrayList<>();
+
         PermissionToOpSynchroniser(@NonNull Context context) {
             mContext = context;
             mPackageManager = context.getPackageManager();
@@ -351,22 +433,27 @@
             final int allowCount = mOpsToAllow.size();
             for (int i = 0; i < allowCount; i++) {
                 final OpToUnrestrict op = mOpsToAllow.get(i);
-                setUidModeAllowed(op.code, op.uid);
+                setUidModeAllowed(op.code, op.uid, op.packageName);
             }
             final int allowIfDefaultCount = mOpsToAllowIfDefault.size();
             for (int i = 0; i < allowIfDefaultCount; i++) {
                 final OpToUnrestrict op = mOpsToAllowIfDefault.get(i);
                 setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
             }
-            final int foregroundCount = mOpsToForeground.size();
+            final int foregroundCount = mOpsToForegroundIfAllow.size();
             for (int i = 0; i < foregroundCount; i++) {
+                final OpToUnrestrict op = mOpsToForegroundIfAllow.get(i);
+                setUidModeForegroundIfAllow(op.code, op.uid, op.packageName);
+            }
+            final int foregroundIfAllowCount = mOpsToForeground.size();
+            for (int i = 0; i < foregroundIfAllowCount; i++) {
                 final OpToUnrestrict op = mOpsToForeground.get(i);
-                setUidModeForeground(op.code, op.uid);
+                setUidModeForeground(op.code, op.uid, op.packageName);
             }
             final int ignoreCount = mOpsToIgnore.size();
             for (int i = 0; i < ignoreCount; i++) {
                 final OpToUnrestrict op = mOpsToIgnore.get(i);
-                setUidModeIgnored(op.code, op.uid);
+                setUidModeIgnored(op.code, op.uid, op.packageName);
             }
             final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size();
             for (int i = 0; i < ignoreIfDefaultCount; i++) {
@@ -459,6 +546,24 @@
             }
         }
 
+        private boolean isBgPermRestricted(@NonNull String pkg, @NonNull String perm, int uid) {
+            try {
+                final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo(perm, 0);
+
+                if (bgPermInfo.isSoftRestricted()) {
+                    Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not "
+                            + "implemented");
+                }
+
+                return bgPermInfo.isHardRestricted() && (mPackageManager.getPermissionFlags(
+                                perm, pkg, UserHandle.getUserHandleForUid(uid))
+                                & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+            } catch (NameNotFoundException e) {
+                Slog.w(LOG_TAG, "Cannot read permission state of " + perm, e);
+                return false;
+            }
+        }
+
         /**
          * Add op that belong to a foreground permission for later processing in
          * {@link #syncPackages()}.
@@ -481,26 +586,27 @@
             final String pkgName = pkg.packageName;
             final int uid = pkg.applicationInfo.uid;
 
-            if (mPackageManager.checkPermission(permission, pkgName)
-                    == PackageManager.PERMISSION_GRANTED) {
-                boolean isBgHardRestricted = false;
-                try {
-                    final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo(
-                            bgPermissionName, 0);
+            // App does not support runtime permissions. Hence the state is encoded in the app-op.
+            // To not override unrecoverable state don't change app-op unless bg perm is reviewed.
+            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+                // If the review is required for this permission, the grant state does not
+                // really matter. To have a stable state, don't change the app-op if review is still
+                // pending.
+                int flags = mPackageManager.getPermissionFlags(bgPermissionName,
+                        pkg.packageName, UserHandle.getUserHandleForUid(uid));
 
-                    if (bgPermInfo.isSoftRestricted()) {
-                        Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not "
-                                + "implemented");
-                    }
-
-                    isBgHardRestricted =
-                            bgPermInfo.isHardRestricted() && (mPackageManager.getPermissionFlags(
-                                    bgPermissionName, pkgName, UserHandle.getUserHandleForUid(uid))
-                                    & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
-                } catch (NameNotFoundException e) {
-                    Slog.w(LOG_TAG, "Cannot read permission state of " + bgPermissionName, e);
+                if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0
+                        && isBgPermRestricted(pkgName, bgPermissionName, uid)) {
+                    mOpsToForegroundIfAllow.add(new OpToUnrestrict(uid, pkgName, opCode));
                 }
 
+                return;
+            }
+
+            if (mPackageManager.checkPermission(permission, pkgName)
+                    == PackageManager.PERMISSION_GRANTED) {
+                final boolean isBgHardRestricted = isBgPermRestricted(pkgName, bgPermissionName,
+                        uid);
                 final boolean isBgPermGranted = mPackageManager.checkPermission(bgPermissionName,
                         pkgName) == PackageManager.PERMISSION_GRANTED;
 
@@ -554,45 +660,49 @@
         }
 
         private void setUidModeAllowedIfDefault(int opCode, int uid, @NonNull String packageName) {
-            setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_ALLOWED, packageName);
+            setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_ALLOWED, packageName);
         }
 
-        private void setUidModeAllowed(int opCode, int uid) {
-            mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
+        private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
+            setUidMode(opCode, uid, MODE_ALLOWED, packageName);
         }
 
-        private void setUidModeForeground(int opCode, int uid) {
-            mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_FOREGROUND);
+        private void setUidModeForegroundIfAllow(int opCode, int uid, @NonNull String packageName) {
+            setUidModeIfMode(opCode, uid, MODE_ALLOWED, MODE_FOREGROUND, packageName);
+        }
+
+        private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
+            setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
         }
 
         private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) {
-            setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_IGNORED, packageName);
+            setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_IGNORED, packageName);
         }
 
-        private void setUidModeIgnored(int opCode, int uid) {
-            mAppOpsManager.setUidMode(opCode, uid, MODE_IGNORED);
+        private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
+            setUidMode(opCode, uid, MODE_IGNORED, packageName);
         }
 
-        private void setUidModeIfDefault(int opCode, int uid, int mode,
+        private void setUidMode(int opCode, int uid, int mode,
                 @NonNull String packageName) {
-            final int currentMode;
-            try {
-                currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
-                        .opToPublicName(opCode), uid, packageName);
-            } catch (SecurityException e) {
-                // This might happen if the app was uninstalled in between the add and sync step.
-                // In this case the package name cannot be resolved inside appops service and hence
-                // the uid does not match.
-                Slog.w(LOG_TAG, "Cannot set mode of uid=" + uid + " op=" + opCode + " to " + mode,
-                        e);
-                return;
-            }
+            final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
+                    .opToPublicName(opCode), uid, packageName);
 
-            if (currentMode == MODE_DEFAULT) {
+            if (currentMode != mode) {
                 mAppOpsManager.setUidMode(opCode, uid, mode);
             }
         }
 
+        private void setUidModeIfMode(int opCode, int uid, int requiredModeBefore, int newMode,
+                @NonNull String packageName) {
+            final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
+                    .opToPublicName(opCode), uid, packageName);
+
+            if (currentMode == requiredModeBefore) {
+                mAppOpsManager.setUidMode(opCode, uid, newMode);
+            }
+        }
+
         private void setUidModeDefault(int opCode, int uid) {
             mAppOpsManager.setUidMode(opCode, uid, MODE_DEFAULT);
         }
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 90e0dc4..1658833 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -29,6 +29,7 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -75,14 +76,16 @@
      * Get the policy for a soft restricted permission.
      *
      * @param context A context to use
-     * @param appInfo The application the permission belongs to
-     * @param user The user the app belongs to
+     * @param appInfo The application the permission belongs to. Can be {@code null}, but then
+     *                only {@link #resolveAppOp} will work.
+     * @param user The user the app belongs to. Can be {@code null}, but then only
+     *             {@link #resolveAppOp} will work.
      * @param permission The name of the permission
      *
      * @return The policy for this permission
      */
     public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context,
-            @NonNull ApplicationInfo appInfo, @NonNull UserHandle user,
+            @Nullable ApplicationInfo appInfo, @Nullable UserHandle user,
             @NonNull String permission) {
         switch (permission) {
             // Storage uses a special app op to decide the mount state and supports soft restriction
@@ -90,13 +93,26 @@
             // collections.
             case READ_EXTERNAL_STORAGE:
             case WRITE_EXTERNAL_STORAGE: {
-                int flags = context.getPackageManager().getPermissionFlags(
-                        permission, appInfo.packageName, user);
-                boolean applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
-                boolean isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
-                boolean hasRequestedLegacyExternalStorage =
-                        appInfo.hasRequestedLegacyExternalStorage();
-                int targetSDK = appInfo.targetSdkVersion;
+                final int flags;
+                final boolean applyRestriction;
+                final boolean isWhiteListed;
+                final boolean hasRequestedLegacyExternalStorage;
+                final int targetSDK;
+
+                if (appInfo != null) {
+                    flags = context.getPackageManager().getPermissionFlags(permission,
+                            appInfo.packageName, user);
+                    applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+                    isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
+                    hasRequestedLegacyExternalStorage = appInfo.hasRequestedLegacyExternalStorage();
+                    targetSDK = appInfo.targetSdkVersion;
+                } else {
+                    flags = 0;
+                    applyRestriction = false;
+                    isWhiteListed = false;
+                    hasRequestedLegacyExternalStorage = false;
+                    targetSDK = 0;
+                }
 
                 return new SoftRestrictedPermissionPolicy() {
                     @Override
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 9189279..be3b924 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -79,6 +79,7 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
+import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 
@@ -540,6 +541,14 @@
                 // If the app was already visible, don't reset the waitingToShow state.
                 if (isHidden()) {
                     waitingToShow = true;
+
+                    // Let's reset the draw state in order to prevent the starting window to be
+                    // immediately dismissed when the app still has the surface.
+                    forAllWindows(w -> {
+                            if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
+                                w.mWinAnimator.resetDrawState();
+                            }
+                        },  true /* traverseTopToBottom */);
                 }
             }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ce8720a..57fa2ed 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7626,22 +7626,30 @@
 
     @Override
     public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
-        boolean shouldWaitForAnimToComplete = false;
+        boolean isDown;
+        boolean isUp;
+
         if (ev instanceof KeyEvent) {
             KeyEvent keyEvent = (KeyEvent) ev;
-            shouldWaitForAnimToComplete = keyEvent.getSource() == InputDevice.SOURCE_MOUSE
-                    || keyEvent.getAction() == KeyEvent.ACTION_DOWN;
-        } else if (ev instanceof MotionEvent) {
+            isDown = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
+            isUp = keyEvent.getAction() == KeyEvent.ACTION_UP;
+        } else {
             MotionEvent motionEvent = (MotionEvent) ev;
-            shouldWaitForAnimToComplete = motionEvent.getSource() == InputDevice.SOURCE_MOUSE
-                    || motionEvent.getAction() == MotionEvent.ACTION_DOWN;
+            isDown = motionEvent.getAction() == MotionEvent.ACTION_DOWN;
+            isUp = motionEvent.getAction() == MotionEvent.ACTION_UP;
         }
 
-        if (shouldWaitForAnimToComplete) {
+        // For ACTION_DOWN, syncInputTransactions before injecting input.
+        // For ACTION_UP, sync after injecting.
+        if (isDown) {
             syncInputTransactions();
         }
-
-        return LocalServices.getService(InputManagerInternal.class).injectInputEvent(ev, mode);
+        final boolean result =
+                LocalServices.getService(InputManagerInternal.class).injectInputEvent(ev, mode);
+        if (isUp) {
+            syncInputTransactions();
+        }
+        return result;
     }
 
     @Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ba59cdb..8b61208 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -6443,7 +6443,7 @@
                     .setAdmin(admin)
                     .setStrings(vpnPackage)
                     .setBoolean(lockdown)
-                    .setInt(/* number of vpn packages */ 0)
+                    .setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0)
                     .write();
         } finally {
             mInjector.binderRestoreCallingIdentity(token);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 1ac81db..a10454e 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -791,6 +791,14 @@
     public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
 
     /**
+     * IMSI (International Mobile Subscriber Identity).
+     * <P>Type: TEXT </P>
+     * @hide
+     */
+    //TODO: add @SystemApi
+    public static final String IMSI = "imsi";
+
+    /**
      * Broadcast Action: The user has changed one of the default subs related to
      * data, phone calls, or sms</p>
      *