Merge "Move most of the shade codebase into its own package" into tm-qpr-dev
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 877e7d3..57dacd0 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -263,6 +263,11 @@
         // After orientation change, the onResume can come in before the top Activity has
         // left, so if the Activity is not top, wait a second for the top Activity to exit.
         if (mEnterTransitionCoordinator == null || activity.isTopOfTask()) {
+            if (mEnterTransitionCoordinator != null) {
+                mEnterTransitionCoordinator.runAfterTransitionsComplete(() -> {
+                    mEnterTransitionCoordinator = null;
+                });
+            }
             restoreExitedViews();
             restoreReenteringViews();
         } else {
@@ -271,6 +276,11 @@
                 public void run() {
                     if (mEnterTransitionCoordinator == null ||
                             mEnterTransitionCoordinator.isWaitingForRemoteExit()) {
+                        if (mEnterTransitionCoordinator != null) {
+                            mEnterTransitionCoordinator.runAfterTransitionsComplete(() -> {
+                                mEnterTransitionCoordinator = null;
+                            });
+                        }
                         restoreExitedViews();
                         restoreReenteringViews();
                     } else if (mEnterTransitionCoordinator.isReturning()) {
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index e8e4fc9..f2525d1 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -22,10 +22,11 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArrayMap;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -41,7 +42,7 @@
 
     private final Object mLock = new Object();
     private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mPrograms =
-            new HashMap<>();
+            new ArrayMap<>();
 
     private final List<ListCallback> mListCallbacks = new ArrayList<>();
     private final List<OnCompleteListener> mOnCompleteListeners = new ArrayList<>();
@@ -184,8 +185,14 @@
             listCallbacksCopied = new ArrayList<>(mListCallbacks);
 
             if (chunk.isPurge()) {
-                for (ProgramSelector.Identifier id : mPrograms.keySet()) {
-                    removeLocked(id, removedList);
+                Iterator<Map.Entry<ProgramSelector.Identifier, RadioManager.ProgramInfo>>
+                        programsIterator = mPrograms.entrySet().iterator();
+                while (programsIterator.hasNext()) {
+                    RadioManager.ProgramInfo removed = programsIterator.next().getValue();
+                    if (removed != null) {
+                        removedList.add(removed.getSelector().getPrimaryId());
+                    }
+                    programsIterator.remove();
                 }
             }
 
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index ac4c2ea..d377565 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -404,7 +404,7 @@
             try {
                 root.setView(view, wparams, panelParentView, userId);
             } catch (RuntimeException e) {
-                final int viewIndex = findViewLocked(view, false);
+                final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
                 // BadTokenException or InvalidDisplayException, clean up.
                 if (viewIndex >= 0) {
                     removeViewLocked(viewIndex, true);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 584beae..c191757 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -41,7 +41,6 @@
 import android.app.ActivityTaskManager;
 import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.AlarmManager;
-import android.app.PendingIntent;
 import android.app.UserSwitchObserver;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
@@ -150,11 +149,6 @@
     private static final boolean DEBUG_SPEW = false;
     private static final int BIOMETRIC_LOCKOUT_RESET_DELAY_MS = 600;
 
-    private static final String ACTION_FACE_UNLOCK_STARTED
-            = "com.android.facelock.FACE_UNLOCK_STARTED";
-    private static final String ACTION_FACE_UNLOCK_STOPPED
-            = "com.android.facelock.FACE_UNLOCK_STOPPED";
-
     // Callback messages
     private static final int MSG_TIME_UPDATE = 301;
     private static final int MSG_BATTERY_UPDATE = 302;
@@ -170,7 +164,6 @@
     private static final int MSG_FINISHED_GOING_TO_SLEEP = 320;
     private static final int MSG_STARTED_GOING_TO_SLEEP = 321;
     private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
-    private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 327;
     private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 328;
     private static final int MSG_AIRPLANE_MODE_CHANGED = 329;
     private static final int MSG_SERVICE_STATE_CHANGE = 330;
@@ -404,7 +397,6 @@
     private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
     private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
     private SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray();
-    private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
     private Map<Integer, Intent> mSecondaryLockscreenRequirement = new HashMap<Integer, Intent>();
 
     @VisibleForTesting
@@ -1131,21 +1123,6 @@
         }
     }
 
-    private void handleFaceUnlockStateChanged(boolean running, int userId) {
-        Assert.isMainThread();
-        mUserFaceUnlockRunning.put(userId, running);
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onFaceUnlockStateChanged(running, userId);
-            }
-        }
-    }
-
-    public boolean isFaceUnlockRunning(int userId) {
-        return mUserFaceUnlockRunning.get(userId);
-    }
-
     public boolean isFingerprintDetectionRunning() {
         return mFingerprintRunningState == BIOMETRIC_STATE_RUNNING;
     }
@@ -1369,16 +1346,6 @@
         }
     }
 
-    static class DisplayClientState {
-        public int clientGeneration;
-        public boolean clearing;
-        public PendingIntent intent;
-        public int playbackState;
-        public long playbackEventTime;
-    }
-
-    private DisplayClientState mDisplayClientState = new DisplayClientState();
-
     @VisibleForTesting
     protected final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
 
@@ -1452,16 +1419,6 @@
             final String action = intent.getAction();
             if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(action)) {
                 mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
-            } else if (ACTION_FACE_UNLOCK_STARTED.equals(action)) {
-                Trace.beginSection(
-                        "KeyguardUpdateMonitor.mBroadcastAllReceiver#onReceive "
-                                + "ACTION_FACE_UNLOCK_STARTED");
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_FACE_UNLOCK_STATE_CHANGED, 1,
-                        getSendingUserId()));
-                Trace.endSection();
-            } else if (ACTION_FACE_UNLOCK_STOPPED.equals(action)) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_FACE_UNLOCK_STATE_CHANGED, 0,
-                        getSendingUserId()));
             } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
                     .equals(action)) {
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED,
@@ -1938,12 +1895,6 @@
                         handleStartedWakingUp();
                         Trace.endSection();
                         break;
-                    case MSG_FACE_UNLOCK_STATE_CHANGED:
-                        Trace.beginSection(
-                                "KeyguardUpdateMonitor#handler MSG_FACE_UNLOCK_STATE_CHANGED");
-                        handleFaceUnlockStateChanged(msg.arg1 != 0, msg.arg2);
-                        Trace.endSection();
-                        break;
                     case MSG_SIM_SUBSCRIPTION_INFO_CHANGED:
                         handleSimSubscriptionInfoChanged();
                         break;
@@ -2035,8 +1986,6 @@
 
         final IntentFilter allUserFilter = new IntentFilter();
         allUserFilter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
-        allUserFilter.addAction(ACTION_FACE_UNLOCK_STARTED);
-        allUserFilter.addAction(ACTION_FACE_UNLOCK_STOPPED);
         allUserFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         allUserFilter.addAction(ACTION_USER_UNLOCKED);
         allUserFilter.addAction(ACTION_USER_STOPPED);
@@ -3347,7 +3296,6 @@
         callback.onTimeChanged();
         callback.onPhoneStateChanged(mPhoneState);
         callback.onRefreshCarrierInfo();
-        callback.onClockVisibilityChanged();
         callback.onKeyguardVisibilityChangedRaw(mKeyguardIsVisible);
         callback.onTelephonyCapable(mTelephonyCapable);
 
@@ -3524,10 +3472,6 @@
                 || state == TelephonyManager.SIM_STATE_PERM_DISABLED);
     }
 
-    public DisplayClientState getCachedDisplayClientState() {
-        return mDisplayClientState;
-    }
-
     // TODO: use these callbacks elsewhere in place of the existing notifyScreen*()
     // (KeyguardViewMediator, KeyguardHostView)
     public void dispatchStartedWakingUp() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index d420abd..99e0ce2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -111,12 +111,6 @@
     public void onKeyguardDismissAnimationFinished() { }
 
     /**
-     * Called when visibility of lockscreen clock changes, such as when
-     * obscured by a widget.
-     */
-    public void onClockVisibilityChanged() { }
-
-    /**
      * Called when the device becomes provisioned
      */
     public void onDeviceProvisioned() { }
@@ -249,11 +243,6 @@
             BiometricSourceType biometricSourceType) { }
 
     /**
-     * Called when the state of face unlock changed.
-     */
-    public void onFaceUnlockStateChanged(boolean running, int userId) { }
-
-    /**
      * Called when biometric running state changed.
      */
     public void onBiometricRunningStateChanged(boolean running,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 70e4fa3..7c816ce 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -26,8 +26,6 @@
 import android.text.format.Formatter;
 import android.util.Log;
 
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.dagger.DozeScope;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -44,8 +42,6 @@
  */
 @DozeScope
 public class DozeUi implements DozeMachine.Part {
-    // if enabled, calls dozeTimeTick() whenever the time changes:
-    private static final boolean BURN_IN_TESTING_ENABLED = false;
     private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min
     private final Context mContext;
     private final DozeHost mHost;
@@ -57,26 +53,13 @@
     private final DozeParameters mDozeParameters;
     private final DozeLog mDozeLog;
     private final StatusBarStateController mStatusBarStateController;
-    private final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback =
-            new KeyguardUpdateMonitorCallback() {
-                @Override
-                public void onTimeChanged() {
-                    if (BURN_IN_TESTING_ENABLED && mStatusBarStateController.isDozing()) {
-                        // update whenever the time changes for manual burn in testing
-                        mHost.dozeTimeTick();
-
-                        // Keep wakelock until a frame has been pushed.
-                        mHandler.post(mWakeLock.wrap(() -> {}));
-                    }
-                }
-            };
 
     private long mLastTimeTickElapsed = 0;
 
     @Inject
     public DozeUi(Context context, AlarmManager alarmManager,
             WakeLock wakeLock, DozeHost host, @Main Handler handler,
-            DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor,
+            DozeParameters params,
             StatusBarStateController statusBarStateController,
             DozeLog dozeLog) {
         mContext = context;
@@ -86,7 +69,6 @@
         mCanAnimateTransition = !params.getDisplayNeedsBlanking();
         mDozeParameters = params;
         mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler);
-        keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
         mDozeLog = dozeLog;
         mStatusBarStateController = statusBarStateController;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e65ed66..e913d2b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -556,11 +556,6 @@
         }
 
         @Override
-        public void onClockVisibilityChanged() {
-            adjustStatusBarLocked();
-        }
-
-        @Override
         public void onDeviceProvisioned() {
             sendUserPresentBroadcast();
             synchronized (KeyguardViewMediator.this) {
@@ -1193,6 +1188,7 @@
             mSystemReady = true;
             doKeyguardLocked(null);
             mUpdateMonitor.registerCallback(mUpdateCallback);
+            adjustStatusBarLocked();
             mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback);
         }
         // Most services aren't available until the system reaches the ready state, so we
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 2fb16ee..bdac888 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -424,11 +424,6 @@
         }
 
         @Override
-        public void onFaceUnlockStateChanged(boolean running, int userId) {
-            update(false /* updateAlways */);
-        }
-
-        @Override
         public void onStrongAuthStateChanged(int userId) {
             update(false /* updateAlways */);
         }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 2dc066c..84903d1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -1109,8 +1109,7 @@
 
         // THEN face unlock is not running b/c status bar state changes don't cause biometric
         // listening state to update
-        assertThat(mKeyguardUpdateMonitor.isFaceUnlockRunning(
-                KeyguardUpdateMonitor.getCurrentUser())).isEqualTo(false);
+        assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isEqualTo(false);
 
         // WHEN biometric listening state is updated
         mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
index e5a75e2..49cdfa7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
@@ -86,7 +86,7 @@
         mHandler = mHandlerThread.getThreadHandler();
 
         mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler,
-                mDozeParameters, mKeyguardUpdateMonitor, mStatusBarStateController, mDozeLog);
+                mDozeParameters, mStatusBarStateController, mDozeLog);
         mDozeUi.setDozeMachine(mMachine);
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index a78dbd6..9be9340 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -19,7 +19,9 @@
 import static android.app.ActivityManager.START_CANCELED;
 import static android.app.ActivityManager.START_SUCCESS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
 
@@ -29,6 +31,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.IApplicationThread;
 import android.content.ComponentName;
@@ -46,6 +49,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.RemoteAnimationAdapter;
+import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -536,6 +540,42 @@
                 .execute();
     }
 
+    boolean startExistingRecentsIfPossible(Intent intent, ActivityOptions options) {
+        final int activityType = mService.getRecentTasks().getRecentsComponent()
+                .equals(intent.getComponent()) ? ACTIVITY_TYPE_RECENTS : ACTIVITY_TYPE_HOME;
+        final Task rootTask = mService.mRootWindowContainer.getDefaultTaskDisplayArea()
+                .getRootTask(WINDOWING_MODE_UNDEFINED, activityType);
+        if (rootTask == null) return false;
+        final ActivityRecord r = rootTask.topRunningActivity();
+        if (r == null || r.mVisibleRequested || !r.attachedToProcess()
+                || !r.mActivityComponent.equals(intent.getComponent())
+                // Recents keeps invisible while device is locked.
+                || r.mDisplayContent.isKeyguardLocked()) {
+            return false;
+        }
+        mService.mRootWindowContainer.startPowerModeLaunchIfNeeded(true /* forceSend */, r);
+        final ActivityMetricsLogger.LaunchingState launchingState =
+                mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
+        final Task task = r.getTask();
+        mService.deferWindowLayout();
+        try {
+            task.mTransitionController.requestTransitionIfNeeded(WindowManager.TRANSIT_TO_FRONT,
+                    0 /* flags */, task, task /* readyGroupRef */,
+                    options.getRemoteTransition(), null /* displayChange */);
+            r.mTransitionController.setTransientLaunch(r,
+                    TaskDisplayArea.getRootTaskAbove(rootTask));
+            task.moveToFront("startExistingRecents");
+            task.mInResumeTopActivity = true;
+            task.resumeTopActivity(null /* prev */, options, true /* deferPause */);
+            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
+                    ActivityManager.START_TASK_TO_FRONT, false, r, options);
+        } finally {
+            task.mInResumeTopActivity = false;
+            mService.continueWindowLayout();
+        }
+        return true;
+    }
+
     void registerRemoteAnimationForNextActivityStart(String packageName,
             RemoteAnimationAdapter adapter, @Nullable IBinder launchCookie) {
         mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter, launchCookie);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index eec7789..bf19bd7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1231,6 +1231,28 @@
             @Nullable String callingFeatureId, Intent intent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode, int startFlags,
             ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
+
+        final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);
+        // A quick path (skip general intent/task resolving) to start recents animation if the
+        // recents (or home) activity is available in background.
+        if (opts != null && opts.getOriginalOptions().getTransientLaunch()
+                && isCallerRecents(Binder.getCallingUid())) {
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                synchronized (mGlobalLock) {
+                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "startExistingRecents");
+                    if (mActivityStartController.startExistingRecentsIfPossible(
+                            intent, opts.getOriginalOptions())) {
+                        return ActivityManager.START_TASK_TO_FRONT;
+                    }
+                    // Else follow the standard launch procedure.
+                }
+            } finally {
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+
         assertPackageMatchesCallingUid(callingPackage);
         enforceNotIsolatedCaller("startActivityAsUser");
         if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
@@ -1257,7 +1279,7 @@
                 .setRequestCode(requestCode)
                 .setStartFlags(startFlags)
                 .setProfilerInfo(profilerInfo)
-                .setActivityOptions(bOptions)
+                .setActivityOptions(opts)
                 .setUserId(userId)
                 .execute();
 
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 2e1d3b1..0af0462 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -120,7 +120,7 @@
             } else {
                 mTransitionOp = OP_CHANGE;
             }
-        } else if (transitionType != WindowManager.TRANSIT_NONE) {
+        } else if (displayContent.mTransitionController.isShellTransitionsEnabled()) {
             mTransitionOp = OP_APP_SWITCH;
         } else {
             mTransitionOp = OP_LEGACY;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 85be108..fe66f7a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1687,7 +1687,7 @@
                     return false;
                 }
             }
-            if (r.isState(RESUMED) && !r.getRootTask().mInResumeTopActivity) {
+            if (r.isState(RESUMED) && !r.getTask().mInResumeTopActivity) {
                 // If the activity is executing or has done the lifecycle callback, use normal
                 // rotation animation so the display info can be updated immediately (see
                 // updateDisplayAndOrientation). This prevents a compatibility issue such as
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index baa31a0..2879e33 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.CONTROL_KEYGUARD;
 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.Manifest.permission.STATUS_BAR_SERVICE;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
@@ -247,6 +248,14 @@
                 throw new SecurityException(msg);
             }
         }
+        if (options.getTransientLaunch() && !supervisor.mRecentTasks.isCallerRecents(callingUid)
+                && ActivityTaskManagerService.checkPermission(
+                        MANAGE_ACTIVITY_TASKS, callingPid, callingUid) == PERMISSION_DENIED) {
+            final String msg = "Permission Denial: starting transient launch from " + callerApp
+                    + ", pid=" + callingPid + ", uid=" + callingUid;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
         // Check if the caller is allowed to launch on the specified display area.
         final WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
         final TaskDisplayArea taskDisplayArea = daToken != null
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index f80e732..d09068b 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -600,7 +600,7 @@
         }
 
         private SurfaceAnimator startDisplayRotation() {
-            return startAnimation(initializeBuilder()
+            SurfaceAnimator animator = startAnimation(initializeBuilder()
                             .setAnimationLeashParent(mDisplayContent.getSurfaceControl())
                             .setSurfaceControl(mDisplayContent.getWindowingLayer())
                             .setParentSurfaceControl(mDisplayContent.getSurfaceControl())
@@ -609,6 +609,13 @@
                             .build(),
                     createWindowAnimationSpec(mRotateEnterAnimation),
                     this::onAnimationEnd);
+
+            // Crop the animation leash to avoid extended wallpaper from showing over
+            // mBackColorSurface
+            Rect displayBounds = mDisplayContent.getBounds();
+            mDisplayContent.getPendingTransaction()
+                    .setWindowCrop(animator.mLeash, displayBounds.width(), displayBounds.height());
+            return animator;
         }
 
         private SurfaceAnimator startScreenshotAlphaAnimation() {