Loading core/java/android/view/ImeInsetsSourceConsumer.java +1 −1 Original line number Diff line number Diff line Loading @@ -217,6 +217,6 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } private InputMethodManager getImm() { return mController.getViewRoot().mContext.getSystemService(InputMethodManager.class); return mController.getHost().getInputMethodManager(); } } core/java/android/view/InsetsController.java +128 −120 Original line number Diff line number Diff line Loading @@ -37,9 +37,7 @@ import android.graphics.Insets; import android.graphics.Rect; import android.os.CancellationSignal; import android.os.Handler; import android.os.RemoteException; import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.view.InsetsSourceConsumer.ShowResult; Loading @@ -53,6 +51,7 @@ import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.animation.PathInterpolator; import android.view.inputmethod.InputMethodManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; Loading @@ -72,6 +71,91 @@ import java.util.function.BiFunction; */ public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks { public interface Host { Handler getHandler(); /** * Notifies host that {@link InsetsController#getState()} has changed. */ void notifyInsetsChanged(); void dispatchWindowInsetsAnimationPrepare(@NonNull WindowInsetsAnimation animation); Bounds dispatchWindowInsetsAnimationStart( @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds); WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations); void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation); /** * Requests host to apply surface params in synchronized manner. */ void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params); /** * @see ViewRootImpl#updateCompatSysUiVisibility(int, boolean, boolean) */ void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible, boolean hasControl); /** * Called when insets have been modified by the client and should be reported back to WM. */ void onInsetsModified(InsetsState insetsState); /** * @return Whether the host has any callbacks it wants to synchronize the animations with. * If there are no callbacks, the animation will be off-loaded to another thread and * slightly different animation curves are picked. */ boolean hasAnimationCallbacks(); /** * @see WindowInsetsController#setSystemBarsAppearance */ void setSystemBarsAppearance(@Appearance int appearance, @Appearance int mask); /** * @see WindowInsetsController#getSystemBarsAppearance() */ @Appearance int getSystemBarsAppearance(); /** * @see WindowInsetsController#setSystemBarsBehavior */ void setSystemBarsBehavior(@Behavior int behavior); /** * @see WindowInsetsController#getSystemBarsBehavior */ @Behavior int getSystemBarsBehavior(); /** * Releases a surface and ensure that this is done after {@link #applySurfaceParams} has * finished applying params. */ void releaseSurfaceControlFromRt(SurfaceControl surfaceControl); /** * If this host is a view hierarchy, adds a pre-draw runnable to ensure proper ordering as * described in {@link WindowInsetsAnimation.Callback#onPrepare}. * * If this host isn't a view hierarchy, the runnable can be executed immediately. */ void addOnPreDrawRunnable(Runnable r); /** * Adds a runnbale to be executed during {@link Choreographer#CALLBACK_INSETS_ANIMATION} * phase. */ void postInsetsAnimationCallback(Runnable r); /** * Obtains {@link InputMethodManager} instance from host. */ InputMethodManager getInputMethodManager(); } private static final int ANIMATION_DURATION_SHOW_MS = 275; private static final int ANIMATION_DURATION_HIDE_MS = 340; Loading Loading @@ -346,7 +430,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final Rect mFrame = new Rect(); private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator; private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); private final ViewRootImpl mViewRoot; private final Host mHost; private final Handler mHandler; private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); Loading @@ -370,8 +454,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private boolean mStartingAnimation; private int mCaptionInsetsHeight = 0; private SyncRtSurfaceTransactionApplier mApplier; private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest; private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners = new ArrayList<>(); Loading @@ -379,22 +461,22 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation /** Set of inset types for which an animation was started since last resetting this field */ private @InsetsType int mLastStartedAnimTypes; public InsetsController(ViewRootImpl viewRoot) { this(viewRoot, (controller, type) -> { public InsetsController(Host host) { this(host, (controller, type) -> { if (type == ITYPE_IME) { return new ImeInsetsSourceConsumer(controller.mState, Transaction::new, controller); } else { return new InsetsSourceConsumer(type, controller.mState, Transaction::new, controller); } }, viewRoot.mHandler); }, host.getHandler()); } @VisibleForTesting public InsetsController(ViewRootImpl viewRoot, public InsetsController(Host host, BiFunction<InsetsController, Integer, InsetsSourceConsumer> consumerCreator, Handler handler) { mViewRoot = viewRoot; mHost = host; mConsumerCreator = consumerCreator; mHandler = handler; mAnimCallback = () -> { Loading @@ -402,10 +484,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (mRunningAnimations.isEmpty()) { return; } if (mViewRoot.mView == null) { // The view has already detached from window. return; } mTmpFinishedControls.clear(); mTmpRunningAnims.clear(); Loading Loading @@ -433,8 +511,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeSystemBars(), mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacySystemUiFlags, null /* typeSideMap */); mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims); mHost.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims); for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) { dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation()); Loading @@ -447,7 +524,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (mFrame.equals(frame)) { return; } mViewRoot.notifyInsetsChanged(); mHost.notifyInsetsChanged(); mFrame.set(frame); } Loading Loading @@ -476,7 +553,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mLastDispachedState.set(state, true /* copySources */); applyLocalVisibilityOverride(); if (localStateChanged) { mViewRoot.notifyInsetsChanged(); mHost.notifyInsetsChanged(); } if (!mState.equals(mLastDispachedState, true /* excludingCaptionInsets */)) { sendStateToWindowManager(); Loading Loading @@ -733,7 +810,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final InsetsAnimationControlRunner runner = useInsetsAnimationThread ? new InsetsAnimationThreadControlRunner(controls, frame, mState, listener, typesReady, this, durationMs, interpolator, animationType, mViewRoot.mHandler) animationType, mHost.getHandler()) : new InsetsAnimationControlImpl(controls, frame, mState, listener, typesReady, this, durationMs, interpolator, animationType); Loading Loading @@ -860,21 +937,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params) { if (mApplier == null) { if (mViewRoot.mView == null) { throw new IllegalStateException("View of the ViewRootImpl is not initiated."); } mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView); } if (mViewRoot.mView.isHardwareAccelerated()) { mApplier.scheduleApply(false /* earlyWakeup */, params); } else { // Window doesn't support hardware acceleration, no synchronization for now. // TODO(b/149342281): use mViewRoot.mSurface.getNextFrameNumber() to sync on every // frame instead. mApplier.applyParams(new Transaction(), -1 /* frame */, false /* earlyWakeup */, params); } mHost.applySurfaceParams(params); } void notifyControlRevoked(InsetsSourceConsumer consumer) { Loading @@ -900,7 +963,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation ArraySet<Integer> types = toInternalType(control.getTypes()); for (int j = types.size() - 1; j >= 0; j--) { if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) { mViewRoot.notifyInsetsChanged(); mHost.notifyInsetsChanged(); } } break; Loading Loading @@ -928,7 +991,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @VisibleForTesting public void notifyVisibilityChanged() { mViewRoot.notifyInsetsChanged(); mHost.notifyInsetsChanged(); sendStateToWindowManager(); } Loading @@ -937,7 +1000,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation */ public void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible, boolean hasControl) { mViewRoot.updateCompatSysUiVisibility(type, visible, hasControl); mHost.updateCompatSysUiVisibility(type, visible, hasControl); } /** Loading @@ -954,10 +1017,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation getSourceConsumer(ITYPE_IME).onWindowFocusLost(); } ViewRootImpl getViewRoot() { return mViewRoot; } /** * Used by {@link ImeInsetsSourceConsumer} when IME decides to be shown/hidden. * @hide Loading Loading @@ -994,12 +1053,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation tmpState.addSource(mState.getSource(consumer.getType())); } } try { mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, tmpState); } catch (RemoteException e) { Log.e(TAG, "Failed to call insetsModified", e); } mHost.onInsetsModified(tmpState); } @VisibleForTesting Loading @@ -1009,7 +1063,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return; } boolean hasAnimationCallbacks = hasAnimationCallbacks(); boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks(); final InternalAnimationControlListener listener = new InternalAnimationControlListener(show, hasAnimationCallbacks, types); Loading @@ -1024,13 +1078,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } private boolean hasAnimationCallbacks() { if (mViewRoot.mView == null) { return false; } return mViewRoot.mView.hasWindowInsetsAnimationCallback(); } private void hideDirectly( @InsetsType int types, boolean animationFinished, @AnimationType int animationType) { final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types); Loading Loading @@ -1064,16 +1111,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public void startAnimation(InsetsAnimationControlImpl controller, WindowInsetsAnimationControlListener listener, int types, WindowInsetsAnimation animation, Bounds bounds) { if (mViewRoot.mView == null) { return; } mViewRoot.mView.dispatchWindowInsetsAnimationPrepare(animation); mViewRoot.mView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() { @Override public boolean onPreDraw() { mViewRoot.mView.getViewTreeObserver().removeOnPreDrawListener(this); mHost.dispatchWindowInsetsAnimationPrepare(animation); mHost.addOnPreDrawRunnable(() -> { if (controller.isCancelled()) { return true; return; } for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { RunningAnimation runningAnimation = mRunningAnimations.get(i); Loading @@ -1081,20 +1122,17 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation runningAnimation.startDispatched = true; } } mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds); mHost.dispatchWindowInsetsAnimationStart(animation, bounds); mStartingAnimation = true; controller.mReadyDispatched = true; listener.onReady(controller, types); mStartingAnimation = false; return true; } }); mViewRoot.mView.invalidate(); } @VisibleForTesting public void dispatchAnimationEnd(WindowInsetsAnimation animation) { mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation); mHost.dispatchWindowInsetsAnimationEnd(animation); } @VisibleForTesting Loading @@ -1106,30 +1144,19 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return; } if (!mAnimCallbackScheduled) { mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION, mAnimCallback, null /* token*/); mHost.postInsetsAnimationCallback(mAnimCallback); mAnimCallbackScheduled = true; } } @Override public void setSystemBarsAppearance(@Appearance int appearance, @Appearance int mask) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_APPEARANCE_CONTROLLED; final InsetsFlags insetsFlags = mViewRoot.mWindowAttributes.insetsFlags; if (insetsFlags.appearance != appearance) { insetsFlags.appearance = (insetsFlags.appearance & ~mask) | (appearance & mask); mViewRoot.mWindowAttributesChanged = true; mViewRoot.scheduleTraversals(); } mHost.setSystemBarsAppearance(appearance, mask); } @Override public @Appearance int getSystemBarsAppearance() { if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) { // We only return the requested appearance, not the implied one. return 0; } return mViewRoot.mWindowAttributes.insetsFlags.appearance; return mHost.getSystemBarsAppearance(); } @Override Loading @@ -1139,21 +1166,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void setSystemBarsBehavior(@Behavior int behavior) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED; if (mViewRoot.mWindowAttributes.insetsFlags.behavior != behavior) { mViewRoot.mWindowAttributes.insetsFlags.behavior = behavior; mViewRoot.mWindowAttributesChanged = true; mViewRoot.scheduleTraversals(); } mHost.setSystemBarsBehavior(behavior); } @Override public @Appearance int getSystemBarsBehavior() { if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) { // We only return the requested behavior, not the implied one. return 0; } return mViewRoot.mWindowAttributes.insetsFlags.behavior; return mHost.getSystemBarsBehavior(); } private @InsetsType int calculateControllableTypes() { Loading Loading @@ -1198,22 +1216,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mControllableInsetsChangedListeners.remove(listener); } /** * At the time we receive new leashes (e.g. InsetsSourceConsumer is processing * setControl) we need to release the old leash. But we may have already scheduled * a SyncRtSurfaceTransaction applier to use it from the RenderThread. To avoid * synchronization issues we also release from the RenderThread so this release * happens after any existing items on the work queue. */ @Override public void releaseSurfaceControlFromRt(SurfaceControl sc) { if (mViewRoot.mView != null && mViewRoot.mView.isHardwareAccelerated()) { mViewRoot.registerRtFrameCallback(frame -> { sc.release(); }); // Make sure a frame gets scheduled. mViewRoot.mView.invalidate(); } else { sc.release(); mHost.releaseSurfaceControlFromRt(sc); } Host getHost() { return mHost; } } core/java/android/view/ViewRootImpl.java +1 −1 Original line number Diff line number Diff line Loading @@ -757,7 +757,7 @@ public final class ViewRootImpl implements ViewParent, mChoreographer = useSfChoreographer ? Choreographer.getSfInstance() : Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mInsetsController = new InsetsController(this); mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this)); String processorOverrideName = context.getResources().getString( R.string.config_inputEventCompatProcessorOverrideClassName); Loading core/java/android/view/ViewRootInsetsControllerHost.java 0 → 100644 +215 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; import android.annotation.NonNull; import android.os.Handler; import android.os.RemoteException; import android.util.Log; import android.view.inputmethod.InputMethodManager; import java.util.List; /** * Implements {@link InsetsController.Host} for {@link ViewRootImpl}s. * @hide */ public class ViewRootInsetsControllerHost implements InsetsController.Host { private final String TAG = "VRInsetsControllerHost"; private final ViewRootImpl mViewRoot; private SyncRtSurfaceTransactionApplier mApplier; public ViewRootInsetsControllerHost(ViewRootImpl viewRoot) { mViewRoot = viewRoot; } @Override public Handler getHandler() { return mViewRoot.mHandler; } @Override public void notifyInsetsChanged() { mViewRoot.notifyInsetsChanged(); } @Override public void addOnPreDrawRunnable(Runnable r) { if (mViewRoot.mView == null) { return; } mViewRoot.mView.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mViewRoot.mView.getViewTreeObserver().removeOnPreDrawListener(this); r.run(); return true; } }); mViewRoot.mView.invalidate(); } @Override public void dispatchWindowInsetsAnimationPrepare(@NonNull WindowInsetsAnimation animation) { if (mViewRoot.mView == null) { return; } mViewRoot.mView.dispatchWindowInsetsAnimationPrepare(animation); } @Override public WindowInsetsAnimation.Bounds dispatchWindowInsetsAnimationStart( @NonNull WindowInsetsAnimation animation, @NonNull WindowInsetsAnimation.Bounds bounds) { if (mViewRoot.mView == null) { return null; } return mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds); } @Override public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations) { if (mViewRoot.mView == null) { // The view has already detached from window. return null; } return mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets, runningAnimations); } @Override public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation); } @Override public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params) { if (mApplier == null) { if (mViewRoot.mView == null) { throw new IllegalStateException("View of the ViewRootImpl is not initiated."); } mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView); } if (mViewRoot.mView.isHardwareAccelerated()) { mApplier.scheduleApply(false /* earlyWakeup */, params); } else { // Window doesn't support hardware acceleration, no synchronization for now. // TODO(b/149342281): use mViewRoot.mSurface.getNextFrameNumber() to sync on every // frame instead. mApplier.applyParams(new SurfaceControl.Transaction(), -1 /* frame */, false /* earlyWakeup */, params); } } @Override public void postInsetsAnimationCallback(Runnable r) { mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION, r, null /* token */); } @Override public void updateCompatSysUiVisibility(int type, boolean visible, boolean hasControl) { mViewRoot.updateCompatSysUiVisibility(type, visible, hasControl); } @Override public void onInsetsModified(InsetsState insetsState) { try { mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, insetsState); } catch (RemoteException e) { Log.e(TAG, "Failed to call insetsModified", e); } } @Override public boolean hasAnimationCallbacks() { if (mViewRoot.mView == null) { return false; } return mViewRoot.mView.hasWindowInsetsAnimationCallback(); } @Override public void setSystemBarsAppearance(int appearance, int mask) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_APPEARANCE_CONTROLLED; final InsetsFlags insetsFlags = mViewRoot.mWindowAttributes.insetsFlags; if (insetsFlags.appearance != appearance) { insetsFlags.appearance = (insetsFlags.appearance & ~mask) | (appearance & mask); mViewRoot.mWindowAttributesChanged = true; mViewRoot.scheduleTraversals(); } } @Override public int getSystemBarsAppearance() { if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) { // We only return the requested appearance, not the implied one. return 0; } return mViewRoot.mWindowAttributes.insetsFlags.appearance; } @Override public void setSystemBarsBehavior(int behavior) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED; if (mViewRoot.mWindowAttributes.insetsFlags.behavior != behavior) { mViewRoot.mWindowAttributes.insetsFlags.behavior = behavior; mViewRoot.mWindowAttributesChanged = true; mViewRoot.scheduleTraversals(); } } @Override public int getSystemBarsBehavior() { if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) { // We only return the requested behavior, not the implied one. return 0; } return mViewRoot.mWindowAttributes.insetsFlags.behavior; } @Override public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) { // At the time we receive new leashes (e.g. InsetsSourceConsumer is processing // setControl) we need to release the old leash. But we may have already scheduled // a SyncRtSurfaceTransaction applier to use it from the RenderThread. To avoid // synchronization issues we also release from the RenderThread so this release // happens after any existing items on the work queue. if (mViewRoot.mView != null && mViewRoot.mView.isHardwareAccelerated()) { mViewRoot.registerRtFrameCallback(frame -> { surfaceControl.release(); }); // Make sure a frame gets scheduled. mViewRoot.mView.invalidate(); } else { surfaceControl.release(); } } @Override public InputMethodManager getInputMethodManager() { return mViewRoot.mContext.getSystemService(InputMethodManager.class); } } core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java +2 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/view/ImeInsetsSourceConsumer.java +1 −1 Original line number Diff line number Diff line Loading @@ -217,6 +217,6 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } private InputMethodManager getImm() { return mController.getViewRoot().mContext.getSystemService(InputMethodManager.class); return mController.getHost().getInputMethodManager(); } }
core/java/android/view/InsetsController.java +128 −120 Original line number Diff line number Diff line Loading @@ -37,9 +37,7 @@ import android.graphics.Insets; import android.graphics.Rect; import android.os.CancellationSignal; import android.os.Handler; import android.os.RemoteException; import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.view.InsetsSourceConsumer.ShowResult; Loading @@ -53,6 +51,7 @@ import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.animation.PathInterpolator; import android.view.inputmethod.InputMethodManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; Loading @@ -72,6 +71,91 @@ import java.util.function.BiFunction; */ public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks { public interface Host { Handler getHandler(); /** * Notifies host that {@link InsetsController#getState()} has changed. */ void notifyInsetsChanged(); void dispatchWindowInsetsAnimationPrepare(@NonNull WindowInsetsAnimation animation); Bounds dispatchWindowInsetsAnimationStart( @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds); WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations); void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation); /** * Requests host to apply surface params in synchronized manner. */ void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params); /** * @see ViewRootImpl#updateCompatSysUiVisibility(int, boolean, boolean) */ void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible, boolean hasControl); /** * Called when insets have been modified by the client and should be reported back to WM. */ void onInsetsModified(InsetsState insetsState); /** * @return Whether the host has any callbacks it wants to synchronize the animations with. * If there are no callbacks, the animation will be off-loaded to another thread and * slightly different animation curves are picked. */ boolean hasAnimationCallbacks(); /** * @see WindowInsetsController#setSystemBarsAppearance */ void setSystemBarsAppearance(@Appearance int appearance, @Appearance int mask); /** * @see WindowInsetsController#getSystemBarsAppearance() */ @Appearance int getSystemBarsAppearance(); /** * @see WindowInsetsController#setSystemBarsBehavior */ void setSystemBarsBehavior(@Behavior int behavior); /** * @see WindowInsetsController#getSystemBarsBehavior */ @Behavior int getSystemBarsBehavior(); /** * Releases a surface and ensure that this is done after {@link #applySurfaceParams} has * finished applying params. */ void releaseSurfaceControlFromRt(SurfaceControl surfaceControl); /** * If this host is a view hierarchy, adds a pre-draw runnable to ensure proper ordering as * described in {@link WindowInsetsAnimation.Callback#onPrepare}. * * If this host isn't a view hierarchy, the runnable can be executed immediately. */ void addOnPreDrawRunnable(Runnable r); /** * Adds a runnbale to be executed during {@link Choreographer#CALLBACK_INSETS_ANIMATION} * phase. */ void postInsetsAnimationCallback(Runnable r); /** * Obtains {@link InputMethodManager} instance from host. */ InputMethodManager getInputMethodManager(); } private static final int ANIMATION_DURATION_SHOW_MS = 275; private static final int ANIMATION_DURATION_HIDE_MS = 340; Loading Loading @@ -346,7 +430,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final Rect mFrame = new Rect(); private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator; private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); private final ViewRootImpl mViewRoot; private final Host mHost; private final Handler mHandler; private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); Loading @@ -370,8 +454,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private boolean mStartingAnimation; private int mCaptionInsetsHeight = 0; private SyncRtSurfaceTransactionApplier mApplier; private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest; private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners = new ArrayList<>(); Loading @@ -379,22 +461,22 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation /** Set of inset types for which an animation was started since last resetting this field */ private @InsetsType int mLastStartedAnimTypes; public InsetsController(ViewRootImpl viewRoot) { this(viewRoot, (controller, type) -> { public InsetsController(Host host) { this(host, (controller, type) -> { if (type == ITYPE_IME) { return new ImeInsetsSourceConsumer(controller.mState, Transaction::new, controller); } else { return new InsetsSourceConsumer(type, controller.mState, Transaction::new, controller); } }, viewRoot.mHandler); }, host.getHandler()); } @VisibleForTesting public InsetsController(ViewRootImpl viewRoot, public InsetsController(Host host, BiFunction<InsetsController, Integer, InsetsSourceConsumer> consumerCreator, Handler handler) { mViewRoot = viewRoot; mHost = host; mConsumerCreator = consumerCreator; mHandler = handler; mAnimCallback = () -> { Loading @@ -402,10 +484,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (mRunningAnimations.isEmpty()) { return; } if (mViewRoot.mView == null) { // The view has already detached from window. return; } mTmpFinishedControls.clear(); mTmpRunningAnims.clear(); Loading Loading @@ -433,8 +511,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeSystemBars(), mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacySystemUiFlags, null /* typeSideMap */); mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims); mHost.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims); for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) { dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation()); Loading @@ -447,7 +524,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (mFrame.equals(frame)) { return; } mViewRoot.notifyInsetsChanged(); mHost.notifyInsetsChanged(); mFrame.set(frame); } Loading Loading @@ -476,7 +553,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mLastDispachedState.set(state, true /* copySources */); applyLocalVisibilityOverride(); if (localStateChanged) { mViewRoot.notifyInsetsChanged(); mHost.notifyInsetsChanged(); } if (!mState.equals(mLastDispachedState, true /* excludingCaptionInsets */)) { sendStateToWindowManager(); Loading Loading @@ -733,7 +810,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final InsetsAnimationControlRunner runner = useInsetsAnimationThread ? new InsetsAnimationThreadControlRunner(controls, frame, mState, listener, typesReady, this, durationMs, interpolator, animationType, mViewRoot.mHandler) animationType, mHost.getHandler()) : new InsetsAnimationControlImpl(controls, frame, mState, listener, typesReady, this, durationMs, interpolator, animationType); Loading Loading @@ -860,21 +937,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params) { if (mApplier == null) { if (mViewRoot.mView == null) { throw new IllegalStateException("View of the ViewRootImpl is not initiated."); } mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView); } if (mViewRoot.mView.isHardwareAccelerated()) { mApplier.scheduleApply(false /* earlyWakeup */, params); } else { // Window doesn't support hardware acceleration, no synchronization for now. // TODO(b/149342281): use mViewRoot.mSurface.getNextFrameNumber() to sync on every // frame instead. mApplier.applyParams(new Transaction(), -1 /* frame */, false /* earlyWakeup */, params); } mHost.applySurfaceParams(params); } void notifyControlRevoked(InsetsSourceConsumer consumer) { Loading @@ -900,7 +963,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation ArraySet<Integer> types = toInternalType(control.getTypes()); for (int j = types.size() - 1; j >= 0; j--) { if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) { mViewRoot.notifyInsetsChanged(); mHost.notifyInsetsChanged(); } } break; Loading Loading @@ -928,7 +991,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @VisibleForTesting public void notifyVisibilityChanged() { mViewRoot.notifyInsetsChanged(); mHost.notifyInsetsChanged(); sendStateToWindowManager(); } Loading @@ -937,7 +1000,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation */ public void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible, boolean hasControl) { mViewRoot.updateCompatSysUiVisibility(type, visible, hasControl); mHost.updateCompatSysUiVisibility(type, visible, hasControl); } /** Loading @@ -954,10 +1017,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation getSourceConsumer(ITYPE_IME).onWindowFocusLost(); } ViewRootImpl getViewRoot() { return mViewRoot; } /** * Used by {@link ImeInsetsSourceConsumer} when IME decides to be shown/hidden. * @hide Loading Loading @@ -994,12 +1053,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation tmpState.addSource(mState.getSource(consumer.getType())); } } try { mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, tmpState); } catch (RemoteException e) { Log.e(TAG, "Failed to call insetsModified", e); } mHost.onInsetsModified(tmpState); } @VisibleForTesting Loading @@ -1009,7 +1063,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return; } boolean hasAnimationCallbacks = hasAnimationCallbacks(); boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks(); final InternalAnimationControlListener listener = new InternalAnimationControlListener(show, hasAnimationCallbacks, types); Loading @@ -1024,13 +1078,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } private boolean hasAnimationCallbacks() { if (mViewRoot.mView == null) { return false; } return mViewRoot.mView.hasWindowInsetsAnimationCallback(); } private void hideDirectly( @InsetsType int types, boolean animationFinished, @AnimationType int animationType) { final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types); Loading Loading @@ -1064,16 +1111,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public void startAnimation(InsetsAnimationControlImpl controller, WindowInsetsAnimationControlListener listener, int types, WindowInsetsAnimation animation, Bounds bounds) { if (mViewRoot.mView == null) { return; } mViewRoot.mView.dispatchWindowInsetsAnimationPrepare(animation); mViewRoot.mView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() { @Override public boolean onPreDraw() { mViewRoot.mView.getViewTreeObserver().removeOnPreDrawListener(this); mHost.dispatchWindowInsetsAnimationPrepare(animation); mHost.addOnPreDrawRunnable(() -> { if (controller.isCancelled()) { return true; return; } for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { RunningAnimation runningAnimation = mRunningAnimations.get(i); Loading @@ -1081,20 +1122,17 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation runningAnimation.startDispatched = true; } } mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds); mHost.dispatchWindowInsetsAnimationStart(animation, bounds); mStartingAnimation = true; controller.mReadyDispatched = true; listener.onReady(controller, types); mStartingAnimation = false; return true; } }); mViewRoot.mView.invalidate(); } @VisibleForTesting public void dispatchAnimationEnd(WindowInsetsAnimation animation) { mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation); mHost.dispatchWindowInsetsAnimationEnd(animation); } @VisibleForTesting Loading @@ -1106,30 +1144,19 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return; } if (!mAnimCallbackScheduled) { mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION, mAnimCallback, null /* token*/); mHost.postInsetsAnimationCallback(mAnimCallback); mAnimCallbackScheduled = true; } } @Override public void setSystemBarsAppearance(@Appearance int appearance, @Appearance int mask) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_APPEARANCE_CONTROLLED; final InsetsFlags insetsFlags = mViewRoot.mWindowAttributes.insetsFlags; if (insetsFlags.appearance != appearance) { insetsFlags.appearance = (insetsFlags.appearance & ~mask) | (appearance & mask); mViewRoot.mWindowAttributesChanged = true; mViewRoot.scheduleTraversals(); } mHost.setSystemBarsAppearance(appearance, mask); } @Override public @Appearance int getSystemBarsAppearance() { if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) { // We only return the requested appearance, not the implied one. return 0; } return mViewRoot.mWindowAttributes.insetsFlags.appearance; return mHost.getSystemBarsAppearance(); } @Override Loading @@ -1139,21 +1166,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void setSystemBarsBehavior(@Behavior int behavior) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED; if (mViewRoot.mWindowAttributes.insetsFlags.behavior != behavior) { mViewRoot.mWindowAttributes.insetsFlags.behavior = behavior; mViewRoot.mWindowAttributesChanged = true; mViewRoot.scheduleTraversals(); } mHost.setSystemBarsBehavior(behavior); } @Override public @Appearance int getSystemBarsBehavior() { if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) { // We only return the requested behavior, not the implied one. return 0; } return mViewRoot.mWindowAttributes.insetsFlags.behavior; return mHost.getSystemBarsBehavior(); } private @InsetsType int calculateControllableTypes() { Loading Loading @@ -1198,22 +1216,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mControllableInsetsChangedListeners.remove(listener); } /** * At the time we receive new leashes (e.g. InsetsSourceConsumer is processing * setControl) we need to release the old leash. But we may have already scheduled * a SyncRtSurfaceTransaction applier to use it from the RenderThread. To avoid * synchronization issues we also release from the RenderThread so this release * happens after any existing items on the work queue. */ @Override public void releaseSurfaceControlFromRt(SurfaceControl sc) { if (mViewRoot.mView != null && mViewRoot.mView.isHardwareAccelerated()) { mViewRoot.registerRtFrameCallback(frame -> { sc.release(); }); // Make sure a frame gets scheduled. mViewRoot.mView.invalidate(); } else { sc.release(); mHost.releaseSurfaceControlFromRt(sc); } Host getHost() { return mHost; } }
core/java/android/view/ViewRootImpl.java +1 −1 Original line number Diff line number Diff line Loading @@ -757,7 +757,7 @@ public final class ViewRootImpl implements ViewParent, mChoreographer = useSfChoreographer ? Choreographer.getSfInstance() : Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mInsetsController = new InsetsController(this); mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this)); String processorOverrideName = context.getResources().getString( R.string.config_inputEventCompatProcessorOverrideClassName); Loading
core/java/android/view/ViewRootInsetsControllerHost.java 0 → 100644 +215 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; import android.annotation.NonNull; import android.os.Handler; import android.os.RemoteException; import android.util.Log; import android.view.inputmethod.InputMethodManager; import java.util.List; /** * Implements {@link InsetsController.Host} for {@link ViewRootImpl}s. * @hide */ public class ViewRootInsetsControllerHost implements InsetsController.Host { private final String TAG = "VRInsetsControllerHost"; private final ViewRootImpl mViewRoot; private SyncRtSurfaceTransactionApplier mApplier; public ViewRootInsetsControllerHost(ViewRootImpl viewRoot) { mViewRoot = viewRoot; } @Override public Handler getHandler() { return mViewRoot.mHandler; } @Override public void notifyInsetsChanged() { mViewRoot.notifyInsetsChanged(); } @Override public void addOnPreDrawRunnable(Runnable r) { if (mViewRoot.mView == null) { return; } mViewRoot.mView.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mViewRoot.mView.getViewTreeObserver().removeOnPreDrawListener(this); r.run(); return true; } }); mViewRoot.mView.invalidate(); } @Override public void dispatchWindowInsetsAnimationPrepare(@NonNull WindowInsetsAnimation animation) { if (mViewRoot.mView == null) { return; } mViewRoot.mView.dispatchWindowInsetsAnimationPrepare(animation); } @Override public WindowInsetsAnimation.Bounds dispatchWindowInsetsAnimationStart( @NonNull WindowInsetsAnimation animation, @NonNull WindowInsetsAnimation.Bounds bounds) { if (mViewRoot.mView == null) { return null; } return mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds); } @Override public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations) { if (mViewRoot.mView == null) { // The view has already detached from window. return null; } return mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets, runningAnimations); } @Override public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation); } @Override public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params) { if (mApplier == null) { if (mViewRoot.mView == null) { throw new IllegalStateException("View of the ViewRootImpl is not initiated."); } mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView); } if (mViewRoot.mView.isHardwareAccelerated()) { mApplier.scheduleApply(false /* earlyWakeup */, params); } else { // Window doesn't support hardware acceleration, no synchronization for now. // TODO(b/149342281): use mViewRoot.mSurface.getNextFrameNumber() to sync on every // frame instead. mApplier.applyParams(new SurfaceControl.Transaction(), -1 /* frame */, false /* earlyWakeup */, params); } } @Override public void postInsetsAnimationCallback(Runnable r) { mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION, r, null /* token */); } @Override public void updateCompatSysUiVisibility(int type, boolean visible, boolean hasControl) { mViewRoot.updateCompatSysUiVisibility(type, visible, hasControl); } @Override public void onInsetsModified(InsetsState insetsState) { try { mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, insetsState); } catch (RemoteException e) { Log.e(TAG, "Failed to call insetsModified", e); } } @Override public boolean hasAnimationCallbacks() { if (mViewRoot.mView == null) { return false; } return mViewRoot.mView.hasWindowInsetsAnimationCallback(); } @Override public void setSystemBarsAppearance(int appearance, int mask) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_APPEARANCE_CONTROLLED; final InsetsFlags insetsFlags = mViewRoot.mWindowAttributes.insetsFlags; if (insetsFlags.appearance != appearance) { insetsFlags.appearance = (insetsFlags.appearance & ~mask) | (appearance & mask); mViewRoot.mWindowAttributesChanged = true; mViewRoot.scheduleTraversals(); } } @Override public int getSystemBarsAppearance() { if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) { // We only return the requested appearance, not the implied one. return 0; } return mViewRoot.mWindowAttributes.insetsFlags.appearance; } @Override public void setSystemBarsBehavior(int behavior) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED; if (mViewRoot.mWindowAttributes.insetsFlags.behavior != behavior) { mViewRoot.mWindowAttributes.insetsFlags.behavior = behavior; mViewRoot.mWindowAttributesChanged = true; mViewRoot.scheduleTraversals(); } } @Override public int getSystemBarsBehavior() { if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) { // We only return the requested behavior, not the implied one. return 0; } return mViewRoot.mWindowAttributes.insetsFlags.behavior; } @Override public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) { // At the time we receive new leashes (e.g. InsetsSourceConsumer is processing // setControl) we need to release the old leash. But we may have already scheduled // a SyncRtSurfaceTransaction applier to use it from the RenderThread. To avoid // synchronization issues we also release from the RenderThread so this release // happens after any existing items on the work queue. if (mViewRoot.mView != null && mViewRoot.mView.isHardwareAccelerated()) { mViewRoot.registerRtFrameCallback(frame -> { surfaceControl.release(); }); // Make sure a frame gets scheduled. mViewRoot.mView.invalidate(); } else { surfaceControl.release(); } } @Override public InputMethodManager getInputMethodManager() { return mViewRoot.mContext.getSystemService(InputMethodManager.class); } }
core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java +2 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes