diff options
12 files changed, 194 insertions, 136 deletions
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index e90b1c0fc167..229e8ee75844 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -26,7 +26,6 @@ import android.annotation.Nullable; import android.os.IBinder; import android.os.Trace; import android.util.proto.ProtoOutputStream; -import android.view.SurfaceControl.Transaction; import android.view.inputmethod.Flags; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InputMethodManager; @@ -34,8 +33,6 @@ import android.view.inputmethod.InputMethodManager; import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.SoftInputShowHideReason; -import java.util.function.Supplier; - /** * Controls the visibility and animations of IME window insets source. * @hide @@ -54,10 +51,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { */ private boolean mIsRequestedVisibleAwaitingLeash; - public ImeInsetsSourceConsumer( - int id, InsetsState state, Supplier<Transaction> transactionSupplier, - InsetsController controller) { - super(id, WindowInsets.Type.ime(), state, transactionSupplier, controller); + public ImeInsetsSourceConsumer(int id, InsetsState state, InsetsController controller) { + super(id, WindowInsets.Type.ime(), state, controller); } @Override diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java index 04bb6091672b..a0d8a173c3e5 100644 --- a/core/java/android/view/InsetsAnimationControlCallbacks.java +++ b/core/java/android/view/InsetsAnimationControlCallbacks.java @@ -54,13 +54,6 @@ public interface InsetsAnimationControlCallbacks { void notifyFinished(InsetsAnimationControlRunner runner, boolean shown); /** - * Apply the new params to the surface. - * @param params The {@link android.view.SyncRtSurfaceTransactionApplier.SurfaceParams} to - * apply. - */ - void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params); - - /** * Post a message to release the Surface, guaranteed to happen after all * previous calls to applySurfaceParams. */ diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 91e9230cdc6a..97facc1ba472 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -99,6 +99,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro private final @InsetsType int mTypes; private @InsetsType int mControllingTypes; private final InsetsAnimationControlCallbacks mController; + private final SurfaceParamsApplier mSurfaceParamsApplier; private final WindowInsetsAnimation mAnimation; private final long mDurationMs; private final Interpolator mInterpolator; @@ -123,6 +124,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls, @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener, @InsetsType int types, InsetsAnimationControlCallbacks controller, + SurfaceParamsApplier surfaceParamsApplier, InsetsAnimationSpec insetsAnimationSpec, @AnimationType int animationType, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation, CompatibilityInfo.Translator translator, @Nullable ImeTracker.Token statsToken) { @@ -131,6 +133,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro mTypes = types; mControllingTypes = types; mController = controller; + mSurfaceParamsApplier = surfaceParamsApplier; mInitialInsetsState = new InsetsState(state, true /* copySources */); if (frame != null) { final SparseIntArray idSideMap = new SparseIntArray(); @@ -258,6 +261,11 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro } @Override + public SurfaceParamsApplier getSurfaceParamsApplier() { + return mSurfaceParamsApplier; + } + + @Override @Nullable public ImeTracker.Token getStatsToken() { return mStatsToken; @@ -305,7 +313,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro updateLeashesForSide(SIDE_RIGHT, offset.right, params, outState, mPendingAlpha); updateLeashesForSide(SIDE_BOTTOM, offset.bottom, params, outState, mPendingAlpha); - mController.applySurfaceParams(params.toArray(new SurfaceParams[params.size()])); + mSurfaceParamsApplier.applySurfaceParams(params.toArray(new SurfaceParams[params.size()])); mCurrentInsets = mPendingInsets; mAnimation.setFraction(mPendingFraction); mCurrentAlpha = mPendingAlpha; diff --git a/core/java/android/view/InsetsAnimationControlRunner.java b/core/java/android/view/InsetsAnimationControlRunner.java index 8cb8b47dd0ec..4f102da4692a 100644 --- a/core/java/android/view/InsetsAnimationControlRunner.java +++ b/core/java/android/view/InsetsAnimationControlRunner.java @@ -77,6 +77,11 @@ public interface InsetsAnimationControlRunner { @AnimationType int getAnimationType(); /** + * @return The {@link SurfaceParamsApplier} this runner is using. + */ + SurfaceParamsApplier getSurfaceParamsApplier(); + + /** * @return The token tracking the current IME request or {@code null} otherwise. */ @Nullable @@ -99,4 +104,27 @@ public interface InsetsAnimationControlRunner { * @param fieldId FieldId of the implementation class */ void dumpDebug(ProtoOutputStream proto, long fieldId); + + /** + * Interface applying given surface operations. + */ + interface SurfaceParamsApplier { + + SurfaceParamsApplier DEFAULT = params -> { + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + for (int i = params.length - 1; i >= 0; i--) { + SyncRtSurfaceTransactionApplier.applyParams(t, params[i], new float[9]); + } + t.apply(); + t.close(); + }; + + /** + * Apply the new params to the surface. + * + * @param params The {@link SyncRtSurfaceTransactionApplier.SurfaceParams} to apply. + */ + void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params); + + } } diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java index fc185bc73735..8c2c4951a9f7 100644 --- a/core/java/android/view/InsetsAnimationThreadControlRunner.java +++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java @@ -17,7 +17,6 @@ package android.view; import static android.view.InsetsController.DEBUG; -import static android.view.SyncRtSurfaceTransactionApplier.applyParams; import android.annotation.Nullable; import android.annotation.UiThread; @@ -30,7 +29,6 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import android.view.InsetsController.AnimationType; import android.view.InsetsController.LayoutInsetsDuringAnimation; -import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsAnimation.Bounds; import android.view.inputmethod.ImeTracker; @@ -50,8 +48,6 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro private final InsetsAnimationControlCallbacks mCallbacks = new InsetsAnimationControlCallbacks() { - private final float[] mTmpFloat9 = new float[9]; - @Override @UiThread public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController> @@ -81,19 +77,6 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro } @Override - public void applySurfaceParams(SurfaceParams... params) { - if (DEBUG) Log.d(TAG, "applySurfaceParams"); - SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - for (int i = params.length - 1; i >= 0; i--) { - SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i]; - applyParams(t, surfaceParams, mTmpFloat9); - } - t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId()); - t.apply(); - t.close(); - } - - @Override public void releaseSurfaceControlFromRt(SurfaceControl sc) { if (DEBUG) Log.d(TAG, "releaseSurfaceControlFromRt"); // Since we don't push the SurfaceParams to the RT we can release directly @@ -106,6 +89,22 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro } }; + private SurfaceParamsApplier mSurfaceParamsApplier = new SurfaceParamsApplier() { + + private final float[] mTmpFloat9 = new float[9]; + + @Override + public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params) { + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + for (int i = params.length - 1; i >= 0; i--) { + SyncRtSurfaceTransactionApplier.applyParams(t, params[i], mTmpFloat9); + } + t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId()); + t.apply(); + t.close(); + } + }; + @UiThread public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls, @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener, @@ -117,8 +116,8 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro mMainThreadHandler = mainThreadHandler; mOuterCallbacks = controller; mControl = new InsetsAnimationControlImpl(controls, frame, state, listener, types, - mCallbacks, insetsAnimationSpec, animationType, layoutInsetsDuringAnimation, - translator, statsToken); + mCallbacks, mSurfaceParamsApplier, insetsAnimationSpec, animationType, + layoutInsetsDuringAnimation, translator, statsToken); InsetsAnimationThread.getHandler().post(() -> { if (mControl.isCancelled()) { return; @@ -187,6 +186,11 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro } @Override + public SurfaceParamsApplier getSurfaceParamsApplier() { + return mSurfaceParamsApplier; + } + + @Override public void updateLayoutInsetsDuringAnimation( @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { InsetsAnimationThread.getHandler().post( diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 8fdf91a2d87c..e38281ffd020 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -55,7 +55,6 @@ import android.util.Pair; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import android.view.InsetsSourceConsumer.ShowResult; -import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsAnimation.Bounds; @@ -85,7 +84,8 @@ import java.util.Objects; * Implements {@link WindowInsetsController} on the client. * @hide */ -public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks { +public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks, + InsetsAnimationControlRunner.SurfaceParamsApplier { private int mTypesBeingCancelled; @@ -307,7 +307,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } /** Not running an animation. */ - @VisibleForTesting public static final int ANIMATION_TYPE_NONE = -1; /** Running animation will show insets */ @@ -317,11 +316,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public static final int ANIMATION_TYPE_HIDE = 1; /** Running animation is controlled by user via {@link #controlWindowInsetsAnimation} */ - @VisibleForTesting(visibility = PACKAGE) public static final int ANIMATION_TYPE_USER = 2; /** Running animation will resize insets */ - @VisibleForTesting public static final int ANIMATION_TYPE_RESIZE = 3; @Retention(RetentionPolicy.SOURCE) @@ -757,11 +754,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public InsetsController(Host host) { this(host, (controller, id, type) -> { if (!Flags.refactorInsetsController() && type == ime()) { - return new ImeInsetsSourceConsumer(id, controller.mState, - Transaction::new, controller); + return new ImeInsetsSourceConsumer(id, controller.mState, controller); } else { - return new InsetsSourceConsumer(id, type, controller.mState, - Transaction::new, controller); + return new InsetsSourceConsumer(id, type, controller.mState, controller); } }, host.getHandler()); } @@ -1525,9 +1520,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation insetsAnimationSpec, animationType, layoutInsetsDuringAnimation, mHost.getTranslator(), mHost.getHandler(), statsToken) : new InsetsAnimationControlImpl(controls, - frame, mState, listener, typesReady, this, insetsAnimationSpec, + frame, mState, listener, typesReady, this, this, insetsAnimationSpec, animationType, layoutInsetsDuringAnimation, mHost.getTranslator(), statsToken); + for (int i = controls.size() - 1; i >= 0; i--) { + final InsetsSourceConsumer consumer = mSourceConsumers.get(controls.keyAt(i)); + if (consumer != null) { + consumer.setSurfaceParamsApplier(runner.getSurfaceParamsApplier()); + } + } if ((typesReady & WindowInsets.Type.ime()) != 0) { ImeTracing.getInstance().triggerClientDump("InsetsAnimationControlImpl", mHost.getInputMethodManager(), null /* icProto */); diff --git a/core/java/android/view/InsetsResizeAnimationRunner.java b/core/java/android/view/InsetsResizeAnimationRunner.java index f90b8411e333..5262751cc6ed 100644 --- a/core/java/android/view/InsetsResizeAnimationRunner.java +++ b/core/java/android/view/InsetsResizeAnimationRunner.java @@ -94,6 +94,11 @@ public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner } @Override + public SurfaceParamsApplier getSurfaceParamsApplier() { + return SurfaceParamsApplier.DEFAULT; + } + + @Override @Nullable public ImeTracker.Token getStatsToken() { // Return null as resizing the IME view is not explicitly tracked. diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index 391d757365e6..2e2ff1d49dfe 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -17,6 +17,7 @@ package android.view; import static android.view.InsetsController.ANIMATION_TYPE_NONE; +import static android.view.InsetsController.ANIMATION_TYPE_RESIZE; import static android.view.InsetsController.AnimationType; import static android.view.InsetsController.DEBUG; import static android.view.InsetsSourceConsumerProto.ANIMATION_STATE; @@ -32,12 +33,13 @@ import static com.android.window.flags.Flags.insetsControlSeq; import android.annotation.IntDef; import android.annotation.Nullable; +import android.graphics.Matrix; +import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.text.TextUtils; import android.util.Log; import android.util.proto.ProtoOutputStream; -import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type.InsetsType; import android.view.inputmethod.Flags; import android.view.inputmethod.ImeTracker; @@ -48,7 +50,6 @@ import com.android.internal.inputmethod.ImeTracing; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; -import java.util.function.Supplier; /** * Controls the visibility and animations of a single window insets source. @@ -92,10 +93,12 @@ public class InsetsSourceConsumer { private final int mType; private static final String TAG = "InsetsSourceConsumer"; - private final Supplier<Transaction> mTransactionSupplier; @Nullable private InsetsSourceControl mSourceControl; private boolean mHasWindowFocus; + private InsetsAnimationControlRunner.SurfaceParamsApplier mSurfaceParamsApplier = + InsetsAnimationControlRunner.SurfaceParamsApplier.DEFAULT; + private final Matrix mTmpMatrix = new Matrix(); /** * Whether the view has focus returned by {@link #onWindowFocusGained(boolean)}. @@ -108,16 +111,13 @@ public class InsetsSourceConsumer { * @param id The ID of the consumed insets. * @param type The {@link InsetsType} of the consumed insets. * @param state The current {@link InsetsState} of the consumed insets. - * @param transactionSupplier The source of new {@link Transaction} instances. The supplier - * must provide *new* instances, which will be explicitly closed by this class. * @param controller The {@link InsetsController} to use for insets interaction. */ public InsetsSourceConsumer(int id, @InsetsType int type, InsetsState state, - Supplier<Transaction> transactionSupplier, InsetsController controller) { + InsetsController controller) { mId = id; mType = type; mState = state; - mTransactionSupplier = transactionSupplier; mController = controller; } @@ -162,6 +162,9 @@ public class InsetsSourceConsumer { if (localVisible != serverVisible) { mController.notifyVisibilityChanged(); } + + // Reset the applier to the default one which has the most lightweight implementation. + setSurfaceParamsApplier(InsetsAnimationControlRunner.SurfaceParamsApplier.DEFAULT); } else { final boolean requestedVisible = isRequestedVisibleAwaitingControl(); final SurfaceControl oldLeash = lastControl != null ? lastControl.getLeash() : null; @@ -184,10 +187,11 @@ public class InsetsSourceConsumer { mController.notifyVisibilityChanged(); } - // If we have a new leash, make sure visibility is up-to-date, even though we - // didn't want to run an animation above. - if (mController.getAnimationType(mType) == ANIMATION_TYPE_NONE) { - applyRequestedVisibilityToControl(); + // If there is no animation controlling the leash, make sure the visibility and the + // position is up-to-date. Note: ANIMATION_TYPE_RESIZE doesn't control the leash. + final int animType = mController.getAnimationType(mType); + if (animType == ANIMATION_TYPE_NONE || animType == ANIMATION_TYPE_RESIZE) { + applyRequestedVisibilityAndPositionToControl(); } // Remove the surface that owned by last control when it lost. @@ -229,6 +233,15 @@ public class InsetsSourceConsumer { } /** + * Sets the SurfaceParamsApplier that the latest animation runner is using. The leash owned by + * this class is always applied by the applier, so that the transaction order can always be + * aligned with the calling sequence. + */ + void setSurfaceParamsApplier(InsetsAnimationControlRunner.SurfaceParamsApplier applier) { + mSurfaceParamsApplier = applier; + } + + /** * Called right after the animation is started or finished. */ @VisibleForTesting(visibility = PACKAGE) @@ -431,24 +444,30 @@ public class InsetsSourceConsumer { if (DEBUG) Log.d(TAG, "updateSource: " + newSource); } - private void applyRequestedVisibilityToControl() { - if (mSourceControl == null || mSourceControl.getLeash() == null) { + private void applyRequestedVisibilityAndPositionToControl() { + if (mSourceControl == null) { return; } - - final boolean requestedVisible = (mController.getRequestedVisibleTypes() & mType) != 0; - try (Transaction t = mTransactionSupplier.get()) { - if (DEBUG) Log.d(TAG, "applyRequestedVisibilityToControl: " + requestedVisible); - if (requestedVisible) { - t.show(mSourceControl.getLeash()); - } else { - t.hide(mSourceControl.getLeash()); - } - // Ensure the alpha value is aligned with the actual requested visibility. - t.setAlpha(mSourceControl.getLeash(), requestedVisible ? 1 : 0); - t.apply(); + final SurfaceControl leash = mSourceControl.getLeash(); + if (leash == null) { + return; } - onPerceptible(requestedVisible); + + final boolean visible = (mController.getRequestedVisibleTypes() & mType) != 0; + final Point surfacePosition = mSourceControl.getSurfacePosition(); + + if (DEBUG) Log.d(TAG, "applyRequestedVisibilityAndPositionToControl: visible=" + visible + + " position=" + surfacePosition); + + mTmpMatrix.setTranslate(surfacePosition.x, surfacePosition.y); + mSurfaceParamsApplier.applySurfaceParams( + new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(leash) + .withVisibility(visible) + .withAlpha(visible ? 1 : 0) + .withMatrix(mTmpMatrix) + .build()); + + onPerceptible(visible); } void dumpDebug(ProtoOutputStream proto, long fieldId) { diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java index 786f1e84728d..ba6f62c6ed19 100644 --- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java @@ -38,7 +38,6 @@ import android.graphics.Rect; import android.graphics.RectF; import android.platform.test.annotations.Presubmit; import android.util.SparseArray; -import android.view.SurfaceControl.Transaction; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; @@ -79,7 +78,6 @@ public class InsetsAnimationControlImplTest { private SurfaceControl mNavLeash; private InsetsState mInsetsState; - @Mock Transaction mMockTransaction; @Mock InsetsController mMockController; @Mock WindowInsetsAnimationControlListener mMockListener; @@ -98,16 +96,14 @@ public class InsetsAnimationControlImplTest { mInsetsState.getOrCreateSource(ID_NAVIGATION_BAR, navigationBars()) .setFrame(new Rect(400, 0, 500, 500)); InsetsSourceConsumer topConsumer = new InsetsSourceConsumer(ID_STATUS_BAR, - WindowInsets.Type.statusBars(), mInsetsState, - () -> mMockTransaction, mMockController); + WindowInsets.Type.statusBars(), mInsetsState, mMockController); topConsumer.setControl( new InsetsSourceControl(ID_STATUS_BAR, WindowInsets.Type.statusBars(), mStatusLeash, true, new Point(0, 0), Insets.of(0, 100, 0, 0)), new int[1], new int[1]); InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(ID_NAVIGATION_BAR, - WindowInsets.Type.navigationBars(), mInsetsState, - () -> mMockTransaction, mMockController); + WindowInsets.Type.navigationBars(), mInsetsState, mMockController); navConsumer.setControl( new InsetsSourceControl(ID_NAVIGATION_BAR, WindowInsets.Type.navigationBars(), mNavLeash, true, new Point(400, 0), Insets.of(0, 0, 100, 0)), @@ -131,8 +127,9 @@ public class InsetsAnimationControlImplTest { mController = new InsetsAnimationControlImpl(controls, new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(), - mMockController, spec /* insetsAnimationSpecCreator */, 0 /* animationType */, - 0 /* layoutInsetsDuringAnimation */, null /* translator */, null /* statsToken */); + mMockController, mMockController, spec /* insetsAnimationSpecCreator */, + 0 /* animationType */, 0 /* layoutInsetsDuringAnimation */, null /* translator */, + null /* statsToken */); mController.setReadyDispatched(true); } diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index bec8b1f76394..4516e9ce72fc 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -63,7 +63,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.CancellationSignal; import android.platform.test.annotations.Presubmit; -import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsController.OnControllableInsetsChangedListener; import android.view.WindowManager.BadTokenException; @@ -138,8 +137,7 @@ public class InsetsControllerTest { mTestHost = spy(new TestHost(mViewRoot)); mController = new InsetsController(mTestHost, (controller, id, type) -> { if (!Flags.refactorInsetsController() && type == ime()) { - return new InsetsSourceConsumer(id, type, controller.getState(), - Transaction::new, controller) { + return new InsetsSourceConsumer(id, type, controller.getState(), controller) { private boolean mImeRequestedShow; @@ -155,8 +153,7 @@ public class InsetsControllerTest { } }; } else { - return new InsetsSourceConsumer(id, type, controller.getState(), - Transaction::new, controller); + return new InsetsSourceConsumer(id, type, controller.getState(), controller); } }, mTestHandler); final Rect rect = new Rect(5, 5, 5, 5); diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java index 655cb4519d3c..d6d45e839f2f 100644 --- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java @@ -28,10 +28,7 @@ import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; import android.app.Instrumentation; import android.content.Context; @@ -39,7 +36,6 @@ import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; -import android.view.SurfaceControl.Transaction; import android.view.WindowManager.BadTokenException; import android.view.WindowManager.LayoutParams; import android.view.inputmethod.ImeTracker; @@ -51,7 +47,6 @@ import androidx.test.platform.app.InstrumentationRegistry; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -75,9 +70,9 @@ public class InsetsSourceConsumerTest { private SurfaceSession mSession = new SurfaceSession(); private SurfaceControl mLeash; - @Mock Transaction mMockTransaction; private InsetsSource mSpyInsetsSource; private boolean mRemoveSurfaceCalled = false; + private boolean mSurfaceParamsApplied = false; private InsetsController mController; private InsetsState mState; private ViewRootImpl mViewRoot; @@ -102,9 +97,14 @@ public class InsetsSourceConsumerTest { mSpyInsetsSource = Mockito.spy(new InsetsSource(ID_STATUS_BAR, statusBars())); mState.addSource(mSpyInsetsSource); - mController = new InsetsController(new ViewRootInsetsControllerHost(mViewRoot)); - mConsumer = new InsetsSourceConsumer(ID_STATUS_BAR, statusBars(), mState, - () -> mMockTransaction, mController) { + mController = new InsetsController(new ViewRootInsetsControllerHost(mViewRoot)) { + @Override + public void applySurfaceParams( + final SyncRtSurfaceTransactionApplier.SurfaceParams... params) { + mSurfaceParamsApplied = true; + } + }; + mConsumer = new InsetsSourceConsumer(ID_STATUS_BAR, statusBars(), mState, mController) { @Override public void removeSurface() { super.removeSurface(); @@ -148,8 +148,7 @@ public class InsetsSourceConsumerTest { InsetsState state = new InsetsState(); InsetsController controller = new InsetsController(new ViewRootInsetsControllerHost( mViewRoot)); - InsetsSourceConsumer consumer = new InsetsSourceConsumer( - ID_IME, ime(), state, null, controller); + InsetsSourceConsumer consumer = new InsetsSourceConsumer(ID_IME, ime(), state, controller); InsetsSource source = new InsetsSource(ID_IME, ime()); source.setFrame(0, 1, 2, 3); @@ -182,9 +181,9 @@ public class InsetsSourceConsumerTest { public void testRestore() { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { mConsumer.setControl(null, new int[1], new int[1]); - reset(mMockTransaction); + mSurfaceParamsApplied = false; mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars()); - verifyZeroInteractions(mMockTransaction); + assertFalse(mSurfaceParamsApplied); int[] hideTypes = new int[1]; mConsumer.setControl( new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash, @@ -200,8 +199,9 @@ public class InsetsSourceConsumerTest { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars()); mConsumer.setControl(null, new int[1], new int[1]); - reset(mMockTransaction); - verifyZeroInteractions(mMockTransaction); + mLeash = new SurfaceControl.Builder(mSession) + .setName("testSurface") + .build(); mRemoveSurfaceCalled = false; int[] hideTypes = new int[1]; mConsumer.setControl( @@ -221,8 +221,7 @@ public class InsetsSourceConsumerTest { ViewRootInsetsControllerHost host = new ViewRootInsetsControllerHost(mViewRoot); InsetsController insetsController = new InsetsController(host, (ic, id, type) -> { if (type == ime()) { - return new InsetsSourceConsumer(ID_IME, ime(), state, - () -> mMockTransaction, ic) { + return new InsetsSourceConsumer(ID_IME, ime(), state, ic) { @Override public int requestShow(boolean fromController, ImeTracker.Token statsToken) { @@ -230,14 +229,14 @@ public class InsetsSourceConsumerTest { } }; } - return new InsetsSourceConsumer(id, type, ic.getState(), Transaction::new, ic); + return new InsetsSourceConsumer(id, type, ic.getState(), ic); }, host.getHandler()); InsetsSourceConsumer imeConsumer = insetsController.getSourceConsumer(ID_IME, ime()); // Initial IME insets source control with its leash. imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash, false /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]); - reset(mMockTransaction); + mSurfaceParamsApplied = false; // Verify when the app requests controlling show IME animation, the IME leash // visibility won't be updated when the consumer received the same leash in setControl. @@ -246,7 +245,7 @@ public class InsetsSourceConsumerTest { assertEquals(ANIMATION_TYPE_USER, insetsController.getAnimationType(ime())); imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash, true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]); - verify(mMockTransaction, never()).show(mLeash); + assertFalse(mSurfaceParamsApplied); }); } } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index f0a4763796e3..57b879277326 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -75,7 +75,8 @@ class InsetsSourceProvider { private final Rect mTmpRect = new Rect(); private final InsetsSourceControl mFakeControl; - private final Consumer<Transaction> mSetLeashPositionConsumer; + private final Point mPosition = new Point(); + private final Consumer<Transaction> mSetControlPositionConsumer; private @Nullable InsetsControlTarget mPendingControlTarget; private @Nullable InsetsControlTarget mFakeControlTarget; @@ -126,13 +127,14 @@ class InsetsSourceProvider { source.getId(), source.getType(), null /* leash */, false /* initialVisible */, new Point(), Insets.NONE); mControllable = (InsetsPolicy.CONTROLLABLE_TYPES & source.getType()) != 0; - mSetLeashPositionConsumer = t -> { - if (mControl != null) { - final SurfaceControl leash = mControl.getLeash(); - if (leash != null) { - final Point position = mControl.getSurfacePosition(); - t.setPosition(leash, position.x, position.y); - } + mSetControlPositionConsumer = t -> { + if (mControl == null || mControlTarget == null) { + return; + } + boolean changed = mControl.setSurfacePosition(mPosition.x, mPosition.y); + final SurfaceControl leash = mControl.getLeash(); + if (changed && leash != null) { + t.setPosition(leash, mPosition.x, mPosition.y); } if (mHasPendingPosition) { mHasPendingPosition = false; @@ -140,9 +142,22 @@ class InsetsSourceProvider { mStateController.notifyControlTargetChanged(mPendingControlTarget, this); } } + changed |= updateInsetsHint(); + if (changed) { + mStateController.notifyControlChanged(mControlTarget, this); + } }; } + private boolean updateInsetsHint() { + final Insets insetsHint = getInsetsHint(); + if (!mControl.getInsetsHint().equals(insetsHint)) { + mControl.setInsetsHint(insetsHint); + return true; + } + return false; + } + InsetsSource getSource() { return mSource; } @@ -363,26 +378,32 @@ class InsetsSourceProvider { } final boolean serverVisibleChanged = mServerVisible != isServerVisible; setServerVisible(isServerVisible); - updateInsetsControlPosition(windowState, serverVisibleChanged); - } - - void updateInsetsControlPosition(WindowState windowState) { - updateInsetsControlPosition(windowState, false); + final boolean positionChanged = updateInsetsControlPosition(windowState); + if (mControl != null && !positionChanged + // The insets hint would be updated if the position is changed. Here updates it for + // the possible change of the bounds or the server visibility. + && (updateInsetsHint() + || serverVisibleChanged + && android.view.inputmethod.Flags.refactorInsetsController())) { + // Only call notifyControlChanged here when the position is not changed. Otherwise, it + // is called or is scheduled to be called during updateInsetsControlPosition. + mStateController.notifyControlChanged(mControlTarget, this); + } } - private void updateInsetsControlPosition(WindowState windowState, - boolean serverVisibleChanged) { + /** + * @return {#code true} if the surface position of the control is changed. + */ + boolean updateInsetsControlPosition(WindowState windowState) { if (mControl == null) { - return; + return false; } - boolean changed = false; final Point position = getWindowFrameSurfacePosition(); - if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) { - changed = true; + if (!mPosition.equals(position)) { + mPosition.set(position.x, position.y); if (windowState != null && windowState.getWindowFrames().didFrameSizeChange() && windowState.mWinAnimator.getShown() && mWindowContainer.okToDisplay()) { - mHasPendingPosition = true; - windowState.applyWithNextDraw(mSetLeashPositionConsumer); + windowState.applyWithNextDraw(mSetControlPositionConsumer); } else { Transaction t = mWindowContainer.getSyncTransaction(); if (windowState != null) { @@ -399,20 +420,11 @@ class InsetsSourceProvider { } } } - mSetLeashPositionConsumer.accept(t); + mSetControlPositionConsumer.accept(t); } + return true; } - final Insets insetsHint = getInsetsHint(); - if (!mControl.getInsetsHint().equals(insetsHint)) { - mControl.setInsetsHint(insetsHint); - changed = true; - } - if (android.view.inputmethod.Flags.refactorInsetsController() && serverVisibleChanged) { - changed = true; - } - if (changed) { - mStateController.notifyControlChanged(mControlTarget, this); - } + return false; } private Point getWindowFrameSurfacePosition() { |