Merge "Use blast sync for 180 degrees rotation" into udc-dev
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 5c9c813..7a11120 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -93,6 +93,9 @@
/** Whether the start transaction of the transition is committed (by shell). */
private boolean mIsStartTransactionCommitted;
+ /** Whether all windows should wait for the start transaction. */
+ private boolean mAlwaysWaitForStartTransaction;
+
/** Whether the target windows have been requested to sync their draw transactions. */
private boolean mIsSyncDrawRequested;
@@ -144,6 +147,15 @@
if (mTransitionOp == OP_LEGACY) {
mIsStartTransactionCommitted = true;
} else if (displayContent.mTransitionController.isCollecting(displayContent)) {
+ final Transition transition =
+ mDisplayContent.mTransitionController.getCollectingTransition();
+ if (transition != null) {
+ final BLASTSyncEngine.SyncGroup syncGroup =
+ mDisplayContent.mWmService.mSyncEngine.getSyncSet(transition.getSyncId());
+ if (syncGroup != null && syncGroup.mSyncMethod == BLASTSyncEngine.METHOD_BLAST) {
+ mAlwaysWaitForStartTransaction = true;
+ }
+ }
keepAppearanceInPreviousRotation();
}
}
@@ -202,7 +214,7 @@
// target windows. But the windows still need to use sync transaction to keep the appearance
// in previous rotation, so request a no-op sync to keep the state.
for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
- if (mTargetWindowTokens.valueAt(i).canDrawBeforeStartTransaction()) {
+ if (canDrawBeforeStartTransaction(mTargetWindowTokens.valueAt(i))) {
// Expect a screenshot layer will cover the non seamless windows.
continue;
}
@@ -521,7 +533,7 @@
if (op == null) return false;
if (DEBUG) Slog.d(TAG, "handleFinishDrawing " + w);
if (postDrawTransaction == null || !mIsSyncDrawRequested
- || op.canDrawBeforeStartTransaction()) {
+ || canDrawBeforeStartTransaction(op)) {
mDisplayContent.finishAsyncRotation(w.mToken);
return false;
}
@@ -563,6 +575,14 @@
return super.getFadeOutAnimation();
}
+ /**
+ * Returns {@code true} if the corresponding window can draw its latest content before the
+ * start transaction of rotation transition is applied.
+ */
+ private boolean canDrawBeforeStartTransaction(Operation op) {
+ return !mAlwaysWaitForStartTransaction && op.mAction != Operation.ACTION_SEAMLESS;
+ }
+
/** The operation to control the rotation appearance associated with window token. */
private static class Operation {
@Retention(RetentionPolicy.SOURCE)
@@ -588,14 +608,5 @@
Operation(@Action int action) {
mAction = action;
}
-
- /**
- * Returns {@code true} if the corresponding window can draw its latest content before the
- * start transaction of rotation transition is applied.
- */
- boolean canDrawBeforeStartTransaction() {
- return TransitionController.SYNC_METHOD != BLASTSyncEngine.METHOD_BLAST
- && mAction != ACTION_SEAMLESS;
- }
}
}
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index cd26e2e..48cf567 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -95,7 +95,7 @@
*/
class SyncGroup {
final int mSyncId;
- final int mSyncMethod;
+ int mSyncMethod = METHOD_BLAST;
final TransactionReadyListener mListener;
final Runnable mOnTimeout;
boolean mReady = false;
@@ -103,9 +103,8 @@
private SurfaceControl.Transaction mOrphanTransaction = null;
private String mTraceName;
- private SyncGroup(TransactionReadyListener listener, int id, String name, int method) {
+ private SyncGroup(TransactionReadyListener listener, int id, String name) {
mSyncId = id;
- mSyncMethod = method;
mListener = listener;
mOnTimeout = () -> {
Slog.w(TAG, "Sync group " + mSyncId + " timeout");
@@ -288,13 +287,12 @@
* Prepares a {@link SyncGroup} that is not active yet. Caller must call {@link #startSyncSet}
* before calling {@link #addToSyncSet(int, WindowContainer)} on any {@link WindowContainer}.
*/
- SyncGroup prepareSyncSet(TransactionReadyListener listener, String name, int method) {
- return new SyncGroup(listener, mNextSyncId++, name, method);
+ SyncGroup prepareSyncSet(TransactionReadyListener listener, String name) {
+ return new SyncGroup(listener, mNextSyncId++, name);
}
- int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name,
- int method) {
- final SyncGroup s = prepareSyncSet(listener, name, method);
+ int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name) {
+ final SyncGroup s = prepareSyncSet(listener, name);
startSyncSet(s, timeoutMs);
return s.mSyncId;
}
@@ -334,6 +332,15 @@
getSyncGroup(id).addToSync(wc);
}
+ void setSyncMethod(int id, int method) {
+ final SyncGroup syncGroup = getSyncGroup(id);
+ if (!syncGroup.mRootMembers.isEmpty()) {
+ throw new IllegalStateException(
+ "Not allow to change sync method after adding group member, id=" + id);
+ }
+ syncGroup.mSyncMethod = method;
+ }
+
void setReady(int id, boolean ready) {
getSyncGroup(id).setReady(ready);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index f2e4937..606f011 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -369,7 +369,6 @@
return mState;
}
- @VisibleForTesting
int getSyncId() {
return mSyncId;
}
@@ -409,18 +408,14 @@
return mState == STATE_FINISHED;
}
- @VisibleForTesting
- void startCollecting(long timeoutMs) {
- startCollecting(timeoutMs, TransitionController.SYNC_METHOD);
- }
-
/** Starts collecting phase. Once this starts, all relevant surface operations are sync. */
- void startCollecting(long timeoutMs, int method) {
+ void startCollecting(long timeoutMs) {
if (mState != STATE_PENDING) {
throw new IllegalStateException("Attempting to re-use a transition");
}
mState = STATE_COLLECTING;
- mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG, method);
+ mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG);
+ mSyncEngine.setSyncMethod(mSyncId, TransitionController.SYNC_METHOD);
mLogger.mSyncId = mSyncId;
mLogger.mCollectTimeNs = SystemClock.elapsedRealtimeNanos();
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 6c951bf..bacc6e6 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -51,7 +51,6 @@
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.FgThread;
@@ -200,12 +199,6 @@
/** Starts Collecting */
void moveToCollecting(@NonNull Transition transition) {
- moveToCollecting(transition, SYNC_METHOD);
- }
-
- /** Starts Collecting */
- @VisibleForTesting
- void moveToCollecting(@NonNull Transition transition, int method) {
if (mCollectingTransition != null) {
throw new IllegalStateException("Simultaneous transition collection not supported.");
}
@@ -219,7 +212,7 @@
// Distinguish change type because the response time is usually expected to be not too long.
final long timeoutMs =
transition.mType == TRANSIT_CHANGE ? CHANGE_TIMEOUT_MS : DEFAULT_TIMEOUT_MS;
- mCollectingTransition.startCollecting(timeoutMs, method);
+ mCollectingTransition.startCollecting(timeoutMs);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Start collecting in Transition: %s",
mCollectingTransition);
dispatchLegacyAppTransitionPending();
@@ -492,6 +485,15 @@
} else {
newTransition = requestStartTransition(createTransition(type, flags),
trigger != null ? trigger.asTask() : null, remoteTransition, displayChange);
+ if (newTransition != null && displayChange != null && (displayChange.getStartRotation()
+ + displayChange.getEndRotation()) % 2 == 0) {
+ // 180 degrees rotation change may not change screen size. So the clients may draw
+ // some frames before and after the display projection transaction is applied by the
+ // remote player. That may cause some buffers to show in different rotation. So use
+ // sync method to pause clients drawing until the projection transaction is applied.
+ mAtm.mWindowManager.mSyncEngine.setSyncMethod(newTransition.getSyncId(),
+ BLASTSyncEngine.METHOD_BLAST);
+ }
}
if (trigger != null) {
if (isExistenceType(type)) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 495d7ce4..c3c87af 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1648,7 +1648,7 @@
private BLASTSyncEngine.SyncGroup prepareSyncWithOrganizer(
IWindowContainerTransactionCallback callback) {
final BLASTSyncEngine.SyncGroup s = mService.mWindowManager.mSyncEngine
- .prepareSyncSet(this, "", BLASTSyncEngine.METHOD_BLAST);
+ .prepareSyncSet(this, "Organizer");
mTransactionCallbacksByPendingSyncId.put(s.mSyncId, callback);
return s;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java
index aff9c1a..8e91ca2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java
@@ -22,7 +22,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.BLASTSyncEngine.METHOD_BLAST;
import static com.android.server.wm.BLASTSyncEngine.METHOD_NONE;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -363,7 +362,8 @@
BLASTSyncEngine.TransactionReadyListener listener = mock(
BLASTSyncEngine.TransactionReadyListener.class);
- int id = startSyncSet(bse, listener, METHOD_NONE);
+ final int id = startSyncSet(bse, listener);
+ bse.setSyncMethod(id, METHOD_NONE);
bse.addToSyncSet(id, mAppWindow.mToken);
mAppWindow.prepareSync();
assertFalse(mAppWindow.shouldSyncWithBuffers());
@@ -373,12 +373,7 @@
static int startSyncSet(BLASTSyncEngine engine,
BLASTSyncEngine.TransactionReadyListener listener) {
- return startSyncSet(engine, listener, METHOD_BLAST);
- }
-
- static int startSyncSet(BLASTSyncEngine engine,
- BLASTSyncEngine.TransactionReadyListener listener, int method) {
- return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "", method);
+ return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "Test");
}
static class TestWindowContainer extends WindowContainer {
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 048e2cc..debfc84 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1704,7 +1704,8 @@
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
final Transition transition = new Transition(TRANSIT_OPEN, 0 /* flags */,
app.mTransitionController, mWm.mSyncEngine);
- app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
+ app.mTransitionController.moveToCollecting(transition);
+ mWm.mSyncEngine.setSyncMethod(transition.getSyncId(), BLASTSyncEngine.METHOD_NONE);
final ArrayList<WindowContainer> freezeCalls = new ArrayList<>();
transition.setContainerFreezer(new Transition.IContainerFreezer() {
@Override
@@ -1755,7 +1756,8 @@
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */,
app.mTransitionController, mWm.mSyncEngine);
- app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
+ app.mTransitionController.moveToCollecting(transition);
+ mWm.mSyncEngine.setSyncMethod(transition.getSyncId(), BLASTSyncEngine.METHOD_NONE);
final SurfaceControl mockSnapshot = mock(SurfaceControl.class);
transition.setContainerFreezer(new Transition.IContainerFreezer() {
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index d7e4c55..a68a573 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -42,7 +42,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
-import static com.android.server.wm.BLASTSyncEngine.METHOD_BLAST;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowContainer.SYNC_STATE_READY;
import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION;
@@ -1001,7 +1000,7 @@
BLASTSyncEngine.TransactionReadyListener transactionListener =
mock(BLASTSyncEngine.TransactionReadyListener.class);
- int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "", METHOD_BLAST);
+ final int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "Test");
bse.addToSyncSet(id, task);
bse.setReady(id);
bse.onSurfacePlacement();