diff options
author | 2024-03-28 04:54:53 +0000 | |
---|---|---|
committer | 2024-03-28 04:54:53 +0000 | |
commit | 86c54353bda358ee41ccdd799a1fc1d80fed750f (patch) | |
tree | e1a49aa1ca8951ca7d33078c50624ffa598a74d9 | |
parent | 7fec47f8836ab6987aa8e36fd7d0d303f720c464 (diff) | |
parent | 548320ffa8b0afbbfc6d59710e5ebef181aa1784 (diff) |
Merge "Skip sleep-token when switching display which will be on" into 24D1-dev
3 files changed, 113 insertions, 6 deletions
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 14fb17c09031..65bf24179bea 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -38,6 +38,17 @@ flag { } flag { + name: "skip_sleeping_when_switching_display" + namespace: "windowing_frontend" + description: "Reduce unnecessary visibility or lifecycle changes when changing fold state" + bug: "303241079" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "introduce_smoother_dimmer" namespace: "windowing_frontend" description: "Refactor dim to fix flickers" diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index ec4b38b10af2..994f50cc1f07 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -530,6 +530,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { // TODO(b/178103325): Track sleep/requested sleep for every display. volatile boolean mRequestedOrSleepingDefaultDisplay; + /** + * This is used to check whether to invoke {@link #updateScreenOffSleepToken} when screen is + * turned off. E.g. if it is false when screen is turned off and the display is swapping, it + * is expected that the screen will be on in a short time. Then it is unnecessary to acquire + * screen-off-sleep-token, so it can avoid intermediate visibility or lifecycle changes. + */ + volatile boolean mIsGoingToSleepDefaultDisplay; + volatile boolean mRecentsVisible; volatile boolean mNavBarVirtualKeyHapticFeedbackEnabled = true; volatile boolean mPictureInPictureVisible; @@ -5464,6 +5472,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mRequestedOrSleepingDefaultDisplay = true; + mIsGoingToSleepDefaultDisplay = true; + + // In case startedGoingToSleep is called after screenTurnedOff (the source caller is in + // order but the methods run on different threads) and updateScreenOffSleepToken was + // skipped. Then acquire sleep token if screen was off. + if (!mDefaultDisplayPolicy.isScreenOnFully() && !mDefaultDisplayPolicy.isScreenOnEarly() + && com.android.window.flags.Flags.skipSleepingWhenSwitchingDisplay()) { + updateScreenOffSleepToken(true /* acquire */, false /* isSwappingDisplay */); + } if (mKeyguardDelegate != null) { mKeyguardDelegate.onStartedGoingToSleep(pmSleepReason); @@ -5487,6 +5504,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000); mRequestedOrSleepingDefaultDisplay = false; + mIsGoingToSleepDefaultDisplay = false; mDefaultDisplayPolicy.setAwake(false); // We must get this work done here because the power manager will drop @@ -5522,7 +5540,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } EventLogTags.writeScreenToggled(1); - + mIsGoingToSleepDefaultDisplay = false; mDefaultDisplayPolicy.setAwake(true); // Since goToSleep performs these functions synchronously, we must @@ -5624,7 +5642,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (DEBUG_WAKEUP) Slog.i(TAG, "Display" + displayId + " turned off..."); if (displayId == DEFAULT_DISPLAY) { - updateScreenOffSleepToken(true, isSwappingDisplay); + if (!isSwappingDisplay || mIsGoingToSleepDefaultDisplay + || !com.android.window.flags.Flags.skipSleepingWhenSwitchingDisplay()) { + updateScreenOffSleepToken(true /* acquire */, isSwappingDisplay); + } mRequestedOrSleepingDefaultDisplay = false; mDefaultDisplayPolicy.screenTurnedOff(); synchronized (mLock) { diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java index 29467f259ac3..a80e2f8ae28c 100644 --- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java @@ -16,10 +16,14 @@ package com.android.server.policy; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManagerGlobal.ADD_OKAY; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -33,18 +37,27 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import android.app.ActivityManager; import android.app.AppOpsManager; +import android.content.Context; +import android.os.PowerManager; import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.filters.SmallTest; +import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; +import com.android.server.wm.DisplayPolicy; +import com.android.server.wm.DisplayRotation; +import com.android.server.wm.WindowManagerInternal; import org.junit.After; import org.junit.Before; @@ -64,16 +77,27 @@ public class PhoneWindowManagerTests { public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); PhoneWindowManager mPhoneWindowManager; + private ActivityTaskManagerInternal mAtmInternal; + private Context mContext; @Before public void setUp() { mPhoneWindowManager = spy(new PhoneWindowManager()); spyOn(ActivityManager.getService()); + mContext = getInstrumentation().getTargetContext(); + spyOn(mContext); + mAtmInternal = mock(ActivityTaskManagerInternal.class); + LocalServices.addService(ActivityTaskManagerInternal.class, mAtmInternal); + mPhoneWindowManager.mActivityTaskManagerInternal = mAtmInternal; + LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class)); } @After public void tearDown() { reset(ActivityManager.getService()); + reset(mContext); + LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); + LocalServices.removeServiceForTest(WindowManagerInternal.class); } @Test @@ -99,6 +123,60 @@ public class PhoneWindowManagerTests { } @Test + public void testScreenTurnedOff() { + mSetFlagsRule.enableFlags(com.android.window.flags.Flags + .FLAG_SKIP_SLEEPING_WHEN_SWITCHING_DISPLAY); + doNothing().when(mPhoneWindowManager).updateSettings(any()); + doNothing().when(mPhoneWindowManager).initializeHdmiState(); + final boolean[] isScreenTurnedOff = { false }; + final DisplayPolicy displayPolicy = mock(DisplayPolicy.class); + doAnswer(invocation -> isScreenTurnedOff[0] = true).when(displayPolicy).screenTurnedOff(); + doAnswer(invocation -> !isScreenTurnedOff[0]).when(displayPolicy).isScreenOnEarly(); + doAnswer(invocation -> !isScreenTurnedOff[0]).when(displayPolicy).isScreenOnFully(); + + mPhoneWindowManager.mDefaultDisplayPolicy = displayPolicy; + mPhoneWindowManager.mDefaultDisplayRotation = mock(DisplayRotation.class); + final ActivityTaskManagerInternal.SleepTokenAcquirer tokenAcquirer = + mock(ActivityTaskManagerInternal.SleepTokenAcquirer.class); + doReturn(tokenAcquirer).when(mAtmInternal).createSleepTokenAcquirer(anyString()); + final PowerManager pm = mock(PowerManager.class); + doReturn(true).when(pm).isInteractive(); + doReturn(pm).when(mContext).getSystemService(eq(Context.POWER_SERVICE)); + + mContext.getMainThreadHandler().runWithScissors(() -> mPhoneWindowManager.init( + new PhoneWindowManager.Injector(mContext, + mock(WindowManagerPolicy.WindowManagerFuncs.class))), 0); + assertThat(isScreenTurnedOff[0]).isFalse(); + assertThat(mPhoneWindowManager.mIsGoingToSleepDefaultDisplay).isFalse(); + + // Skip sleep-token for non-sleep-screen-off. + clearInvocations(tokenAcquirer); + mPhoneWindowManager.screenTurnedOff(DEFAULT_DISPLAY, true /* isSwappingDisplay */); + verify(tokenAcquirer, never()).acquire(anyInt(), anyBoolean()); + assertThat(isScreenTurnedOff[0]).isTrue(); + + // Apply sleep-token for sleep-screen-off. + mPhoneWindowManager.startedGoingToSleep(DEFAULT_DISPLAY, 0 /* reason */); + assertThat(mPhoneWindowManager.mIsGoingToSleepDefaultDisplay).isTrue(); + mPhoneWindowManager.screenTurnedOff(DEFAULT_DISPLAY, true /* isSwappingDisplay */); + verify(tokenAcquirer).acquire(eq(DEFAULT_DISPLAY), eq(true)); + + mPhoneWindowManager.finishedGoingToSleep(DEFAULT_DISPLAY, 0 /* reason */); + assertThat(mPhoneWindowManager.mIsGoingToSleepDefaultDisplay).isFalse(); + + // Simulate unexpected reversed order: screenTurnedOff -> startedGoingToSleep. The sleep + // token can still be acquired. + isScreenTurnedOff[0] = false; + clearInvocations(tokenAcquirer); + mPhoneWindowManager.screenTurnedOff(DEFAULT_DISPLAY, true /* isSwappingDisplay */); + verify(tokenAcquirer, never()).acquire(anyInt(), anyBoolean()); + assertThat(displayPolicy.isScreenOnEarly()).isFalse(); + assertThat(displayPolicy.isScreenOnFully()).isFalse(); + mPhoneWindowManager.startedGoingToSleep(DEFAULT_DISPLAY, 0 /* reason */); + verify(tokenAcquirer).acquire(eq(DEFAULT_DISPLAY), eq(false)); + } + + @Test public void testCheckAddPermission_withoutAccessibilityOverlay_noAccessibilityAppOpLogged() { mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags .FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); @@ -130,11 +208,8 @@ public class PhoneWindowManagerTests { private void mockStartDockOrHome() throws Exception { doNothing().when(ActivityManager.getService()).stopAppSwitches(); - ActivityTaskManagerInternal mMockActivityTaskManagerInternal = - mock(ActivityTaskManagerInternal.class); - when(mMockActivityTaskManagerInternal.startHomeOnDisplay( + when(mAtmInternal.startHomeOnDisplay( anyInt(), anyString(), anyInt(), anyBoolean(), anyBoolean())).thenReturn(false); - mPhoneWindowManager.mActivityTaskManagerInternal = mMockActivityTaskManagerInternal; mPhoneWindowManager.mUserManagerInternal = mock(UserManagerInternal.class); } } |