Loading core/java/android/view/WindowManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -624,6 +624,12 @@ public interface WindowManager extends ViewManager { */ int TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH = (1 << 14); // 0x4000 /** * Transition flag: Indicates that aod is showing hidden by entering doze * @hide */ int TRANSIT_FLAG_AOD_APPEARING = (1 << 15); // 0x8000 /** * @hide */ Loading @@ -643,6 +649,7 @@ public interface WindowManager extends ViewManager { TRANSIT_FLAG_KEYGUARD_OCCLUDING, TRANSIT_FLAG_KEYGUARD_UNOCCLUDING, TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH, TRANSIT_FLAG_AOD_APPEARING, }) @Retention(RetentionPolicy.SOURCE) @interface TransitionFlags {} Loading @@ -659,7 +666,8 @@ public interface WindowManager extends ViewManager { (TRANSIT_FLAG_KEYGUARD_GOING_AWAY | TRANSIT_FLAG_KEYGUARD_APPEARING | TRANSIT_FLAG_KEYGUARD_OCCLUDING | TRANSIT_FLAG_KEYGUARD_UNOCCLUDING); | TRANSIT_FLAG_KEYGUARD_UNOCCLUDING | TRANSIT_FLAG_AOD_APPEARING); /** * Remove content mode: Indicates remove content mode is currently not defined. Loading services/tests/wmtests/src/com/android/server/TransitionSubject.java 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import android.annotation.Nullable; import com.google.common.truth.FailureMetadata; import com.google.common.truth.IterableSubject; import com.google.common.truth.Subject; import com.google.common.truth.Truth; import java.util.ArrayList; import java.util.List; public class TransitionSubject extends Subject { @Nullable private final Transition actual; /** * Internal constructor. * * @see TransitionSubject#assertThat(Transition) */ private TransitionSubject(FailureMetadata metadata, @Nullable Transition actual) { super(metadata, actual); this.actual = actual; } /** * In a fluent assertion chain, the argument to the "custom" overload of {@link * StandardSubjectBuilder#about(CustomSubjectBuilder.Factory) about}, the method that specifies * what kind of {@link Subject} to create. */ public static Factory<TransitionSubject, Transition> transitions() { return TransitionSubject::new; } /** * Typical entry point for making assertions about Transitions. * * @see @Truth#assertThat(Object) */ public static TransitionSubject assertThat(Transition transition) { return Truth.assertAbout(transitions()).that(transition); } /** * Converts to a {@link IterableSubject} containing {@link Transition#getFlags()} separated into * a list of individual flags for assertions such as {@code flags().contains(TRANSIT_FLAG_XYZ)}. * * <p>If the subject is null, this will fail instead of returning a null subject. */ public IterableSubject flags() { isNotNull(); final List<Integer> sortedFlags = new ArrayList<>(); for (int i = 0; i < 32; i++) { if ((actual.getFlags() & (1 << i)) != 0) { sortedFlags.add((1 << i)); } } return com.google.common.truth.Truth.assertThat(sortedFlags); } } services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +48 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; Loading @@ -80,6 +83,7 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFO import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.TransitionSubject.assertThat; import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING; import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE; import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT; Loading Loading @@ -147,6 +151,7 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.utils.WmDisplayCutout; import com.android.window.flags.Flags; import org.junit.Test; import org.junit.runner.RunWith; Loading Loading @@ -2620,6 +2625,7 @@ public class DisplayContentTests extends WindowTestsBase { final KeyguardController keyguard = mAtm.mKeyguardController; final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); final int displayId = mDisplayContent.getDisplayId(); final TestTransitionPlayer transitions = registerTestTransitionPlayer(); final BooleanSupplier keyguardShowing = () -> keyguard.isKeyguardShowing(displayId); final BooleanSupplier keyguardGoingAway = () -> keyguard.isKeyguardGoingAway(displayId); Loading @@ -2629,21 +2635,40 @@ public class DisplayContentTests extends WindowTestsBase { keyguard.setKeyguardShown(displayId, true /* keyguard */, true /* aod */); assertFalse(keyguardGoingAway.getAsBoolean()); assertFalse(appVisible.getAsBoolean()); transitions.flush(); // Start unlocking from AOD. keyguard.keyguardGoingAway(displayId, 0x0 /* flags */); assertTrue(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); if (Flags.ensureKeyguardDoesTransitionStarting()) { assertThat(transitions.mLastTransit).isNull(); } else { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_KEYGUARD_GOING_AWAY); } transitions.flush(); // Clear AOD. This does *not* clear the going-away status. keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */); assertTrue(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); if (Flags.aodTransition()) { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_AOD_APPEARING); } else { assertThat(transitions.mLastTransit).isNull(); } transitions.flush(); // Finish unlock keyguard.setKeyguardShown(displayId, false /* keyguard */, false /* aod */); assertFalse(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); assertThat(transitions.mLastTransit).isNull(); } @Test Loading @@ -2653,6 +2678,7 @@ public class DisplayContentTests extends WindowTestsBase { final KeyguardController keyguard = mAtm.mKeyguardController; final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); final int displayId = mDisplayContent.getDisplayId(); final TestTransitionPlayer transitions = registerTestTransitionPlayer(); final BooleanSupplier keyguardShowing = () -> keyguard.isKeyguardShowing(displayId); final BooleanSupplier keyguardGoingAway = () -> keyguard.isKeyguardGoingAway(displayId); Loading @@ -2662,22 +2688,44 @@ public class DisplayContentTests extends WindowTestsBase { keyguard.setKeyguardShown(displayId, true /* keyguard */, true /* aod */); assertFalse(keyguardGoingAway.getAsBoolean()); assertFalse(appVisible.getAsBoolean()); transitions.flush(); // Start unlocking from AOD. keyguard.keyguardGoingAway(displayId, 0x0 /* flags */); assertTrue(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); if (!Flags.ensureKeyguardDoesTransitionStarting()) { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_KEYGUARD_GOING_AWAY); } transitions.flush(); // Clear AOD. This does *not* clear the going-away status. keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */); assertTrue(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); if (Flags.aodTransition()) { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_AOD_APPEARING); } else { assertThat(transitions.mLastTransit).isNull(); } transitions.flush(); // Same API call a second time cancels the unlock, because AOD isn't changing. keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */); assertTrue(keyguardShowing.getAsBoolean()); assertFalse(keyguardGoingAway.getAsBoolean()); assertFalse(appVisible.getAsBoolean()); if (Flags.ensureKeyguardDoesTransitionStarting()) { assertThat(transitions.mLastTransit).isNull(); } else { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_KEYGUARD_APPEARING); } } @Test Loading services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +8 −0 Original line number Diff line number Diff line Loading @@ -2151,6 +2151,14 @@ public class WindowTestsBase extends SystemServiceTestsBase { mLastRequest = null; } void flush() { if (mLastTransit != null) { start(); finish(); clear(); } } @Override public void onTransitionReady(IBinder transitToken, TransitionInfo transitionInfo, SurfaceControl.Transaction transaction, SurfaceControl.Transaction finishT) Loading Loading
core/java/android/view/WindowManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -624,6 +624,12 @@ public interface WindowManager extends ViewManager { */ int TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH = (1 << 14); // 0x4000 /** * Transition flag: Indicates that aod is showing hidden by entering doze * @hide */ int TRANSIT_FLAG_AOD_APPEARING = (1 << 15); // 0x8000 /** * @hide */ Loading @@ -643,6 +649,7 @@ public interface WindowManager extends ViewManager { TRANSIT_FLAG_KEYGUARD_OCCLUDING, TRANSIT_FLAG_KEYGUARD_UNOCCLUDING, TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH, TRANSIT_FLAG_AOD_APPEARING, }) @Retention(RetentionPolicy.SOURCE) @interface TransitionFlags {} Loading @@ -659,7 +666,8 @@ public interface WindowManager extends ViewManager { (TRANSIT_FLAG_KEYGUARD_GOING_AWAY | TRANSIT_FLAG_KEYGUARD_APPEARING | TRANSIT_FLAG_KEYGUARD_OCCLUDING | TRANSIT_FLAG_KEYGUARD_UNOCCLUDING); | TRANSIT_FLAG_KEYGUARD_UNOCCLUDING | TRANSIT_FLAG_AOD_APPEARING); /** * Remove content mode: Indicates remove content mode is currently not defined. Loading
services/tests/wmtests/src/com/android/server/TransitionSubject.java 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import android.annotation.Nullable; import com.google.common.truth.FailureMetadata; import com.google.common.truth.IterableSubject; import com.google.common.truth.Subject; import com.google.common.truth.Truth; import java.util.ArrayList; import java.util.List; public class TransitionSubject extends Subject { @Nullable private final Transition actual; /** * Internal constructor. * * @see TransitionSubject#assertThat(Transition) */ private TransitionSubject(FailureMetadata metadata, @Nullable Transition actual) { super(metadata, actual); this.actual = actual; } /** * In a fluent assertion chain, the argument to the "custom" overload of {@link * StandardSubjectBuilder#about(CustomSubjectBuilder.Factory) about}, the method that specifies * what kind of {@link Subject} to create. */ public static Factory<TransitionSubject, Transition> transitions() { return TransitionSubject::new; } /** * Typical entry point for making assertions about Transitions. * * @see @Truth#assertThat(Object) */ public static TransitionSubject assertThat(Transition transition) { return Truth.assertAbout(transitions()).that(transition); } /** * Converts to a {@link IterableSubject} containing {@link Transition#getFlags()} separated into * a list of individual flags for assertions such as {@code flags().contains(TRANSIT_FLAG_XYZ)}. * * <p>If the subject is null, this will fail instead of returning a null subject. */ public IterableSubject flags() { isNotNull(); final List<Integer> sortedFlags = new ArrayList<>(); for (int i = 0; i < 32; i++) { if ((actual.getFlags() & (1 << i)) != 0) { sortedFlags.add((1 << i)); } } return com.google.common.truth.Truth.assertThat(sortedFlags); } }
services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +48 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; Loading @@ -80,6 +83,7 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFO import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.TransitionSubject.assertThat; import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING; import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE; import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT; Loading Loading @@ -147,6 +151,7 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.utils.WmDisplayCutout; import com.android.window.flags.Flags; import org.junit.Test; import org.junit.runner.RunWith; Loading Loading @@ -2620,6 +2625,7 @@ public class DisplayContentTests extends WindowTestsBase { final KeyguardController keyguard = mAtm.mKeyguardController; final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); final int displayId = mDisplayContent.getDisplayId(); final TestTransitionPlayer transitions = registerTestTransitionPlayer(); final BooleanSupplier keyguardShowing = () -> keyguard.isKeyguardShowing(displayId); final BooleanSupplier keyguardGoingAway = () -> keyguard.isKeyguardGoingAway(displayId); Loading @@ -2629,21 +2635,40 @@ public class DisplayContentTests extends WindowTestsBase { keyguard.setKeyguardShown(displayId, true /* keyguard */, true /* aod */); assertFalse(keyguardGoingAway.getAsBoolean()); assertFalse(appVisible.getAsBoolean()); transitions.flush(); // Start unlocking from AOD. keyguard.keyguardGoingAway(displayId, 0x0 /* flags */); assertTrue(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); if (Flags.ensureKeyguardDoesTransitionStarting()) { assertThat(transitions.mLastTransit).isNull(); } else { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_KEYGUARD_GOING_AWAY); } transitions.flush(); // Clear AOD. This does *not* clear the going-away status. keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */); assertTrue(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); if (Flags.aodTransition()) { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_AOD_APPEARING); } else { assertThat(transitions.mLastTransit).isNull(); } transitions.flush(); // Finish unlock keyguard.setKeyguardShown(displayId, false /* keyguard */, false /* aod */); assertFalse(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); assertThat(transitions.mLastTransit).isNull(); } @Test Loading @@ -2653,6 +2678,7 @@ public class DisplayContentTests extends WindowTestsBase { final KeyguardController keyguard = mAtm.mKeyguardController; final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); final int displayId = mDisplayContent.getDisplayId(); final TestTransitionPlayer transitions = registerTestTransitionPlayer(); final BooleanSupplier keyguardShowing = () -> keyguard.isKeyguardShowing(displayId); final BooleanSupplier keyguardGoingAway = () -> keyguard.isKeyguardGoingAway(displayId); Loading @@ -2662,22 +2688,44 @@ public class DisplayContentTests extends WindowTestsBase { keyguard.setKeyguardShown(displayId, true /* keyguard */, true /* aod */); assertFalse(keyguardGoingAway.getAsBoolean()); assertFalse(appVisible.getAsBoolean()); transitions.flush(); // Start unlocking from AOD. keyguard.keyguardGoingAway(displayId, 0x0 /* flags */); assertTrue(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); if (!Flags.ensureKeyguardDoesTransitionStarting()) { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_KEYGUARD_GOING_AWAY); } transitions.flush(); // Clear AOD. This does *not* clear the going-away status. keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */); assertTrue(keyguardGoingAway.getAsBoolean()); assertTrue(appVisible.getAsBoolean()); if (Flags.aodTransition()) { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_AOD_APPEARING); } else { assertThat(transitions.mLastTransit).isNull(); } transitions.flush(); // Same API call a second time cancels the unlock, because AOD isn't changing. keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */); assertTrue(keyguardShowing.getAsBoolean()); assertFalse(keyguardGoingAway.getAsBoolean()); assertFalse(appVisible.getAsBoolean()); if (Flags.ensureKeyguardDoesTransitionStarting()) { assertThat(transitions.mLastTransit).isNull(); } else { assertThat(transitions.mLastTransit).flags() .containsExactly(TRANSIT_FLAG_KEYGUARD_APPEARING); } } @Test Loading
services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +8 −0 Original line number Diff line number Diff line Loading @@ -2151,6 +2151,14 @@ public class WindowTestsBase extends SystemServiceTestsBase { mLastRequest = null; } void flush() { if (mLastTransit != null) { start(); finish(); clear(); } } @Override public void onTransitionReady(IBinder transitToken, TransitionInfo transitionInfo, SurfaceControl.Transaction transaction, SurfaceControl.Transaction finishT) Loading