Merge "Decouple InsetsController from ViewRootImpl" into rvc-dev am: 1db61c9a6e
Change-Id: Iacebd870781140b735ba7cabd27d63a1a6fea68f
This commit is contained in:
@@ -217,6 +217,6 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private InputMethodManager getImm() {
|
private InputMethodManager getImm() {
|
||||||
return mController.getViewRoot().mContext.getSystemService(InputMethodManager.class);
|
return mController.getHost().getInputMethodManager();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,7 @@ import android.graphics.Insets;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.CancellationSignal;
|
import android.os.CancellationSignal;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.InsetsSourceConsumer.ShowResult;
|
import android.view.InsetsSourceConsumer.ShowResult;
|
||||||
@@ -53,6 +51,7 @@ import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
|
|||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
import android.view.animation.LinearInterpolator;
|
import android.view.animation.LinearInterpolator;
|
||||||
import android.view.animation.PathInterpolator;
|
import android.view.animation.PathInterpolator;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
|
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
|
||||||
@@ -72,6 +71,91 @@ import java.util.function.BiFunction;
|
|||||||
*/
|
*/
|
||||||
public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks {
|
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_SHOW_MS = 275;
|
||||||
private static final int ANIMATION_DURATION_HIDE_MS = 340;
|
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 Rect mFrame = new Rect();
|
||||||
private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator;
|
private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator;
|
||||||
private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();
|
private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();
|
||||||
private final ViewRootImpl mViewRoot;
|
private final Host mHost;
|
||||||
private final Handler mHandler;
|
private final Handler mHandler;
|
||||||
|
|
||||||
private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
|
private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
|
||||||
@@ -370,8 +454,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
private boolean mStartingAnimation;
|
private boolean mStartingAnimation;
|
||||||
private int mCaptionInsetsHeight = 0;
|
private int mCaptionInsetsHeight = 0;
|
||||||
|
|
||||||
private SyncRtSurfaceTransactionApplier mApplier;
|
|
||||||
|
|
||||||
private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
|
private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
|
||||||
private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
|
private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
|
||||||
= new ArrayList<>();
|
= 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 */
|
/** Set of inset types for which an animation was started since last resetting this field */
|
||||||
private @InsetsType int mLastStartedAnimTypes;
|
private @InsetsType int mLastStartedAnimTypes;
|
||||||
|
|
||||||
public InsetsController(ViewRootImpl viewRoot) {
|
public InsetsController(Host host) {
|
||||||
this(viewRoot, (controller, type) -> {
|
this(host, (controller, type) -> {
|
||||||
if (type == ITYPE_IME) {
|
if (type == ITYPE_IME) {
|
||||||
return new ImeInsetsSourceConsumer(controller.mState, Transaction::new, controller);
|
return new ImeInsetsSourceConsumer(controller.mState, Transaction::new, controller);
|
||||||
} else {
|
} else {
|
||||||
return new InsetsSourceConsumer(type, controller.mState, Transaction::new,
|
return new InsetsSourceConsumer(type, controller.mState, Transaction::new,
|
||||||
controller);
|
controller);
|
||||||
}
|
}
|
||||||
}, viewRoot.mHandler);
|
}, host.getHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public InsetsController(ViewRootImpl viewRoot,
|
public InsetsController(Host host,
|
||||||
BiFunction<InsetsController, Integer, InsetsSourceConsumer> consumerCreator,
|
BiFunction<InsetsController, Integer, InsetsSourceConsumer> consumerCreator,
|
||||||
Handler handler) {
|
Handler handler) {
|
||||||
mViewRoot = viewRoot;
|
mHost = host;
|
||||||
mConsumerCreator = consumerCreator;
|
mConsumerCreator = consumerCreator;
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
mAnimCallback = () -> {
|
mAnimCallback = () -> {
|
||||||
@@ -402,10 +484,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
if (mRunningAnimations.isEmpty()) {
|
if (mRunningAnimations.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mViewRoot.mView == null) {
|
|
||||||
// The view has already detached from window.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mTmpFinishedControls.clear();
|
mTmpFinishedControls.clear();
|
||||||
mTmpRunningAnims.clear();
|
mTmpRunningAnims.clear();
|
||||||
@@ -433,8 +511,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeSystemBars(),
|
mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeSystemBars(),
|
||||||
mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacySystemUiFlags,
|
mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacySystemUiFlags,
|
||||||
null /* typeSideMap */);
|
null /* typeSideMap */);
|
||||||
mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets,
|
mHost.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims);
|
||||||
mUnmodifiableTmpRunningAnims);
|
|
||||||
|
|
||||||
for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) {
|
for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) {
|
||||||
dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation());
|
dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation());
|
||||||
@@ -447,7 +524,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
if (mFrame.equals(frame)) {
|
if (mFrame.equals(frame)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mViewRoot.notifyInsetsChanged();
|
mHost.notifyInsetsChanged();
|
||||||
mFrame.set(frame);
|
mFrame.set(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,7 +553,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
mLastDispachedState.set(state, true /* copySources */);
|
mLastDispachedState.set(state, true /* copySources */);
|
||||||
applyLocalVisibilityOverride();
|
applyLocalVisibilityOverride();
|
||||||
if (localStateChanged) {
|
if (localStateChanged) {
|
||||||
mViewRoot.notifyInsetsChanged();
|
mHost.notifyInsetsChanged();
|
||||||
}
|
}
|
||||||
if (!mState.equals(mLastDispachedState, true /* excludingCaptionInsets */)) {
|
if (!mState.equals(mLastDispachedState, true /* excludingCaptionInsets */)) {
|
||||||
sendStateToWindowManager();
|
sendStateToWindowManager();
|
||||||
@@ -733,7 +810,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
final InsetsAnimationControlRunner runner = useInsetsAnimationThread
|
final InsetsAnimationControlRunner runner = useInsetsAnimationThread
|
||||||
? new InsetsAnimationThreadControlRunner(controls,
|
? new InsetsAnimationThreadControlRunner(controls,
|
||||||
frame, mState, listener, typesReady, this, durationMs, interpolator,
|
frame, mState, listener, typesReady, this, durationMs, interpolator,
|
||||||
animationType, mViewRoot.mHandler)
|
animationType, mHost.getHandler())
|
||||||
: new InsetsAnimationControlImpl(controls,
|
: new InsetsAnimationControlImpl(controls,
|
||||||
frame, mState, listener, typesReady, this, durationMs, interpolator,
|
frame, mState, listener, typesReady, this, durationMs, interpolator,
|
||||||
animationType);
|
animationType);
|
||||||
@@ -860,21 +937,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
|
public void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
|
||||||
if (mApplier == null) {
|
mHost.applySurfaceParams(params);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyControlRevoked(InsetsSourceConsumer consumer) {
|
void notifyControlRevoked(InsetsSourceConsumer consumer) {
|
||||||
@@ -900,7 +963,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
ArraySet<Integer> types = toInternalType(control.getTypes());
|
ArraySet<Integer> types = toInternalType(control.getTypes());
|
||||||
for (int j = types.size() - 1; j >= 0; j--) {
|
for (int j = types.size() - 1; j >= 0; j--) {
|
||||||
if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) {
|
if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) {
|
||||||
mViewRoot.notifyInsetsChanged();
|
mHost.notifyInsetsChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -928,7 +991,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void notifyVisibilityChanged() {
|
public void notifyVisibilityChanged() {
|
||||||
mViewRoot.notifyInsetsChanged();
|
mHost.notifyInsetsChanged();
|
||||||
sendStateToWindowManager();
|
sendStateToWindowManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -937,7 +1000,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
*/
|
*/
|
||||||
public void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible,
|
public void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible,
|
||||||
boolean hasControl) {
|
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();
|
getSourceConsumer(ITYPE_IME).onWindowFocusLost();
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewRootImpl getViewRoot() {
|
|
||||||
return mViewRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by {@link ImeInsetsSourceConsumer} when IME decides to be shown/hidden.
|
* Used by {@link ImeInsetsSourceConsumer} when IME decides to be shown/hidden.
|
||||||
* @hide
|
* @hide
|
||||||
@@ -994,12 +1053,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
tmpState.addSource(mState.getSource(consumer.getType()));
|
tmpState.addSource(mState.getSource(consumer.getType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mHost.onInsetsModified(tmpState);
|
||||||
try {
|
|
||||||
mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, tmpState);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Failed to call insetsModified", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -1009,7 +1063,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasAnimationCallbacks = hasAnimationCallbacks();
|
boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
|
||||||
final InternalAnimationControlListener listener =
|
final InternalAnimationControlListener listener =
|
||||||
new InternalAnimationControlListener(show, hasAnimationCallbacks, types);
|
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(
|
private void hideDirectly(
|
||||||
@InsetsType int types, boolean animationFinished, @AnimationType int animationType) {
|
@InsetsType int types, boolean animationFinished, @AnimationType int animationType) {
|
||||||
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
|
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
|
||||||
@@ -1064,37 +1111,28 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
public void startAnimation(InsetsAnimationControlImpl controller,
|
public void startAnimation(InsetsAnimationControlImpl controller,
|
||||||
WindowInsetsAnimationControlListener listener, int types,
|
WindowInsetsAnimationControlListener listener, int types,
|
||||||
WindowInsetsAnimation animation, Bounds bounds) {
|
WindowInsetsAnimation animation, Bounds bounds) {
|
||||||
if (mViewRoot.mView == null) {
|
mHost.dispatchWindowInsetsAnimationPrepare(animation);
|
||||||
return;
|
mHost.addOnPreDrawRunnable(() -> {
|
||||||
}
|
if (controller.isCancelled()) {
|
||||||
mViewRoot.mView.dispatchWindowInsetsAnimationPrepare(animation);
|
return;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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
|
@VisibleForTesting
|
||||||
public void dispatchAnimationEnd(WindowInsetsAnimation animation) {
|
public void dispatchAnimationEnd(WindowInsetsAnimation animation) {
|
||||||
mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation);
|
mHost.dispatchWindowInsetsAnimationEnd(animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -1106,30 +1144,19 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!mAnimCallbackScheduled) {
|
if (!mAnimCallbackScheduled) {
|
||||||
mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION,
|
mHost.postInsetsAnimationCallback(mAnimCallback);
|
||||||
mAnimCallback, null /* token*/);
|
|
||||||
mAnimCallbackScheduled = true;
|
mAnimCallbackScheduled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSystemBarsAppearance(@Appearance int appearance, @Appearance int mask) {
|
public void setSystemBarsAppearance(@Appearance int appearance, @Appearance int mask) {
|
||||||
mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_APPEARANCE_CONTROLLED;
|
mHost.setSystemBarsAppearance(appearance, mask);
|
||||||
final InsetsFlags insetsFlags = mViewRoot.mWindowAttributes.insetsFlags;
|
|
||||||
if (insetsFlags.appearance != appearance) {
|
|
||||||
insetsFlags.appearance = (insetsFlags.appearance & ~mask) | (appearance & mask);
|
|
||||||
mViewRoot.mWindowAttributesChanged = true;
|
|
||||||
mViewRoot.scheduleTraversals();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Appearance int getSystemBarsAppearance() {
|
public @Appearance int getSystemBarsAppearance() {
|
||||||
if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) {
|
return mHost.getSystemBarsAppearance();
|
||||||
// We only return the requested appearance, not the implied one.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return mViewRoot.mWindowAttributes.insetsFlags.appearance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1139,21 +1166,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSystemBarsBehavior(@Behavior int behavior) {
|
public void setSystemBarsBehavior(@Behavior int behavior) {
|
||||||
mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
|
mHost.setSystemBarsBehavior(behavior);
|
||||||
if (mViewRoot.mWindowAttributes.insetsFlags.behavior != behavior) {
|
|
||||||
mViewRoot.mWindowAttributes.insetsFlags.behavior = behavior;
|
|
||||||
mViewRoot.mWindowAttributesChanged = true;
|
|
||||||
mViewRoot.scheduleTraversals();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Appearance int getSystemBarsBehavior() {
|
public @Appearance int getSystemBarsBehavior() {
|
||||||
if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) {
|
return mHost.getSystemBarsBehavior();
|
||||||
// We only return the requested behavior, not the implied one.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return mViewRoot.mWindowAttributes.insetsFlags.behavior;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @InsetsType int calculateControllableTypes() {
|
private @InsetsType int calculateControllableTypes() {
|
||||||
@@ -1198,22 +1216,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
mControllableInsetsChangedListeners.remove(listener);
|
mControllableInsetsChangedListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
public void releaseSurfaceControlFromRt(SurfaceControl sc) {
|
public void releaseSurfaceControlFromRt(SurfaceControl sc) {
|
||||||
if (mViewRoot.mView != null && mViewRoot.mView.isHardwareAccelerated()) {
|
mHost.releaseSurfaceControlFromRt(sc);
|
||||||
mViewRoot.registerRtFrameCallback(frame -> {
|
}
|
||||||
sc.release();
|
|
||||||
});
|
Host getHost() {
|
||||||
// Make sure a frame gets scheduled.
|
return mHost;
|
||||||
mViewRoot.mView.invalidate();
|
|
||||||
} else {
|
|
||||||
sc.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -757,7 +757,7 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
mChoreographer = useSfChoreographer
|
mChoreographer = useSfChoreographer
|
||||||
? Choreographer.getSfInstance() : Choreographer.getInstance();
|
? Choreographer.getSfInstance() : Choreographer.getInstance();
|
||||||
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
|
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
|
||||||
mInsetsController = new InsetsController(this);
|
mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
|
||||||
|
|
||||||
String processorOverrideName = context.getResources().getString(
|
String processorOverrideName = context.getResources().getString(
|
||||||
R.string.config_inputEventCompatProcessorOverrideClassName);
|
R.string.config_inputEventCompatProcessorOverrideClassName);
|
||||||
|
|||||||
215
core/java/android/view/ViewRootInsetsControllerHost.java
Normal file
215
core/java/android/view/ViewRootInsetsControllerHost.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,7 +78,8 @@ public class ImeInsetsSourceConsumerTest {
|
|||||||
} catch (BadTokenException e) {
|
} catch (BadTokenException e) {
|
||||||
// activity isn't running, we will ignore BadTokenException.
|
// activity isn't running, we will ignore BadTokenException.
|
||||||
}
|
}
|
||||||
mController = Mockito.spy(new InsetsController(viewRootImpl));
|
mController = Mockito.spy(new InsetsController(
|
||||||
|
new ViewRootInsetsControllerHost(viewRootImpl)));
|
||||||
final Rect rect = new Rect(5, 5, 5, 5);
|
final Rect rect = new Rect(5, 5, 5, 5);
|
||||||
mController.calculateInsets(
|
mController.calculateInsets(
|
||||||
false,
|
false,
|
||||||
|
|||||||
@@ -123,7 +123,8 @@ public class InsetsControllerTest {
|
|||||||
}
|
}
|
||||||
mTestClock = new OffsettableClock();
|
mTestClock = new OffsettableClock();
|
||||||
mTestHandler = new TestHandler(null, mTestClock);
|
mTestHandler = new TestHandler(null, mTestClock);
|
||||||
mController = new InsetsController(mViewRoot, (controller, type) -> {
|
mController = new InsetsController(new ViewRootInsetsControllerHost(mViewRoot),
|
||||||
|
(controller, type) -> {
|
||||||
if (type == ITYPE_IME) {
|
if (type == ITYPE_IME) {
|
||||||
return new InsetsSourceConsumer(type, controller.getState(),
|
return new InsetsSourceConsumer(type, controller.getState(),
|
||||||
Transaction::new, controller) {
|
Transaction::new, controller) {
|
||||||
|
|||||||
@@ -89,7 +89,8 @@ public class InsetsSourceConsumerTest {
|
|||||||
state.addSource(mSpyInsetsSource);
|
state.addSource(mSpyInsetsSource);
|
||||||
|
|
||||||
mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, state,
|
mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, state,
|
||||||
() -> mMockTransaction, new InsetsController(viewRootImpl));
|
() -> mMockTransaction,
|
||||||
|
new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl)));
|
||||||
});
|
});
|
||||||
instrumentation.waitForIdleSync();
|
instrumentation.waitForIdleSync();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user