Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 776ed34c authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge "Skip sleep-token when switching display which will be on" into main

parents 99075875 20e51039
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -37,6 +37,17 @@ flag {
  bug: "291870756"
}

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"
+23 −2
Original line number Diff line number Diff line
@@ -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;
@@ -5470,6 +5478,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);
@@ -5493,6 +5510,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
@@ -5528,7 +5546,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
        EventLogTags.writeScreenToggled(1);


        mIsGoingToSleepDefaultDisplay = false;
        mDefaultDisplayPolicy.setAwake(true);

        // Since goToSleep performs these functions synchronously, we must
@@ -5630,7 +5648,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) {
+79 −4
Original line number Diff line number Diff line
@@ -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
@@ -98,6 +122,60 @@ public class PhoneWindowManagerTests {
        verify(mPhoneWindowManager).createHomeDockIntent();
    }

    @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
@@ -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);
    }
}