Notify transition listener only for its interested display
In legacy transition, the listeners are managed by AppTransition
per display (DisplayContent.mAppTransition.registerListenerLocked).
So listeners won't be notified by unrelated display.
While in shell transition, all listeners are managed by
TransitionController. So all listeners will be notified once any
display has a transition.
This change allows the listener to specify the display it wants
to monitor. If no display is specified, it will receive from all
displays, e.g. WMS#mActivityManagerAppTransitionNotifier. The
behavior is only enabled in TransitionController (shell transition).
Bug: 326610743
Flag: EXEMPT bugfix
Test: TransitionTests
Change-Id: Ia297b2e7a1204dc501a9ae288580b74638a78e2e
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8419a60..df97313 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2402,7 +2402,7 @@
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
}
- mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() {
+ final var transitionListener = new AppTransitionListener(DEFAULT_DISPLAY) {
@Override
public int onAppTransitionStartingLocked(long statusBarAnimationStartTime,
long statusBarAnimationDuration) {
@@ -2436,7 +2436,8 @@
mLockAfterDreamingTransitionFinished = false;
}
}
- });
+ };
+ mWindowManagerInternal.registerAppTransitionListener(transitionListener);
mKeyguardDrawnTimeout = mContext.getResources().getInteger(
com.android.internal.R.integer.config_keyguardDrawnTimeout);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9371149..ed8dbbc 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6911,6 +6911,10 @@
/** Whether {@link #mAnimatingRecents} is going to be the top activity. */
private boolean mRecentsWillBeTop;
+ FixedRotationTransitionListener() {
+ super(DisplayContent.this.mDisplayId);
+ }
+
/**
* If the recents activity has a fixed orientation which is different from the current top
* activity, it will be rotated before being shown so we avoid a screen rotation animation
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 80362a4..c3339cd 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -588,7 +588,7 @@
gesturesPointerEventCallbacks);
displayContent.registerPointerEventListener(mSystemGestures);
}
- mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() {
+ mAppTransitionListener = new WindowManagerInternal.AppTransitionListener(displayId) {
private Runnable mAppTransitionPending = () -> {
StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 5336044..475cf24 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -744,6 +744,7 @@
if (mController.isAnimating()) {
dc.enableHighPerfTransition(true);
}
+ mController.dispatchLegacyAppTransitionPending(dc.mDisplayId);
}
/**
@@ -1617,7 +1618,7 @@
mController.mTransitionTracer.logAbortedTransition(this);
// Syncengine abort will call through to onTransactionReady()
mSyncEngine.abort(mSyncId);
- mController.dispatchLegacyAppTransitionCancelled();
+ mController.dispatchLegacyAppTransitionCancelled(mTargetDisplays);
invokeTransitionEndedListeners();
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index f4ff404..1df251c 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -42,6 +42,7 @@
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import android.view.Display;
import android.view.WindowManager;
import android.window.ITransitionMetricsReporter;
import android.window.ITransitionPlayer;
@@ -326,7 +327,6 @@
mCollectingTransition.startCollecting(timeoutMs);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Start collecting in Transition: %s",
mCollectingTransition);
- dispatchLegacyAppTransitionPending();
}
void registerTransitionPlayer(@Nullable ITransitionPlayer player,
@@ -1347,31 +1347,54 @@
mLegacyListeners.remove(listener);
}
- void dispatchLegacyAppTransitionPending() {
+ private static boolean shouldDispatchLegacyListener(
+ WindowManagerInternal.AppTransitionListener listener, int displayId) {
+ // INVALID_DISPLAY means that it is a global listener.
+ return listener.mDisplayId == Display.INVALID_DISPLAY || listener.mDisplayId == displayId;
+ }
+
+ void dispatchLegacyAppTransitionPending(int displayId) {
for (int i = 0; i < mLegacyListeners.size(); ++i) {
- mLegacyListeners.get(i).onAppTransitionPendingLocked();
+ final WindowManagerInternal.AppTransitionListener listener = mLegacyListeners.get(i);
+ if (shouldDispatchLegacyListener(listener, displayId)) {
+ listener.onAppTransitionPendingLocked();
+ }
}
}
void dispatchLegacyAppTransitionStarting(TransitionInfo info, long statusBarTransitionDelay) {
+ final long now = SystemClock.uptimeMillis();
for (int i = 0; i < mLegacyListeners.size(); ++i) {
- // TODO(shell-transitions): handle (un)occlude transition.
- mLegacyListeners.get(i).onAppTransitionStartingLocked(
- SystemClock.uptimeMillis() + statusBarTransitionDelay,
- AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
+ final WindowManagerInternal.AppTransitionListener listener = mLegacyListeners.get(i);
+ for (int j = 0; j < info.getRootCount(); ++j) {
+ final int displayId = info.getRoot(j).getDisplayId();
+ if (shouldDispatchLegacyListener(listener, displayId)) {
+ listener.onAppTransitionStartingLocked(
+ now + statusBarTransitionDelay,
+ AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
+ }
+ }
}
}
void dispatchLegacyAppTransitionFinished(ActivityRecord ar) {
for (int i = 0; i < mLegacyListeners.size(); ++i) {
- mLegacyListeners.get(i).onAppTransitionFinishedLocked(ar.token);
+ final WindowManagerInternal.AppTransitionListener listener = mLegacyListeners.get(i);
+ if (shouldDispatchLegacyListener(listener, ar.getDisplayId())) {
+ listener.onAppTransitionFinishedLocked(ar.token);
+ }
}
}
- void dispatchLegacyAppTransitionCancelled() {
- for (int i = 0; i < mLegacyListeners.size(); ++i) {
- mLegacyListeners.get(i).onAppTransitionCancelledLocked(
- false /* keyguardGoingAwayCancelled */);
+ void dispatchLegacyAppTransitionCancelled(ArrayList<DisplayContent> targetDisplays) {
+ for (int i = 0; i < targetDisplays.size(); ++i) {
+ final int displayId = targetDisplays.get(i).mDisplayId;
+ for (int j = 0; j < mLegacyListeners.size(); ++j) {
+ final var listener = mLegacyListeners.get(j);
+ if (shouldDispatchLegacyListener(listener, displayId)) {
+ listener.onAppTransitionCancelledLocked(false /* keyguardGoingAwayCancelled */);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 2ea1cf8..132e1ee 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -244,6 +244,22 @@
public static abstract class AppTransitionListener {
/**
+ * The display this listener is interested in. If it is INVALID_DISPLAY, then which display
+ * should be notified depends on the dispatcher.
+ */
+ public final int mDisplayId;
+
+ /** Let transition controller decide which display should receive the callbacks. */
+ public AppTransitionListener() {
+ this(Display.INVALID_DISPLAY);
+ }
+
+ /** It will listen the transition on the given display. */
+ public AppTransitionListener(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ /**
* Called when an app transition is being setup and about to be executed.
*/
public void onAppTransitionPendingLocked() {}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 95d37eb..0c84cc4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1572,7 +1572,8 @@
enteringAnimReports.clear();
doCallRealMethod().when(mWm.mRoot).ensureActivitiesVisible(any(), anyBoolean());
final boolean[] wasInFinishingTransition = { false };
- controller.registerLegacyListener(new WindowManagerInternal.AppTransitionListener() {
+ controller.registerLegacyListener(new WindowManagerInternal.AppTransitionListener(
+ mDisplayContent.mDisplayId) {
@Override
public void onAppTransitionFinishedLocked(IBinder token) {
final ActivityRecord r = ActivityRecord.forToken(token);
@@ -1581,6 +1582,14 @@
}
}
});
+ final boolean[] calledListenerOnOtherDisplay = { false };
+ controller.registerLegacyListener(new WindowManagerInternal.AppTransitionListener(
+ mDisplayContent.mDisplayId + 1234) {
+ @Override
+ public void onAppTransitionFinishedLocked(IBinder token) {
+ calledListenerOnOtherDisplay[0] = true;
+ }
+ });
assertTrue(activity1.isVisible());
doReturn(false).when(task1).isTranslucent(null);
doReturn(false).when(task1).isTranslucentForTransition();
@@ -1591,6 +1600,7 @@
controller.finishTransition(closeTransition);
assertTrue(wasInFinishingTransition[0]);
+ assertFalse(calledListenerOnOtherDisplay[0]);
assertNull(controller.mFinishingTransition);
assertTrue(activity2.isVisible());