Set transform hint before rotation transaction is applied
Unlike legacy transition applies setDisplayProjection immediately when applying rotation change, shell transition applies the display projection in shell side when the animation is ready. So if uses the surface when receiving configuration change but the transaction is not applied yet, it may get an intermediate inconsistent transform hint. With this change: Rotation changed -> send config -> apply pending transaction with fixed transform hint -> transition ready -> shell starts animation and applies display projection and unsets fixed transform hint. Bug: 270282500 Test: atest SurfaceControlTests#testSurfaceChangedOnRotation Change-Id: Id4ad45adb9719b078f46040a09f786092c325a8a
This commit is contained in:
@@ -2181,6 +2181,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
}
|
||||
|
||||
mWmService.mDisplayManagerInternal.performTraversal(transaction);
|
||||
if (shellTransitions) {
|
||||
// Before setDisplayProjection is applied by the start transaction of transition,
|
||||
// set the transform hint to avoid using surface in old rotation.
|
||||
getPendingTransaction().setFixedTransformHint(mSurfaceControl, rotation);
|
||||
// The sync transaction should already contains setDisplayProjection, so unset the
|
||||
// hint to restore the natural state when the transaction is applied.
|
||||
transaction.unsetFixedTransformHint(mSurfaceControl);
|
||||
}
|
||||
scheduleAnimation();
|
||||
|
||||
mWmService.mRotationWatcherController.dispatchDisplayRotationChange(mDisplayId, rotation);
|
||||
|
||||
@@ -806,6 +806,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
if (c.getSnapshot() != null) {
|
||||
t.reparent(c.getSnapshot(), null);
|
||||
}
|
||||
// The fixed transform hint was set in DisplayContent#applyRotation(). Make sure to
|
||||
// clear the hint in case the start transaction is not applied.
|
||||
if (c.hasFlags(FLAG_IS_DISPLAY) && c.getStartRotation() != c.getEndRotation()
|
||||
&& c.getContainer() != null) {
|
||||
t.unsetFixedTransformHint(WindowContainer.fromBinder(c.getContainer().asBinder())
|
||||
.asDisplayContent().mSurfaceControl);
|
||||
}
|
||||
}
|
||||
for (int i = info.getRootCount() - 1; i >= 0; --i) {
|
||||
final SurfaceControl leash = info.getRoot(i).getLeash();
|
||||
|
||||
@@ -725,6 +725,7 @@ class TransitionController {
|
||||
// Run state-validation checks when no transitions are active anymore.
|
||||
if (!inTransition()) {
|
||||
validateStates();
|
||||
mAtm.mWindowManager.onAnimationFinished();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
android:turnScreenOn="true"
|
||||
android:showWhenLocked="true" />
|
||||
<activity android:name="com.android.server.wm.ActivityOptionsTest$MainActivity"
|
||||
android:configChanges="screenLayout|screenSize|smallestScreenSize|orientation"
|
||||
android:turnScreenOn="true"
|
||||
android:showWhenLocked="true" />
|
||||
<activity android:name="com.android.server.wm.ScreenshotTests$ScreenshotActivity"
|
||||
|
||||
@@ -16,19 +16,34 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Parcel;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Class for testing {@link SurfaceControl}.
|
||||
*
|
||||
@@ -106,6 +121,50 @@ public class SurfaceControlTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSurfaceChangedOnRotation() {
|
||||
final Instrumentation instrumentation = getInstrumentation();
|
||||
final Context context = instrumentation.getContext();
|
||||
final Activity activity = instrumentation.startActivitySync(new Intent().setComponent(
|
||||
new ComponentName(context, ActivityOptionsTest.MainActivity.class))
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
final SurfaceView sv = new SurfaceView(activity);
|
||||
final AtomicInteger surfaceChangedCount = new AtomicInteger();
|
||||
instrumentation.runOnMainSync(() -> activity.setContentView(sv));
|
||||
sv.getHolder().addCallback(new SurfaceHolder.Callback() {
|
||||
@Override
|
||||
public void surfaceCreated(@NonNull SurfaceHolder holder) {
|
||||
}
|
||||
@Override
|
||||
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
|
||||
int height) {
|
||||
surfaceChangedCount.getAndIncrement();
|
||||
Log.i("surfaceChanged", "width=" + width + " height=" + height
|
||||
+ " getTransformHint="
|
||||
+ sv.getViewRootImpl().getSurfaceControl().getTransformHint());
|
||||
}
|
||||
@Override
|
||||
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
|
||||
}
|
||||
});
|
||||
final int rotation = activity.getResources().getConfiguration()
|
||||
.windowConfiguration.getRotation();
|
||||
activity.setRequestedOrientation(activity.getResources().getConfiguration().orientation
|
||||
== Configuration.ORIENTATION_PORTRAIT
|
||||
? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
: ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
instrumentation.getUiAutomation().syncInputTransactions();
|
||||
instrumentation.waitForIdleSync();
|
||||
final int newRotation = activity.getResources().getConfiguration()
|
||||
.windowConfiguration.getRotation();
|
||||
final int count = surfaceChangedCount.get();
|
||||
activity.finishAndRemoveTask();
|
||||
// The first count is triggered from creation, so the target number is 2.
|
||||
if (rotation != newRotation && count > 2) {
|
||||
fail("More than once surfaceChanged for rotation change: " + count);
|
||||
}
|
||||
}
|
||||
|
||||
private SurfaceControl buildTestSurface() {
|
||||
return new SurfaceControl.Builder()
|
||||
.setContainerLayer()
|
||||
|
||||
Reference in New Issue
Block a user