diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index da7b389fbd36e..058f37a2ef389 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -36,6 +36,7 @@ import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.doze.dagger.WrappedService; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.util.sensors.AsyncSensorManager; import java.io.PrintWriter; @@ -55,6 +56,16 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi "com.android.systemui.doze.AOD_BRIGHTNESS"; protected static final String BRIGHTNESS_BUCKET = "brightness_bucket"; + /** + * Just before the screen times out from user inactivity, DisplayPowerController dims the screen + * brightness to the lower of {@link #mScreenBrightnessDim}, or the current brightness minus + * DisplayPowerController#SCREEN_DIM_MINIMUM_REDUCTION_FLOAT. + * + * This value is 0.04f * 255, which converts SCREEN_DIM_MINIMUM_REDUCTION_FLOAT to the integer + * brightness values used by doze. + */ + private static final int SCREEN_DIM_MINIMUM_REDUCTION_INT = 10; + private final Context mContext; private final DozeMachine.Service mDozeService; private final DozeHost mDozeHost; @@ -82,6 +93,8 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi */ private int mDebugBrightnessBucket = -1; + private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; + @Inject public DozeScreenBrightness(Context context, @WrappedService DozeMachine.Service service, AsyncSensorManager sensorManager, @@ -89,7 +102,8 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi AlwaysOnDisplayPolicy alwaysOnDisplayPolicy, WakefulnessLifecycle wakefulnessLifecycle, DozeParameters dozeParameters, - DockManager dockManager) { + DockManager dockManager, + UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) { mContext = context; mDozeService = service; mSensorManager = sensorManager; @@ -99,6 +113,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi mDozeHost = host; mHandler = handler; mDockManager = dockManager; + mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; mDefaultDozeBrightness = alwaysOnDisplayPolicy.defaultDozeBrightness; mScreenBrightnessDim = alwaysOnDisplayPolicy.dimBrightness; @@ -148,14 +163,15 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } } - private void updateBrightnessAndReady(boolean force) { + public void updateBrightnessAndReady(boolean force) { if (force || mRegistered || mDebugBrightnessBucket != -1) { int sensorValue = mDebugBrightnessBucket == -1 ? mLastSensorValue : mDebugBrightnessBucket; int brightness = computeBrightness(sensorValue); boolean brightnessReady = brightness > 0; if (brightnessReady) { - mDozeService.setDozeScreenBrightness(clampToUserSetting(brightness)); + mDozeService.setDozeScreenBrightness( + clampToDimBrightnessForScreenOff(clampToUserSetting(brightness))); } int scrimOpacity = -1; @@ -207,13 +223,21 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi /** * Clamp the brightness to the dim brightness value used by PowerManagerService just before the * device times out and goes to sleep, if we are sleeping from a timeout. This ensures that we - * don't raise the brightness back to the user setting before playing the screen off animation. + * don't raise the brightness back to the user setting before or during the screen off + * animation. */ private int clampToDimBrightnessForScreenOff(int brightness) { - if (mDozeParameters.shouldControlUnlockedScreenOff() + if (mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying() && mWakefulnessLifecycle.getLastSleepReason() == PowerManager.GO_TO_SLEEP_REASON_TIMEOUT) { - return Math.min(mScreenBrightnessDim, brightness); + return Math.max( + PowerManager.BRIGHTNESS_OFF, + // Use the lower of either the dim brightness, or the current brightness reduced + // by the minimum dim amount. This is the same logic used in + // DisplayPowerController#updatePowerState to apply a minimum dim amount. + Math.min( + brightness - SCREEN_DIM_MINIMUM_REDUCTION_INT, + mScreenBrightnessDim)); } else { return brightness; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java index 8f1486b0c7cbb..038be48b53eeb 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java @@ -77,6 +77,7 @@ public class DozeScreenState implements DozeMachine.Part { private final Provider mUdfpsControllerProvider; @Nullable private UdfpsController mUdfpsController; private final DozeLog mDozeLog; + private final DozeScreenBrightness mDozeScreenBrightness; private int mPendingScreenState = Display.STATE_UNKNOWN; private SettableWakeLock mWakeLock; @@ -90,7 +91,8 @@ public class DozeScreenState implements DozeMachine.Part { WakeLock wakeLock, AuthController authController, Provider udfpsControllerProvider, - DozeLog dozeLog) { + DozeLog dozeLog, + DozeScreenBrightness dozeScreenBrightness) { mDozeService = service; mHandler = handler; mParameters = parameters; @@ -99,6 +101,7 @@ public class DozeScreenState implements DozeMachine.Part { mAuthController = authController; mUdfpsControllerProvider = udfpsControllerProvider; mDozeLog = dozeLog; + mDozeScreenBrightness = dozeScreenBrightness; updateUdfpsController(); if (mUdfpsController == null) { @@ -204,6 +207,12 @@ public class DozeScreenState implements DozeMachine.Part { if (screenState != Display.STATE_UNKNOWN) { if (DEBUG) Log.d(TAG, "setDozeScreenState(" + screenState + ")"); mDozeService.setDozeScreenState(screenState); + if (screenState == Display.STATE_DOZE) { + // If we're entering doze, update the doze screen brightness. We might have been + // clamping it to the dim brightness during the screen off animation, and we should + // now change it to the brightness we actually want according to the sensor. + mDozeScreenBrightness.updateBrightnessAndReady(false /* force */); + } mPendingScreenState = Display.STATE_UNKNOWN; mWakeLock.setAcquired(false); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index e0520b406a0ae..b8d465a8c8817 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -51,6 +51,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeThreadFactory; import com.android.systemui.util.sensors.AsyncSensorManager; @@ -86,6 +87,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { DozeParameters mDozeParameters; @Mock DockManager mDockManager; + @Mock + private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor); @@ -113,7 +116,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { mSensor = fakeSensorManager.getFakeLightSensor(); mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, Optional.of(mSensor.getSensor()), mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); + mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager, + mUnlockedScreenOffAnimationController); } @Test @@ -211,7 +215,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception { mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, Optional.empty() /* sensor */, mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); + mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager, + mUnlockedScreenOffAnimationController); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE); reset(mDozeHost); @@ -240,7 +245,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { public void testNullSensor() throws Exception { mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, Optional.empty() /* sensor */, mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); + mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager, + mUnlockedScreenOffAnimationController); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); @@ -313,13 +319,14 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn( PowerManager.GO_TO_SLEEP_REASON_TIMEOUT); when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true); + when(mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()).thenReturn(true); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE); // If we're dozing after a timeout, and playing the unlocked screen animation, we should - // stay at dim brightness, because the screen dims just before timeout. - assertEquals(mServiceFake.screenBrightness, DIM_BRIGHTNESS); + // stay at or below dim brightness, because the screen dims just before timeout. + assertTrue(mServiceFake.screenBrightness <= DIM_BRIGHTNESS); } @Test @@ -327,6 +334,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn( PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON); when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true); + when(mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()).thenReturn(true); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE); @@ -341,6 +349,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn( PowerManager.GO_TO_SLEEP_REASON_TIMEOUT); when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false); + when(mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()).thenReturn(false); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java index 150ab7700e4be..3e19cc436dca6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java @@ -82,6 +82,8 @@ public class DozeScreenStateTest extends SysuiTestCase { private UdfpsController mUdfpsController; @Mock private DozeLog mDozeLog; + @Mock + private DozeScreenBrightness mDozeScreenBrightness; @Before public void setUp() throws Exception { @@ -96,7 +98,8 @@ public class DozeScreenStateTest extends SysuiTestCase { mHandlerFake = new FakeHandler(Looper.getMainLooper()); mWakeLock = new WakeLockFake(); mScreen = new DozeScreenState(mServiceFake, mHandlerFake, mDozeHost, mDozeParameters, - mWakeLock, mAuthController, mUdfpsControllerProvider, mDozeLog); + mWakeLock, mAuthController, mUdfpsControllerProvider, mDozeLog, + mDozeScreenBrightness); } @Test diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index f3ba56a03aef9..08f3b1a8c6e01 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3387,9 +3387,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final List actions = r.pictureInPictureArgs.getActions(); mRootWindowContainer.moveActivityToPinnedRootTask( r, "enterPictureInPictureMode"); - final Task rootTask = r.getRootTask(); - rootTask.setPictureInPictureAspectRatio(aspectRatio); - rootTask.setPictureInPictureActions(actions); + final Task task = r.getTask(); + task.setPictureInPictureAspectRatio(aspectRatio); + task.setPictureInPictureActions(actions); + + // Continue the pausing process after entering pip. + if (task.getPausingActivity() == r) { + task.schedulePauseActivity(r, false /* userLeaving */, + false /* pauseImmediately */, "auto-pip"); + } } }; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index c3074fab0a1a5..c068fd1a5f6e3 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -5771,23 +5771,8 @@ class Task extends WindowContainer { + "directly: %s", prev); didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs); - mPausingActivity = null; } else { - ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev); - try { - EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), - prev.shortComponentName, "userLeaving=" + userLeaving, reason); - - mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), - prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, - prev.configChangeFlags, pauseImmediately)); - } catch (Exception e) { - // Ignore exception, if process died other code will cleanup. - Slog.w(TAG, "Exception thrown during pause", e); - mPausingActivity = null; - mLastPausedActivity = null; - mTaskSupervisor.mNoHistoryActivities.remove(prev); - } + schedulePauseActivity(prev, userLeaving, pauseImmediately, reason); } } else { mPausingActivity = null; @@ -5802,7 +5787,7 @@ class Task extends WindowContainer { } // If already entered PIP mode, no need to keep pausing. - if (mPausingActivity != null && !didAutoPip) { + if (mPausingActivity != null) { // Have the window manager pause its key dispatching until the new // activity has started. If we're pausing the activity just because // the screen is being turned off and the UI is sleeping, don't interrupt @@ -5835,6 +5820,25 @@ class Task extends WindowContainer { } } + void schedulePauseActivity(ActivityRecord prev, boolean userLeaving, + boolean pauseImmediately, String reason) { + ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev); + try { + EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), + prev.shortComponentName, "userLeaving=" + userLeaving, reason); + + mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), + prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, + prev.configChangeFlags, pauseImmediately)); + } catch (Exception e) { + // Ignore exception, if process died other code will cleanup. + Slog.w(TAG, "Exception thrown during pause", e); + mPausingActivity = null; + mLastPausedActivity = null; + mTaskSupervisor.mNoHistoryActivities.remove(prev); + } + } + @VisibleForTesting void completePauseLocked(boolean resumeNext, ActivityRecord resuming) { // Complete the pausing process of a pausing activity, so it doesn't make sense to