Decouple InsetsController from ViewRootImpl

Such that all it's goodness can also be used in context when
ViewRootImpl isn't available, like the SystemUI controller used
for Car and Split

Test: InsetsControllerTest
Fixes: 154631128
Change-Id: I54a3f8a34810472d9273e4627a7811b7abd0863f
This commit is contained in:
Jorim Jaggi
2020-04-22 17:18:25 +02:00
parent 6b25213d68
commit bf87c15b33
7 changed files with 352 additions and 126 deletions

View File

@@ -217,6 +217,6 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
}
private InputMethodManager getImm() {
return mController.getViewRoot().mContext.getSystemService(InputMethodManager.class);
return mController.getHost().getInputMethodManager();
}
}

View File

@@ -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;
@@ -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;
@@ -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;
@@ -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<>();
@@ -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<>();
@@ -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 = () -> {
@@ -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();
@@ -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());
@@ -447,7 +524,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (mFrame.equals(frame)) {
return;
}
mViewRoot.notifyInsetsChanged();
mHost.notifyInsetsChanged();
mFrame.set(frame);
}
@@ -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();
@@ -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);
@@ -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) {
@@ -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;
@@ -928,7 +991,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public void notifyVisibilityChanged() {
mViewRoot.notifyInsetsChanged();
mHost.notifyInsetsChanged();
sendStateToWindowManager();
}
@@ -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);
}
/**
@@ -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
@@ -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
@@ -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);
@@ -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);
@@ -1064,37 +1111,28 @@ 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);
if (controller.isCancelled()) {
return true;
}
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == controller) {
runningAnimation.startDispatched = true;
}
}
mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds);
mStartingAnimation = true;
controller.mReadyDispatched = true;
listener.onReady(controller, types);
mStartingAnimation = false;
return true;
mHost.dispatchWindowInsetsAnimationPrepare(animation);
mHost.addOnPreDrawRunnable(() -> {
if (controller.isCancelled()) {
return;
}
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == controller) {
runningAnimation.startDispatched = true;
}
}
mHost.dispatchWindowInsetsAnimationStart(animation, bounds);
mStartingAnimation = true;
controller.mReadyDispatched = true;
listener.onReady(controller, types);
mStartingAnimation = false;
});
mViewRoot.mView.invalidate();
}
@VisibleForTesting
public void dispatchAnimationEnd(WindowInsetsAnimation animation) {
mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation);
mHost.dispatchWindowInsetsAnimationEnd(animation);
}
@VisibleForTesting
@@ -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
@@ -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() {
@@ -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;
}
}

View File

@@ -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);

View File

@@ -0,0 +1,215 @@
/*
* 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);
}
}