Merge "Pad indication text to prevent clipping on side of screen." into qt-r1-dev
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index eda6cd0..a3fccd9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4986,6 +4986,7 @@
         <service
                 android:name="com.android.server.autofill.AutofillCompatAccessibilityService"
                 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+                android:visibleToInstantApps="true"
                 android:exported="true">
             <meta-data
                     android:name="android.accessibilityservice"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 7c24130..861187f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -154,12 +154,8 @@
     <!-- The number of milliseconds before the heads up notification accepts touches. -->
     <integer name="touch_acceptance_delay">700</integer>
 
-    <!-- The number of milliseconds before the ambient notification auto-dismisses. This will
-         override the default pulse length. -->
-    <integer name="heads_up_notification_decay_dozing">10000</integer>
-
     <!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
-    <integer name="ambient_notification_extension_time">6000</integer>
+    <integer name="ambient_notification_extension_time">10000</integer>
 
     <!-- In multi-window, determines whether the stack where recents lives should grow from
          the smallest position when being launched. -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index c7c648c..4ad262f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -513,7 +513,7 @@
                 case SimPuk:
                     // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
                     SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
-                    if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
+                    if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
                             KeyguardUpdateMonitor.getCurrentUser())) {
                         finish = true;
                         eventSubtype = BOUNCER_DISMISS_SIM;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index fc3d1a5..d22d2c3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -30,6 +30,7 @@
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.classifier.FalsingManagerFactory;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.AsyncSensorManager;
 import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -70,7 +71,7 @@
                 new DozeScreenState(wrappedService, handler, params, wakeLock),
                 createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
                         handler),
-                new DozeWallpaperState(context),
+                new DozeWallpaperState(context, getBiometricUnlockController(dozeService)),
                 new DozeDockHandler(context, machine, host, config, handler, dockManager),
                 new DozeAuthRemover(dozeService)
         });
@@ -108,4 +109,10 @@
         final SystemUIApplication app = (SystemUIApplication) appCandidate;
         return app.getComponent(DozeHost.class);
     }
+
+    public static BiometricUnlockController getBiometricUnlockController(DozeService service) {
+        Application appCandidate = service.getApplication();
+        final SystemUIApplication app = (SystemUIApplication) appCandidate;
+        return app.getComponent(BiometricUnlockController.class);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index 1b3cd88..35c8b74 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -24,6 +24,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.DozeParameters;
 
 import java.io.PrintWriter;
@@ -38,18 +39,22 @@
 
     private final IWallpaperManager mWallpaperManagerService;
     private final DozeParameters mDozeParameters;
+    private final BiometricUnlockController mBiometricUnlockController;
     private boolean mIsAmbientMode;
 
-    public DozeWallpaperState(Context context) {
+    public DozeWallpaperState(Context context,
+            BiometricUnlockController biometricUnlockController) {
         this(IWallpaperManager.Stub.asInterface(
                 ServiceManager.getService(Context.WALLPAPER_SERVICE)),
+                biometricUnlockController,
                 DozeParameters.getInstance(context));
     }
 
     @VisibleForTesting
     DozeWallpaperState(IWallpaperManager wallpaperManagerService,
-            DozeParameters parameters) {
+            BiometricUnlockController biometricUnlockController, DozeParameters parameters) {
         mWallpaperManagerService = wallpaperManagerService;
+        mBiometricUnlockController = biometricUnlockController;
         mDozeParameters = parameters;
     }
 
@@ -76,7 +81,9 @@
         } else {
             boolean wakingUpFromPulse = oldState == DozeMachine.State.DOZE_PULSING
                     && newState == DozeMachine.State.FINISH;
-            animated = !mDozeParameters.getDisplayNeedsBlanking() || wakingUpFromPulse;
+            boolean fastDisplay = !mDozeParameters.getDisplayNeedsBlanking();
+            animated = (fastDisplay && !mBiometricUnlockController.unlockedByWakeAndUnlock())
+                    || wakingUpFromPulse;
         }
 
         if (isAmbientMode != mIsAmbientMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 930f57e..94cd2cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -141,6 +141,7 @@
     private BiometricSourceType mPendingAuthenticatedBioSourceType = null;
     private boolean mPendingShowBouncer;
     private boolean mHasScreenTurnedOnSinceAuthenticating;
+    private boolean mFadedAwayAfterWakeAndUnlock;
 
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
@@ -368,6 +369,7 @@
     @Override
     public void onStartedGoingToSleep(int why) {
         resetMode();
+        mFadedAwayAfterWakeAndUnlock = false;
         mPendingAuthenticatedUserId = -1;
         mPendingAuthenticatedBioSourceType = null;
     }
@@ -513,6 +515,9 @@
     }
 
     public void finishKeyguardFadingAway() {
+        if (isWakeAndUnlock()) {
+            mFadedAwayAfterWakeAndUnlock = true;
+        }
         resetMode();
     }
 
@@ -563,6 +568,14 @@
     }
 
     /**
+     * Successful authentication with fingerprint, face, or iris that wakes up the device.
+     * This will return {@code true} even after the keyguard fades away.
+     */
+    public boolean unlockedByWakeAndUnlock() {
+        return  isWakeAndUnlock() || mFadedAwayAfterWakeAndUnlock;
+    }
+
+    /**
      * Successful authentication with fingerprint, face, or iris when the screen was either
      * on or off.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index cbaf85c..680e522 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -72,8 +72,6 @@
     private NotificationGroupManager mGroupManager;
     private VisualStabilityManager mVisualStabilityManager;
     private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
-    @VisibleForTesting
-    int mAutoDismissNotificationDecayDozing;
     private boolean mReleaseOnExpandFinish;
 
     private int mStatusBarHeight;
@@ -120,8 +118,6 @@
             KeyguardBypassController bypassController) {
         super(context);
         Resources resources = mContext.getResources();
-        mAutoDismissNotificationDecayDozing = resources.getInteger(
-                R.integer.heads_up_notification_decay_dozing);
         mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
         mAutoHeadsUpNotificationDecay = resources.getInteger(
                 R.integer.auto_heads_up_notification_decay);
@@ -612,9 +608,7 @@
         }
 
         private int getDecayDuration() {
-            if (mStatusBarStateController.isDozing()) {
-                return mAutoDismissNotificationDecayDozing;
-            } else if (isAutoHeadsUp()) {
+            if (isAutoHeadsUp()) {
                 return getRecommendedHeadsUpTimeoutMs(mAutoHeadsUpNotificationDecay);
             } else {
                 return getRecommendedHeadsUpTimeoutMs(mAutoDismissNotificationDecay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 49afae7..1360a08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -102,6 +102,7 @@
     private boolean mWakeAndUnlockRunning;
     private boolean mKeyguardShowing;
     private boolean mShowingLaunchAffordance;
+    private boolean mKeyguardJustShown;
     private boolean mUpdatePending;
 
     private final KeyguardMonitor.Callback mKeyguardMonitorCallback =
@@ -115,6 +116,9 @@
                         mBlockUpdates = false;
                         force = true;
                     }
+                    if (!wasShowing && mKeyguardShowing) {
+                        mKeyguardJustShown = true;
+                    }
                     update(force);
                 }
 
@@ -273,8 +277,10 @@
 
         int state = getState();
         int lastState = mLastState;
+        boolean keyguardJustShown = mKeyguardJustShown;
         mIsFaceUnlockState = state == STATE_SCANNING_FACE;
         mLastState = state;
+        mKeyguardJustShown = false;
 
         boolean shouldUpdate = lastState != state || mForceUpdate;
         if (mBlockUpdates && canBlockUpdates()) {
@@ -283,7 +289,7 @@
         if (shouldUpdate) {
             mForceUpdate = false;
             @LockAnimIndex final int lockAnimIndex = getAnimationIndexForTransition(lastState,
-                    state, mPulsing, mDozing);
+                    state, mPulsing, mDozing, keyguardJustShown);
             boolean isAnim = lockAnimIndex != -1;
             int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(state);
 
@@ -412,7 +418,7 @@
     }
 
     private static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
-            boolean dozing) {
+            boolean dozing, boolean keyguardJustShown) {
 
         // Never animate when screen is off
         if (dozing && !pulsing) {
@@ -423,7 +429,7 @@
             return ERROR;
         } else if (oldState != STATE_LOCK_OPEN && newState == STATE_LOCK_OPEN) {
             return UNLOCK;
-        } else if (oldState == STATE_LOCK_OPEN && newState == STATE_LOCKED) {
+        } else if (oldState == STATE_LOCK_OPEN && newState == STATE_LOCKED && !keyguardJustShown) {
             return LOCK;
         } else if (newState == STATE_SCANNING_FACE) {
             return SCANNING;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 9e6454e..d93dc95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1230,6 +1230,7 @@
                 mDozeScrimController, keyguardViewMediator,
                 mScrimController, this, UnlockMethodCache.getInstance(mContext),
                 new Handler(), mKeyguardUpdateMonitor, mKeyguardBypassController);
+        putComponent(BiometricUnlockController.class, mBiometricUnlockController);
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                 getBouncerContainer(), mNotificationPanel, mBiometricUnlockController,
                 mStatusBarWindow.findViewById(R.id.lock_icon_container), mStackScroller,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
index 87ae85f..f07edf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -29,6 +30,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.DozeParameters;
 
 import org.junit.Before;
@@ -44,12 +46,14 @@
 
     private DozeWallpaperState mDozeWallpaperState;
     @Mock IWallpaperManager mIWallpaperManager;
+    @Mock BiometricUnlockController mBiometricUnlockController;
     @Mock DozeParameters mDozeParameters;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mDozeParameters);
+        mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mBiometricUnlockController,
+                mDozeParameters);
     }
 
     @Test
@@ -102,6 +106,20 @@
     }
 
     @Test
+    public void testDoesNotAnimate_whenWakeAndUnlock() throws RemoteException {
+        // Pre-conditions
+        when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+        when(mBiometricUnlockController.unlockedByWakeAndUnlock()).thenReturn(true);
+
+        mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED,
+                DozeMachine.State.DOZE_AOD);
+        clearInvocations(mIWallpaperManager);
+
+        mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH);
+        verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(0L));
+    }
+
+    @Test
     public void testTransitionTo_requestPulseIsAmbientMode() throws RemoteException {
         mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE,
                 DozeMachine.State.DOZE_REQUEST_PULSE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 5c1f473..881cc39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -64,7 +64,7 @@
     protected static final int TEST_AUTO_DISMISS_TIME = 500;
     // Number of notifications to use in tests requiring multiple notifications
     private static final int TEST_NUM_NOTIFICATIONS = 4;
-    protected static final int TEST_TIMEOUT_TIME = 10000;
+    protected static final int TEST_TIMEOUT_TIME = 15000;
     protected final Runnable TEST_TIMEOUT_RUNNABLE = () -> mTimedOut = true;
 
     private AlertingNotificationManager mAlertingNotificationManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index f8b9e68..48934da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -70,7 +70,6 @@
             setUp(statusBarWindowView, groupManager, bar, vsManager);
             mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
             mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
-            mAutoDismissNotificationDecayDozing = TEST_AUTO_DISMISS_TIME;
         }
     }
 
@@ -134,13 +133,11 @@
 
     @Test
     public void testExtendHeadsUp() {
-        when(mStatusBarStateController.isDozing()).thenReturn(true);
         mHeadsUpManager.showNotification(mEntry);
         Runnable pastNormalTimeRunnable =
                 () -> mLivesPastNormalTime = mHeadsUpManager.isAlerting(mEntry.key);
         mTestHandler.postDelayed(pastNormalTimeRunnable,
-                mHeadsUpManager.mAutoDismissNotificationDecayDozing +
-                        mHeadsUpManager.mExtensionTime / 2);
+                TEST_AUTO_DISMISS_TIME + mHeadsUpManager.mExtensionTime / 2);
         mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_TIMEOUT_TIME);
 
         mHeadsUpManager.extendHeadsUp();
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 8a639c5..90e4670 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -466,7 +466,7 @@
         // the user being changed will cause a reload of all user specific settings, which causes
         // provider initialization, and propagates changes until a steady state is reached
         mCurrentUserId = UserHandle.USER_NULL;
-        onUserChangedLocked(UserHandle.USER_SYSTEM);
+        onUserChangedLocked(ActivityManager.getCurrentUser());
 
         // initialize in-memory settings values
         onBackgroundThrottleWhitelistChangedLocked();
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
new file mode 100644
index 0000000..55fbcb4
--- /dev/null
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 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.server.om;
+
+import static android.content.Context.IDMAP_SERVICE;
+
+import static com.android.server.om.OverlayManagerService.DEBUG;
+import static com.android.server.om.OverlayManagerService.TAG;
+
+import android.os.IBinder;
+import android.os.IIdmap2;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.server.IoThread;
+
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * To prevent idmap2d from continuously running, the idmap daemon will terminate after 10
+ * seconds without a transaction.
+ **/
+class IdmapDaemon {
+    // The amount of time in milliseconds to wait after a transaction to the idmap service is made
+    // before stopping the service.
+    private static final int SERVICE_TIMEOUT_MS = 10000;
+
+    // The amount of time in milliseconds to wait when attempting to connect to idmap service.
+    private static final int SERVICE_CONNECT_TIMEOUT_MS = 5000;
+
+    private static final Object IDMAP_TOKEN = new Object();
+    private static final String IDMAP_DAEMON = "idmap2d";
+
+    private static IdmapDaemon sInstance;
+    private volatile IIdmap2 mService;
+    private final AtomicInteger mOpenedCount = new AtomicInteger();
+
+    /**
+     * An {@link AutoCloseable} connection to the idmap service. When the connection is closed or
+     * finalized, the idmap service will be stopped after a period of time unless another connection
+     * to the service is open.
+     **/
+    private class Connection implements AutoCloseable {
+        private boolean mOpened = true;
+
+        private Connection() {
+            synchronized (IDMAP_TOKEN) {
+                mOpenedCount.incrementAndGet();
+            }
+        }
+
+        @Override
+        public void close() {
+            synchronized (IDMAP_TOKEN) {
+                if (!mOpened) {
+                    return;
+                }
+
+                mOpened = false;
+                if (mOpenedCount.decrementAndGet() != 0) {
+                    // Only post the callback to stop the service if the service does not have an
+                    // open connection.
+                    return;
+                }
+
+                IoThread.getHandler().postDelayed(() -> {
+                    synchronized (IDMAP_TOKEN) {
+                        // Only stop the service if the service does not have an open connection.
+                        if (mService == null || mOpenedCount.get() != 0) {
+                            return;
+                        }
+
+                        stopIdmapService();
+                        mService = null;
+                    }
+                }, IDMAP_TOKEN, SERVICE_TIMEOUT_MS);
+            }
+        }
+    }
+
+    static IdmapDaemon getInstance() {
+        if (sInstance == null) {
+            sInstance = new IdmapDaemon();
+        }
+        return sInstance;
+    }
+
+    String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
+            int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId);
+        }
+    }
+
+    boolean removeIdmap(String overlayPath, int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.removeIdmap(overlayPath, userId);
+        }
+    }
+
+    boolean verifyIdmap(String overlayPath, int policies, boolean enforce, int userId)
+            throws Exception {
+        try (Connection connection = connect()) {
+            return mService.verifyIdmap(overlayPath, policies, enforce, userId);
+        }
+    }
+
+    String getIdmapPath(String overlayPath, int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.getIdmapPath(overlayPath, userId);
+        }
+    }
+
+    static void startIdmapService() {
+        SystemProperties.set("ctl.start", IDMAP_DAEMON);
+    }
+
+    static void stopIdmapService() {
+        SystemProperties.set("ctl.stop", IDMAP_DAEMON);
+    }
+
+    private Connection connect() throws Exception {
+        synchronized (IDMAP_TOKEN) {
+            IoThread.getHandler().removeCallbacksAndMessages(IDMAP_TOKEN);
+            if (mService != null) {
+                // Not enough time has passed to stop the idmap service. Reuse the existing
+                // interface.
+                return new Connection();
+            }
+
+            // Start the idmap service if it is not currently running.
+            startIdmapService();
+
+            // Block until the service is found.
+            FutureTask<IBinder> bindIdmap = new FutureTask<>(() -> {
+                IBinder binder = null;
+                while (binder == null) {
+                    try {
+                        binder = ServiceManager.getService(IDMAP_SERVICE);
+                        Thread.sleep(100);
+                    } catch (Exception e) {
+                        Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; "
+                                + e.getMessage());
+                    }
+                }
+                return binder;
+            });
+
+            IBinder binder;
+            try {
+                IoThread.getHandler().postAtFrontOfQueue(bindIdmap);
+                binder = bindIdmap.get(SERVICE_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            } catch (Exception rethrow) {
+                Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not found;");
+                throw rethrow;
+            }
+
+            try {
+                binder.linkToDeath(() -> {
+                    Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died");
+                }, 0);
+            } catch (RemoteException rethrow) {
+                Slog.e(TAG, "service '" + IDMAP_SERVICE + "' failed to be bound");
+                throw rethrow;
+            }
+
+            mService = IIdmap2.Stub.asInterface(binder);
+            if (DEBUG) {
+                Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
+            }
+
+            return new Connection();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index b604aa8..9b6d986 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -16,9 +16,6 @@
 
 package com.android.server.om;
 
-import static android.content.Context.IDMAP_SERVICE;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-
 import static com.android.server.om.OverlayManagerService.DEBUG;
 import static com.android.server.om.OverlayManagerService.TAG;
 
@@ -27,15 +24,11 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Build.VERSION_CODES;
-import android.os.IBinder;
 import android.os.IIdmap2;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Slog;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper;
 import com.android.server.pm.Installer;
 
@@ -51,11 +44,6 @@
  */
 class IdmapManager {
     private static final boolean FEATURE_FLAG_IDMAP2 = true;
-
-    private final Installer mInstaller;
-    private final PackageManagerHelper mPackageManager;
-    private IIdmap2 mIdmap2Service;
-
     private static final boolean VENDOR_IS_Q_OR_LATER;
     static {
         final String value = SystemProperties.get("ro.vndk.version", "29");
@@ -70,12 +58,14 @@
         VENDOR_IS_Q_OR_LATER = isQOrLater;
     }
 
+    private final Installer mInstaller;
+    private final PackageManagerHelper mPackageManager;
+    private final IdmapDaemon mIdmapDaemon;
+
     IdmapManager(final Installer installer, final PackageManagerHelper packageManager) {
         mInstaller = installer;
         mPackageManager = packageManager;
-        if (FEATURE_FLAG_IDMAP2) {
-            connectToIdmap2d();
-        }
+        mIdmapDaemon = IdmapDaemon.getInstance();
     }
 
     boolean createIdmap(@NonNull final PackageInfo targetPackage,
@@ -91,11 +81,11 @@
             if (FEATURE_FLAG_IDMAP2) {
                 int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
                 boolean enforce = enforceOverlayable(overlayPackage);
-                if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
+                if (mIdmapDaemon.verifyIdmap(overlayPath, policies, enforce, userId)) {
                     return true;
                 }
-                return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
-                    userId) != null;
+                return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
+                        enforce, userId) != null;
             } else {
                 mInstaller.idmap(targetPath, overlayPath, sharedGid);
                 return true;
@@ -113,7 +103,7 @@
         }
         try {
             if (FEATURE_FLAG_IDMAP2) {
-                return mIdmap2Service.removeIdmap(oi.baseCodePath, userId);
+                return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId);
             } else {
                 mInstaller.removeIdmap(oi.baseCodePath);
                 return true;
@@ -137,7 +127,7 @@
             final int userId) {
         if (FEATURE_FLAG_IDMAP2) {
             try {
-                return mIdmap2Service.getIdmapPath(overlayPackagePath, userId);
+                return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId);
             } catch (Exception e) {
                 Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
                         + e.getMessage());
@@ -151,35 +141,6 @@
         }
     }
 
-    private void connectToIdmap2d() {
-        IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
-        if (binder != null) {
-            try {
-                binder.linkToDeath(new IBinder.DeathRecipient() {
-                    @Override
-                    public void binderDied() {
-                        Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died; reconnecting...");
-                        connectToIdmap2d();
-                    }
-
-                }, 0);
-            } catch (RemoteException e) {
-                binder = null;
-            }
-        }
-        if (binder != null) {
-            mIdmap2Service = IIdmap2.Stub.asInterface(binder);
-            if (DEBUG) {
-                Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
-            }
-        } else {
-            Slog.w(TAG, "service '" + IDMAP_SERVICE + "' not found; trying again...");
-            BackgroundThread.getHandler().postDelayed(() -> {
-                connectToIdmap2d();
-            }, SECOND_IN_MILLIS);
-        }
-    }
-
     /**
      * Checks if overlayable and policies should be enforced on the specified overlay for backwards
      * compatibility with pre-Q overlays.
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index da69986..ce95181 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -262,6 +262,7 @@
 
             initIfNeeded();
             onSwitchUser(UserHandle.USER_SYSTEM);
+            IdmapDaemon.stopIdmapService();
 
             publishBinderService(Context.OVERLAY_SERVICE, mService);
             publishLocalService(OverlayManagerService.class, this);
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index d53f685..c1a6dbd 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -28,11 +28,14 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
 
+import static java.lang.Integer.min;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.UserHandle;
 
@@ -73,6 +76,41 @@
             };
 
     /**
+     * TargetSDK is per package. To make sure two apps int the same shared UID do not fight over
+     * what to set, always compute the combined targetSDK.
+     *
+     * @param context A context
+     * @param appInfo The app that is changed
+     * @param user The user the app belongs to
+     *
+     * @return The minimum targetSDK of all apps sharing the uid of the app
+     */
+    private static int getMinimumTargetSDK(@NonNull Context context,
+            @NonNull ApplicationInfo appInfo, @NonNull UserHandle user) {
+        PackageManager pm = context.getPackageManager();
+
+        int minimumTargetSDK = appInfo.targetSdkVersion;
+
+        String[] uidPkgs = pm.getPackagesForUid(appInfo.uid);
+        if (uidPkgs != null) {
+            for (String uidPkg : uidPkgs) {
+                if (!uidPkg.equals(appInfo.packageName)) {
+                    ApplicationInfo uidPkgInfo;
+                    try {
+                        uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        continue;
+                    }
+
+                    minimumTargetSDK = min(minimumTargetSDK, uidPkgInfo.targetSdkVersion);
+                }
+            }
+        }
+
+        return minimumTargetSDK;
+    }
+
+    /**
      * Get the policy for a soft restricted permission.
      *
      * @param context A context to use
@@ -99,12 +137,36 @@
                 final int targetSDK;
 
                 if (appInfo != null) {
-                    flags = context.getPackageManager().getPermissionFlags(permission,
-                            appInfo.packageName, user);
+                    PackageManager pm = context.getPackageManager();
+                    flags = pm.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;
+                    targetSDK = getMinimumTargetSDK(context, appInfo, user);
+
+                    boolean hasAnyRequestedLegacyExternalStorage =
+                            appInfo.hasRequestedLegacyExternalStorage();
+
+                    // hasRequestedLegacyExternalStorage is per package. To make sure two apps in
+                    // the same shared UID do not fight over what to set, always compute the
+                    // combined hasRequestedLegacyExternalStorage
+                    String[] uidPkgs = pm.getPackagesForUid(appInfo.uid);
+                    if (uidPkgs != null) {
+                        for (String uidPkg : uidPkgs) {
+                            if (!uidPkg.equals(appInfo.packageName)) {
+                                ApplicationInfo uidPkgInfo;
+                                try {
+                                    uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user);
+                                } catch (PackageManager.NameNotFoundException e) {
+                                    continue;
+                                }
+
+                                hasAnyRequestedLegacyExternalStorage |=
+                                        uidPkgInfo.hasRequestedLegacyExternalStorage();
+                            }
+                        }
+                    }
+
+                    hasRequestedLegacyExternalStorage = hasAnyRequestedLegacyExternalStorage;
                 } else {
                     flags = 0;
                     applyRestriction = false;
@@ -155,7 +217,7 @@
                     final int flags = context.getPackageManager().getPermissionFlags(permission,
                             appInfo.packageName, user);
                     isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
-                    targetSDK = appInfo.targetSdkVersion;
+                    targetSDK = getMinimumTargetSDK(context, appInfo, user);
                 } else {
                     isWhiteListed = false;
                     targetSDK = 0;
diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING
index c7e241b..17392e0 100644
--- a/services/core/java/com/android/server/policy/TEST_MAPPING
+++ b/services/core/java/com/android/server/policy/TEST_MAPPING
@@ -33,6 +33,9 @@
       "options": [
         {
           "include-filter": "android.permission2.cts.RestrictedPermissionsTest"
+        },
+        {
+          "include-filter": "android.permission2.cts.RestrictedStoragePermissionSharedUidTest"
         }
       ]
     },
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9ea6e30..f68d7c0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1633,7 +1633,7 @@
                 || !mRelayoutCalled
                 || (atoken == null && mToken.isHidden())
                 || (atoken != null && atoken.hiddenRequested)
-                || isParentWindowHidden()
+                || isParentWindowGoneForLayout()
                 || (mAnimatingExit && !isAnimatingLw())
                 || mDestroying;
     }
@@ -3840,6 +3840,11 @@
         return parent != null && parent.mHidden;
     }
 
+    private boolean isParentWindowGoneForLayout() {
+        final WindowState parent = getParentWindow();
+        return parent != null && parent.isGoneForLayoutLw();
+    }
+
     void setWillReplaceWindow(boolean animate) {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final WindowState c = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2c0a733..3505afb 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1493,6 +1493,12 @@
     }
 
     void detachChildren() {
+
+        // Do not detach children of starting windows, as their lifecycle is well under control and
+        // it may lead to issues in case we relaunch when we just added the starting window.
+        if (mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
+            return;
+        }
         if (mSurfaceController != null) {
             mSurfaceController.detachChildren();
         }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index cd659e2..d37c4a2 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -190,7 +190,7 @@
      * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in
      * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides
      * the network info in the form of a {@link android.net.NetworkInfo}. A third extra provides
-     * the details of the group.
+     * the details of the group and may contain a {@code null}.
      *
      * All of these permissions are required to receive this broadcast:
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and