Loading packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -1473,3 +1473,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "check_lockscreen_gone_transition" namespace: "systemui" description: "Run notification pipeline when the lockscreen is not in gone transition for avoiding janky frames during unlocking animation" bug: "358301118" metadata { purpose: PURPOSE_BUGFIX } } packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java +33 −5 Original line number Diff line number Diff line Loading @@ -20,8 +20,6 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertFalse; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; Loading @@ -31,12 +29,16 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; import android.platform.test.annotations.EnableFlags; import android.testing.TestableLooper; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.compose.animation.scene.ObservableTransitionState; import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.communal.shared.model.CommunalScenes; import com.android.systemui.dump.DumpManager; Loading Loading @@ -67,9 +69,6 @@ import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.time.FakeSystemClock; import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.test.TestScope; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -79,6 +78,9 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.verification.VerificationMode; import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.test.TestScope; @SmallTest @RunWith(AndroidJUnit4.class) @TestableLooper.RunWithLooper Loading Loading @@ -516,6 +518,32 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { verifyStabilityManagerWasInvalidated(times(1)); } @Test @EnableFlags(Flags.FLAG_CHECK_LOCKSCREEN_GONE_TRANSITION) public void testNotLockscreenInGoneTransition_invalidationCalled() { // GIVEN visual stability is being maintained b/c animation is playing mKosmos.getKeyguardTransitionRepository().sendTransitionStepJava( mTestScope, new TransitionStep( KeyguardState.LOCKSCREEN, KeyguardState.GONE, 1f, TransitionState.RUNNING), /* validateStep = */ false); mTestScope.getTestScheduler().runCurrent(); assertFalse(mNotifStabilityManager.isPipelineRunAllowed()); // WHEN the animation has stopped playing mKosmos.getKeyguardTransitionRepository().sendTransitionStepJava( mTestScope, new TransitionStep( KeyguardState.LOCKSCREEN, KeyguardState.GONE, 1f, TransitionState.FINISHED), /* validateStep = */ false); mTestScope.getTestScheduler().runCurrent(); // invalidate is called, b/c we were previously suppressing the pipeline from running verifyStabilityManagerWasInvalidated(times(1)); } @Test public void testNeverSuppressPipelineRunFromPanelCollapse_noInvalidationCalled() { // GIVEN animation is playing Loading packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt +11 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.view.View import android.view.WindowInsets import android.widget.FrameLayout import androidx.core.view.updateMargins import com.android.systemui.Flags import com.android.systemui.compose.ComposeInitializer import com.android.systemui.res.R Loading Loading @@ -103,6 +104,8 @@ open class WindowRootView( private fun applyMargins() { val count = childCount val hasFlagsEnabled = Flags.checkLockscreenGoneTransition() var hasChildMarginUpdated = false for (i in 0 until count) { val child = getChildAt(i) if (child.layoutParams is LayoutParams) { Loading @@ -113,11 +116,18 @@ open class WindowRootView( layoutParams.leftMargin != leftInset) ) { layoutParams.updateMargins(left = leftInset, right = rightInset) hasChildMarginUpdated = true if (!hasFlagsEnabled) { child.requestLayout() } } } } if (hasFlagsEnabled && hasChildMarginUpdated) { // Request layout at once after all children's margins has updated requestLayout() } } /** * Returns `true` if this view is the true root of the view-hierarchy; `false` otherwise. Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +10 −3 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import androidx.annotation.WorkerThread; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dumpable; import com.android.systemui.Flags; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; Loading Loading @@ -813,11 +814,17 @@ public class NotificationLockscreenUserManagerImpl implements private void notifyNotificationStateChanged() { if (!Looper.getMainLooper().isCurrentThread()) { if (Flags.checkLockscreenGoneTransition()) { for (NotificationStateChangedListener listener : mNotifStateChangedListeners) { mMainExecutor.execute(listener::onNotificationStateChanged); } } else { mMainExecutor.execute(() -> { for (NotificationStateChangedListener listener : mNotifStateChangedListeners) { listener.onNotificationStateChanged(); } }); } } else { for (NotificationStateChangedListener listener : mNotifStateChangedListeners) { listener.onNotificationStateChanged(); Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java +28 −2 Original line number Diff line number Diff line Loading @@ -22,15 +22,18 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.systemui.Dumpable; import com.android.systemui.Flags; import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.shared.model.Edge; import com.android.systemui.keyguard.shared.model.KeyguardState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.scene.shared.model.Scenes; import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.notification.VisibilityLocationProvider; Loading Loading @@ -85,6 +88,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { private boolean mNotifPanelLaunchingActivity; private boolean mCommunalShowing = false; private boolean mLockscreenShowing = false; private boolean mLockscreenInGoneTransition = false; private boolean mPipelineRunAllowed; private boolean mReorderingAllowed; Loading Loading @@ -158,6 +162,13 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { KeyguardState.LOCKSCREEN), this::onLockscreenKeyguardStateTransitionValueChanged); } if (Flags.checkLockscreenGoneTransition()) { mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.isInTransition( Edge.create(KeyguardState.LOCKSCREEN, Scenes.Gone), Edge.create(KeyguardState.LOCKSCREEN, KeyguardState.GONE)), this::onLockscreenInGoneTransitionChanged); } pipeline.setVisualStabilityManager(mNotifStabilityManager); } Loading Loading @@ -239,7 +250,9 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { private void updateAllowedStates(String field, boolean value) { boolean wasPipelineRunAllowed = mPipelineRunAllowed; boolean wasReorderingAllowed = mReorderingAllowed; mPipelineRunAllowed = !isPanelCollapsingOrLaunchingActivity(); // No need to run notification pipeline when the lockscreen is in fading animation. mPipelineRunAllowed = !(isPanelCollapsingOrLaunchingActivity() || (Flags.checkLockscreenGoneTransition() && mLockscreenInGoneTransition)); mReorderingAllowed = isReorderingAllowed(); if (wasPipelineRunAllowed != mPipelineRunAllowed || wasReorderingAllowed != mReorderingAllowed) { Loading Loading @@ -330,7 +343,6 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { updateAllowedStates("fullyDozed", fullyDozed); } }; final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { @Override public void onFinishedGoingToSleep() { Loading @@ -353,6 +365,9 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { pw.println("pipelineRunAllowed: " + mPipelineRunAllowed); pw.println(" notifPanelCollapsing: " + mNotifPanelCollapsing); pw.println(" launchingNotifActivity: " + mNotifPanelLaunchingActivity); if (Flags.checkLockscreenGoneTransition()) { pw.println(" lockscreenInGoneTransition: " + mLockscreenInGoneTransition); } pw.println("reorderingAllowed: " + mReorderingAllowed); pw.println(" sleepy: " + mSleepy); pw.println(" fullyDozed: " + mFullyDozed); Loading Loading @@ -401,4 +416,15 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { mLockscreenShowing = isShowing; updateAllowedStates("lockscreenShowing", isShowing); } private void onLockscreenInGoneTransitionChanged(boolean inGoneTransition) { if (!Flags.checkLockscreenGoneTransition()) { return; } if (inGoneTransition == mLockscreenInGoneTransition) { return; } mLockscreenInGoneTransition = inGoneTransition; updateAllowedStates("lockscreenInGoneTransition", mLockscreenInGoneTransition); } } Loading
packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -1473,3 +1473,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "check_lockscreen_gone_transition" namespace: "systemui" description: "Run notification pipeline when the lockscreen is not in gone transition for avoiding janky frames during unlocking animation" bug: "358301118" metadata { purpose: PURPOSE_BUGFIX } }
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java +33 −5 Original line number Diff line number Diff line Loading @@ -20,8 +20,6 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertFalse; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; Loading @@ -31,12 +29,16 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; import android.platform.test.annotations.EnableFlags; import android.testing.TestableLooper; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.compose.animation.scene.ObservableTransitionState; import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.communal.shared.model.CommunalScenes; import com.android.systemui.dump.DumpManager; Loading Loading @@ -67,9 +69,6 @@ import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.time.FakeSystemClock; import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.test.TestScope; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -79,6 +78,9 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.verification.VerificationMode; import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.test.TestScope; @SmallTest @RunWith(AndroidJUnit4.class) @TestableLooper.RunWithLooper Loading Loading @@ -516,6 +518,32 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { verifyStabilityManagerWasInvalidated(times(1)); } @Test @EnableFlags(Flags.FLAG_CHECK_LOCKSCREEN_GONE_TRANSITION) public void testNotLockscreenInGoneTransition_invalidationCalled() { // GIVEN visual stability is being maintained b/c animation is playing mKosmos.getKeyguardTransitionRepository().sendTransitionStepJava( mTestScope, new TransitionStep( KeyguardState.LOCKSCREEN, KeyguardState.GONE, 1f, TransitionState.RUNNING), /* validateStep = */ false); mTestScope.getTestScheduler().runCurrent(); assertFalse(mNotifStabilityManager.isPipelineRunAllowed()); // WHEN the animation has stopped playing mKosmos.getKeyguardTransitionRepository().sendTransitionStepJava( mTestScope, new TransitionStep( KeyguardState.LOCKSCREEN, KeyguardState.GONE, 1f, TransitionState.FINISHED), /* validateStep = */ false); mTestScope.getTestScheduler().runCurrent(); // invalidate is called, b/c we were previously suppressing the pipeline from running verifyStabilityManagerWasInvalidated(times(1)); } @Test public void testNeverSuppressPipelineRunFromPanelCollapse_noInvalidationCalled() { // GIVEN animation is playing Loading
packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt +11 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.view.View import android.view.WindowInsets import android.widget.FrameLayout import androidx.core.view.updateMargins import com.android.systemui.Flags import com.android.systemui.compose.ComposeInitializer import com.android.systemui.res.R Loading Loading @@ -103,6 +104,8 @@ open class WindowRootView( private fun applyMargins() { val count = childCount val hasFlagsEnabled = Flags.checkLockscreenGoneTransition() var hasChildMarginUpdated = false for (i in 0 until count) { val child = getChildAt(i) if (child.layoutParams is LayoutParams) { Loading @@ -113,11 +116,18 @@ open class WindowRootView( layoutParams.leftMargin != leftInset) ) { layoutParams.updateMargins(left = leftInset, right = rightInset) hasChildMarginUpdated = true if (!hasFlagsEnabled) { child.requestLayout() } } } } if (hasFlagsEnabled && hasChildMarginUpdated) { // Request layout at once after all children's margins has updated requestLayout() } } /** * Returns `true` if this view is the true root of the view-hierarchy; `false` otherwise. Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +10 −3 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import androidx.annotation.WorkerThread; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dumpable; import com.android.systemui.Flags; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; Loading Loading @@ -813,11 +814,17 @@ public class NotificationLockscreenUserManagerImpl implements private void notifyNotificationStateChanged() { if (!Looper.getMainLooper().isCurrentThread()) { if (Flags.checkLockscreenGoneTransition()) { for (NotificationStateChangedListener listener : mNotifStateChangedListeners) { mMainExecutor.execute(listener::onNotificationStateChanged); } } else { mMainExecutor.execute(() -> { for (NotificationStateChangedListener listener : mNotifStateChangedListeners) { listener.onNotificationStateChanged(); } }); } } else { for (NotificationStateChangedListener listener : mNotifStateChangedListeners) { listener.onNotificationStateChanged(); Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java +28 −2 Original line number Diff line number Diff line Loading @@ -22,15 +22,18 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.systemui.Dumpable; import com.android.systemui.Flags; import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.shared.model.Edge; import com.android.systemui.keyguard.shared.model.KeyguardState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.scene.shared.model.Scenes; import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.notification.VisibilityLocationProvider; Loading Loading @@ -85,6 +88,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { private boolean mNotifPanelLaunchingActivity; private boolean mCommunalShowing = false; private boolean mLockscreenShowing = false; private boolean mLockscreenInGoneTransition = false; private boolean mPipelineRunAllowed; private boolean mReorderingAllowed; Loading Loading @@ -158,6 +162,13 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { KeyguardState.LOCKSCREEN), this::onLockscreenKeyguardStateTransitionValueChanged); } if (Flags.checkLockscreenGoneTransition()) { mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.isInTransition( Edge.create(KeyguardState.LOCKSCREEN, Scenes.Gone), Edge.create(KeyguardState.LOCKSCREEN, KeyguardState.GONE)), this::onLockscreenInGoneTransitionChanged); } pipeline.setVisualStabilityManager(mNotifStabilityManager); } Loading Loading @@ -239,7 +250,9 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { private void updateAllowedStates(String field, boolean value) { boolean wasPipelineRunAllowed = mPipelineRunAllowed; boolean wasReorderingAllowed = mReorderingAllowed; mPipelineRunAllowed = !isPanelCollapsingOrLaunchingActivity(); // No need to run notification pipeline when the lockscreen is in fading animation. mPipelineRunAllowed = !(isPanelCollapsingOrLaunchingActivity() || (Flags.checkLockscreenGoneTransition() && mLockscreenInGoneTransition)); mReorderingAllowed = isReorderingAllowed(); if (wasPipelineRunAllowed != mPipelineRunAllowed || wasReorderingAllowed != mReorderingAllowed) { Loading Loading @@ -330,7 +343,6 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { updateAllowedStates("fullyDozed", fullyDozed); } }; final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { @Override public void onFinishedGoingToSleep() { Loading @@ -353,6 +365,9 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { pw.println("pipelineRunAllowed: " + mPipelineRunAllowed); pw.println(" notifPanelCollapsing: " + mNotifPanelCollapsing); pw.println(" launchingNotifActivity: " + mNotifPanelLaunchingActivity); if (Flags.checkLockscreenGoneTransition()) { pw.println(" lockscreenInGoneTransition: " + mLockscreenInGoneTransition); } pw.println("reorderingAllowed: " + mReorderingAllowed); pw.println(" sleepy: " + mSleepy); pw.println(" fullyDozed: " + mFullyDozed); Loading Loading @@ -401,4 +416,15 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { mLockscreenShowing = isShowing; updateAllowedStates("lockscreenShowing", isShowing); } private void onLockscreenInGoneTransitionChanged(boolean inGoneTransition) { if (!Flags.checkLockscreenGoneTransition()) { return; } if (inGoneTransition == mLockscreenInGoneTransition) { return; } mLockscreenInGoneTransition = inGoneTransition; updateAllowedStates("lockscreenInGoneTransition", mLockscreenInGoneTransition); } }