Merge "Reduce duration of AOD headsup" into qt-r1-dev
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 28d5402..52ec1f0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -30,7 +30,7 @@
  */
 @ProvidesInterface(version = FalsingManager.VERSION)
 public interface FalsingManager {
-    int VERSION = 1;
+    int VERSION = 2;
 
     void onSucccessfulUnlock();
 
@@ -103,4 +103,6 @@
     void onTouchEvent(MotionEvent ev, int width, int height);
 
     void dump(PrintWriter pw);
+
+    void cleanup();
 }
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/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
index 67dfdca..fba0d50 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
@@ -168,6 +168,7 @@
                     .append("enabled=").append(isEnabled() ? 1 : 0)
                     .append(" mScreenOn=").append(mScreenOn ? 1 : 0)
                     .append(" mState=").append(StatusBarState.toShortString(mState))
+                    .append(" mShowingAod=").append(mShowingAod ? 1 : 0)
                     .toString()
             );
         }
@@ -550,6 +551,14 @@
         pw.println();
     }
 
+    @Override
+    public void cleanup() {
+        mSensorManager.unregisterListener(mSensorEventListener);
+        mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
+        Dependency.get(StatusBarStateController.class).removeCallback(mStatusBarStateListener);
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mKeyguardUpdateCallback);
+    }
+
     public Uri reportRejectedTouch() {
         if (mDataCollector.isEnabled()) {
             return mDataCollector.reportRejectedTouch();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 3cc8ec9a..8210951 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -65,6 +65,7 @@
             public void onPluginConnected(FalsingPlugin plugin, Context context) {
                 FalsingManager pluginFalsingManager = plugin.getFalsingManager(context);
                 if (pluginFalsingManager != null) {
+                    mInternalFalsingManager.cleanup();
                     mInternalFalsingManager = pluginFalsingManager;
                 }
             }
@@ -290,4 +291,9 @@
     public void dump(PrintWriter pw) {
         mInternalFalsingManager.dump(pw);
     }
+
+    @Override
+    public void cleanup() {
+        mInternalFalsingManager.cleanup();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index 00f35aa..cee01a4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -324,6 +324,11 @@
     public void dump(PrintWriter printWriter) {
     }
 
+    @Override
+    public void cleanup() {
+        unregisterSensors();
+    }
+
     static void logDebug(String msg) {
         logDebug(msg, null);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 3c9d4a9..ae6dac5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -50,9 +50,23 @@
      */
     void onSlpiTap(float x, float y);
 
+    /**
+     * Artificially dim down the the display by changing scrim opacities.
+     * @param scrimOpacity opacity from 0 to 1.
+     */
     default void setAodDimmingScrim(float scrimOpacity) {}
+
+    /**
+     * Sets the actual display brightness.
+     * @param value from 0 to 255.
+     */
     void setDozeScreenBrightness(int value);
 
+    /**
+     * Makes scrims black and changes animation durations.
+     */
+    default void prepareForGentleWakeUp() {}
+
     void onIgnoreTouchWhilePulsing(boolean ignore);
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 5be097c..38ee2fe 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -82,7 +82,10 @@
         boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
         boolean pulseEnding = oldState  == DozeMachine.State.DOZE_PULSE_DONE
                 && newState == DozeMachine.State.DOZE_AOD;
-        if (messagePending || oldState == DozeMachine.State.INITIALIZED || pulseEnding) {
+        boolean turningOn = (oldState == DozeMachine.State.DOZE_AOD_PAUSED
+                || oldState  == DozeMachine.State.DOZE) && newState == DozeMachine.State.DOZE_AOD;
+        boolean justInitialized = oldState == DozeMachine.State.INITIALIZED;
+        if (messagePending || justInitialized || pulseEnding || turningOn) {
             // During initialization, we hide the navigation bar. That is however only applied after
             // a traversal; setting the screen state here is immediate however, so it can happen
             // that the screen turns on again before the navigation bar is hidden. To work around
@@ -91,7 +94,7 @@
 
             // Delay screen state transitions even longer while animations are running.
             boolean shouldDelayTransition = newState == DozeMachine.State.DOZE_AOD
-                    && mParameters.shouldControlScreenOff();
+                    && mParameters.shouldControlScreenOff() && !turningOn;
 
             if (shouldDelayTransition) {
                 mWakeLock.setAcquired(true);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 63de960..8ef01e8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -201,7 +201,7 @@
             // Let's prepare the display to wake-up by drawing black.
             // This will cover the hardware wake-up sequence, where the display
             // becomes black for a few frames.
-            mDozeHost.setAodDimmingScrim(255f);
+            mDozeHost.setAodDimmingScrim(1f);
         }
         mMachine.wakeUp();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 51e96d2..e877d44 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -130,6 +130,7 @@
                 break;
             case DOZE:
             case DOZE_AOD_PAUSED:
+                mHost.prepareForGentleWakeUp();
                 unscheduleTimeTick();
                 break;
             case DOZE_REQUEST_PULSE:
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 ea25ca8..930f57e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -467,8 +467,11 @@
         }
         if (mStatusBarKeyguardViewManager.isShowing()) {
             if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) {
-                return bypass && !mKeyguardBypassController.canPlaySubtleWindowAnimations()
-                        ? MODE_UNLOCK_COLLAPSING : MODE_UNLOCK_FADING;
+                if (bypass && mKeyguardBypassController.canPlaySubtleWindowAnimations()) {
+                    return MODE_UNLOCK_FADING;
+                } else {
+                    return MODE_DISMISS_BOUNCER;
+                }
             } else if (unlockingAllowed) {
                 return bypass ? MODE_UNLOCK_FADING : MODE_NONE;
             } else {
@@ -568,6 +571,13 @@
     }
 
     /**
+     * Successful authentication with fingerprint, face, or iris when the lockscreen fades away
+     */
+    public boolean isUnlockFading() {
+        return mMode == MODE_UNLOCK_FADING;
+    }
+
+    /**
      * Translates biometric source type for logging purpose.
      */
     private int toSubtype(BiometricSourceType biometricSourceType) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index c88b22b..0aec2b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -167,4 +167,8 @@
         pw.print("  qSExpanded: "); pw.println(qSExpanded)
         pw.print("  bouncerShowing: "); pw.println(bouncerShowing)
     }
+
+    companion object {
+        const val BYPASS_PANEL_FADE_DURATION = 67
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 3f38c04..1aec5e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -487,6 +487,20 @@
     }
 
     /**
+     * Set front scrim to black, cancelling animations, in order to prepare to fade them
+     * away once the display turns on.
+     */
+    public void prepareForGentleWakeUp() {
+        if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()) {
+            mCurrentInFrontAlpha = 1f;
+            mAnimateChange = false;
+            updateScrims();
+            mAnimateChange = true;
+            mAnimationDuration = ANIMATION_DURATION_LONG;
+        }
+    }
+
+    /**
      * If the lock screen sensor is active.
      */
     public void setWakeLockScreenSensorActive(boolean active) {
@@ -932,6 +946,12 @@
         }
     }
 
+    public void setUnlockIsFading(boolean unlockFading) {
+        for (ScrimState state : ScrimState.values()) {
+            state.setUnlockIsFading(unlockFading);
+        }
+    }
+
     public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
         for (ScrimState state : ScrimState.values()) {
             state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index d152ecd..763e0d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -147,7 +147,9 @@
         public void prepare(ScrimState previousState) {
             mCurrentBehindAlpha = 0;
             mCurrentInFrontAlpha = 0;
-            mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION;
+            mAnimationDuration = mUnlockIsFading
+                    ? KeyguardBypassController.BYPASS_PANEL_FADE_DURATION
+                    : StatusBar.FADE_KEYGUARD_DURATION;
             mAnimateChange = !mLaunchingAffordanceWithPreview;
 
             if (previousState == ScrimState.AOD) {
@@ -198,6 +200,7 @@
     boolean mHasBackdrop;
     boolean mLaunchingAffordanceWithPreview;
     boolean mWakeLockScreenSensorActive;
+    boolean mUnlockIsFading;
 
     ScrimState(int index) {
         mIndex = index;
@@ -285,4 +288,8 @@
     public void setWakeLockScreenSensorActive(boolean active) {
         mWakeLockScreenSensorActive = active;
     }
+
+    public void setUnlockIsFading(boolean unlockIsFading) {
+        mUnlockIsFading = unlockIsFading;
+    }
 }
\ No newline at end of file
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 fb8eca1..9e6454e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3840,6 +3840,7 @@
 
     public void notifyBiometricAuthModeChanged() {
         updateDozing();
+        mScrimController.setUnlockIsFading(mBiometricUnlockController.isUnlockFading());
         updateScrimController();
         mStatusBarWindow.onBiometricAuthModeChanged(mBiometricUnlockController.isWakeAndUnlock(),
                 mBiometricUnlockController.isBiometricUnlock());
@@ -3851,7 +3852,8 @@
 
         // We don't want to end up in KEYGUARD state when we're unlocking with
         // fingerprint from doze. We should cross fade directly from black.
-        boolean wakeAndUnlocking = mBiometricUnlockController.isWakeAndUnlock();
+        boolean unlocking = mBiometricUnlockController.isWakeAndUnlock()
+                || mKeyguardMonitor.isKeyguardFadingAway();
 
         // Do not animate the scrim expansion when triggered by the fingerprint sensor.
         mScrimController.setExpansionAffectsAlpha(
@@ -3876,9 +3878,9 @@
         } else if (isPulsing()) {
             mScrimController.transitionTo(ScrimState.PULSING,
                     mDozeScrimController.getScrimCallback());
-        } else if (mDozing && !wakeAndUnlocking) {
+        } else if (mDozing && !unlocking) {
             mScrimController.transitionTo(ScrimState.AOD);
-        } else if (mIsKeyguard && !wakeAndUnlocking) {
+        } else if (mIsKeyguard && !unlocking) {
             mScrimController.transitionTo(ScrimState.KEYGUARD);
         } else if (mBubbleController.isStackExpanded()) {
             mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
@@ -4119,6 +4121,11 @@
             mScrimController.setAodFrontScrimAlpha(scrimOpacity);
         }
 
+        @Override
+        public void prepareForGentleWakeUp() {
+            mScrimController.prepareForGentleWakeUp();
+        }
+
         private void dispatchTap(View view, float x, float y) {
             long now = SystemClock.elapsedRealtime();
             dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index da85039..1321784 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -84,7 +84,6 @@
     // make everything a bit slower to bridge a gap until the user is unlocked and home screen has
     // dranw its first frame.
     private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
-    private static final long BYPASS_PANEL_FADE_DURATION = 67;
 
     private static String TAG = "StatusBarKeyguardViewManager";
 
@@ -269,7 +268,7 @@
         boolean keyguardWithoutQs = mStatusBarStateController.getState() == StatusBarState.KEYGUARD
                 && !mNotificationPanelView.isQsExpanded();
         boolean lockVisible = (mBouncer.isShowing() || keyguardWithoutQs)
-                && !mBouncer.isAnimatingAway();
+                && !mBouncer.isAnimatingAway() && !mKeyguardMonitor.isKeyguardFadingAway();
 
         if (mLastLockVisible != lockVisible) {
             mLastLockVisible = lockVisible;
@@ -278,8 +277,14 @@
                         AppearAnimationUtils.DEFAULT_APPEAR_DURATION /* duration */,
                         0 /* delay */);
             } else {
+                final long duration;
+                if (needsBypassFading()) {
+                    duration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION;
+                } else {
+                    duration = AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2;
+                }
                 CrossFadeHelper.fadeOut(mLockIconContainer,
-                        AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2 /* duration */,
+                        duration /* duration */,
                         0 /* delay */, null /* runnable */);
             }
         }
@@ -566,7 +571,7 @@
                 if (needsBypassFading()) {
                     ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
                             mNotificationContainer,
-                            BYPASS_PANEL_FADE_DURATION,
+                            KeyguardBypassController.BYPASS_PANEL_FADE_DURATION,
                                     () -> {
                         mStatusBar.hideKeyguard();
                         onKeyguardFadedAway();
@@ -582,7 +587,7 @@
                     if (needsBypassFading()) {
                         ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
                                 mNotificationContainer,
-                                BYPASS_PANEL_FADE_DURATION,
+                                KeyguardBypassController.BYPASS_PANEL_FADE_DURATION,
                                 () -> {
                                     mStatusBar.hideKeyguard();
                                 });
@@ -601,6 +606,7 @@
                     mBiometricUnlockController.finishKeyguardFadingAway();
                 }
             }
+            updateLockIcon();
             updateStates();
             mStatusBarWindowController.setKeyguardShowing(false);
             mViewMediatorCallback.keyguardGone();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 6feff9c..eb8ef09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -155,7 +155,7 @@
                 false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
                 null /* rawValues */);
 
-        verify(mHost).setAodDimmingScrim(eq(255f));
+        verify(mHost).setAodDimmingScrim(eq(1f));
         verify(mMachine).wakeUp();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index a99dc7f..7d9920d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -192,6 +194,34 @@
     }
 
     @Test
+    public void onBiometricAuthenticated_whenBypassOnBouncer_dismissBouncer() {
+        reset(mKeyguardBypassController);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+                BiometricSourceType.FACE);
+
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
+    }
+
+    @Test
+    public void onBiometricAuthenticated_whenBypassOnBouncer_respectsCanPlaySubtleAnim() {
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+                BiometricSourceType.FACE);
+
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING);
+    }
+
+    @Test
     public void onBiometricAuthenticated_whenFaceAndPulsing_dontDismissKeyguard() {
         reset(mUpdateMonitor);
         reset(mStatusBarKeyguardViewManager);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bd198dd..d358f9a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -397,7 +397,7 @@
 
     // for enabling and disabling notification pulse behavior
     boolean mScreenOn = true;
-    protected boolean mInCall = false;
+    protected boolean mInCallStateOffHook = false;
     boolean mNotificationPulseEnabled;
 
     private Uri mInCallNotificationUri;
@@ -1292,7 +1292,7 @@
                 mScreenOn = false;
                 updateNotificationPulse();
             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
-                mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
+                mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK
                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
                 updateNotificationPulse();
             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
@@ -5710,7 +5710,7 @@
                     }
                     if (DBG) Slog.v(TAG, "Interrupting!");
                     if (hasValidSound) {
-                        if (mInCall) {
+                        if (isInCall()) {
                             playInCallNotification();
                             beep = true;
                         } else {
@@ -5724,7 +5724,7 @@
                     final boolean ringerModeSilent =
                             mAudioManager.getRingerModeInternal()
                                     == AudioManager.RINGER_MODE_SILENT;
-                    if (!mInCall && hasValidVibrate && !ringerModeSilent) {
+                    if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
                         buzz = playVibration(record, vibration, hasValidSound);
                         if(buzz) {
                             mVibrateNotificationKey = key;
@@ -5812,7 +5812,7 @@
             return false;
         }
         // not if in call or the screen's on
-        if (mInCall || mScreenOn) {
+        if (isInCall() || mScreenOn) {
             return false;
         }
 
@@ -6913,7 +6913,7 @@
         }
 
         // Don't flash while we are in a call or screen is on
-        if (ledNotification == null || mInCall || mScreenOn) {
+        if (ledNotification == null || isInCall() || mScreenOn) {
             mNotificationLight.turnOff();
         } else {
             NotificationRecord.Light light = ledNotification.getLight();
@@ -7381,6 +7381,18 @@
         }
     }
 
+    private boolean isInCall() {
+        if (mInCallStateOffHook) {
+            return true;
+        }
+        int audioMode = mAudioManager.getMode();
+        if (audioMode == AudioManager.MODE_IN_CALL
+                || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
+            return true;
+        }
+        return false;
+    }
+
     public class NotificationAssistants extends ManagedServices {
         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 7692977..6491360 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -921,8 +921,9 @@
         return ResolverActivity.class.getName().equals(className);
     }
 
-    boolean isResolverActivity() {
-        return isResolverActivity(mActivityComponent.getClassName());
+    boolean isResolverOrDelegateActivity() {
+        return isResolverActivity(mActivityComponent.getClassName()) || Objects.equals(
+                mActivityComponent, mAtmService.mStackSupervisor.getSystemChooserActivity());
     }
 
     boolean isResolverOrChildActivity() {
@@ -1251,7 +1252,8 @@
                 && intent.getType() == null;
     }
 
-    private boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
+    @VisibleForTesting
+    boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
         if (uid == Process.myUid() || uid == 0) {
             // System process can launch home activity.
             return true;
@@ -1261,8 +1263,8 @@
         if (recentTasks != null && recentTasks.isCallerRecents(uid)) {
             return true;
         }
-        // Resolver activity can launch home activity.
-        return sourceRecord != null && sourceRecord.isResolverActivity();
+        // Resolver or system chooser activity can launch home activity.
+        return sourceRecord != null && sourceRecord.isResolverOrDelegateActivity();
     }
 
     /**
@@ -1281,7 +1283,7 @@
             ActivityOptions options, ActivityRecord sourceRecord) {
         int activityType = ACTIVITY_TYPE_UNDEFINED;
         if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord))
-                && isHomeIntent(intent) && !isResolverActivity()) {
+                && isHomeIntent(intent) && !isResolverOrDelegateActivity()) {
             // This sure looks like a home activity!
             activityType = ACTIVITY_TYPE_HOME;
 
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 19916bc..3550ebf 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -130,6 +130,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.ReferrerIntent;
@@ -323,6 +324,12 @@
     boolean mUserLeaving = false;
 
     /**
+     * The system chooser activity which worked as a delegate of
+     * {@link com.android.internal.app.ResolverActivity}.
+     */
+    private ComponentName mSystemChooserActivity;
+
+    /**
      * We don't want to allow the device to go to sleep while in the process
      * of launching an activity.  This is primarily to allow alarm intent
      * receivers to launch an activity and get that to run before the device
@@ -469,6 +476,14 @@
         return mKeyguardController;
     }
 
+    ComponentName getSystemChooserActivity() {
+        if (mSystemChooserActivity == null) {
+            mSystemChooserActivity = ComponentName.unflattenFromString(
+                    mService.mContext.getResources().getString(R.string.config_chooserActivity));
+        }
+        return mSystemChooserActivity;
+    }
+
     void setRecentTasks(RecentTasks recentTasks) {
         mRecentTasks = recentTasks;
         mRecentTasks.registerCallback(this);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index eda9d24..b0ca0af 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1979,8 +1979,8 @@
             // Also put noDisplay activities in the source task. These by itself can be placed
             // in any task/stack, however it could launch other activities like ResolverActivity,
             // and we want those to stay in the original task.
-            if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
-                    && mSourceRecord.inFreeformWindowingMode())  {
+            if ((mStartActivity.isResolverOrDelegateActivity() || mStartActivity.noDisplay)
+                    && mSourceRecord != null && mSourceRecord.inFreeformWindowingMode()) {
                 mAddingToTask = true;
             }
         }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 6061d51..8c3373f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -156,7 +156,7 @@
         mService.setUsageStats(mUsageStats);
         mService.setAccessibilityManager(accessibilityManager);
         mService.mScreenOn = false;
-        mService.mInCall = false;
+        mService.mInCallStateOffHook = false;
         mService.mNotificationPulseEnabled = true;
     }
 
@@ -681,7 +681,7 @@
         mService.buzzBeepBlinkLocked(r);
         Mockito.reset(mRingtonePlayer);
 
-        mService.mInCall = true;
+        mService.mInCallStateOffHook = true;
         mService.buzzBeepBlinkLocked(r);
 
         verify(mService, times(1)).playInCallNotification();
@@ -1137,7 +1137,7 @@
 
     @Test
     public void testLightsInCall() {
-        mService.mInCall = true;
+        mService.mInCallStateOffHook = true;
         NotificationRecord r = getLightsNotification();
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8fbb7f5..4608c3b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.Process.NOBODY_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_90;
@@ -40,6 +41,8 @@
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -54,8 +57,10 @@
 import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.PauseActivityItem;
+import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.MergedConfiguration;
@@ -67,6 +72,7 @@
 
 import androidx.test.filters.MediumTest;
 
+import com.android.internal.R;
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Before;
@@ -605,6 +611,15 @@
         assertNull(mActivity.pendingOptions);
     }
 
+    @Test
+    public void testCanLaunchHomeActivityFromChooser() {
+        ComponentName chooserComponent = ComponentName.unflattenFromString(
+                Resources.getSystem().getString(R.string.config_chooserActivity));
+        ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
+                chooserComponent).build();
+        assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
+    }
+
     /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
     private void prepareFixedAspectRatioUnresizableActivity() {
         setupDisplayContentForCompatDisplayInsets();