summaryrefslogtreecommitdiff
path: root/core/java/android/view/ViewRootInsetsControllerHost.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/view/ViewRootInsetsControllerHost.java')
-rw-r--r--core/java/android/view/ViewRootInsetsControllerHost.java252
1 files changed, 252 insertions, 0 deletions
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
new file mode 100644
index 000000000000..90a80cefc54d
--- /dev/null
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -0,0 +1,252 @@
+/*
+ * 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.InsetsController.DEBUG;
+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.IBinder;
+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;
+ }
+ if (DEBUG) Log.d(TAG, "windowInsetsAnimation started");
+ 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;
+ }
+ if (DEBUG) {
+ for (WindowInsetsAnimation anim : runningAnimations) {
+ Log.d(TAG, "windowInsetsAnimation progress: "
+ + anim.getInterpolatedFraction());
+ }
+ }
+ return mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets, runningAnimations);
+ }
+
+ @Override
+ public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) {
+ if (DEBUG) Log.d(TAG, "windowInsetsAnimation ended");
+ mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation);
+ }
+
+ @Override
+ public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
+ if (mViewRoot.mView == null) {
+ throw new IllegalStateException("View of the ViewRootImpl is not initiated.");
+ }
+ if (mApplier == null) {
+ mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView);
+ }
+ if (mViewRoot.mView.isHardwareAccelerated()) {
+ mApplier.scheduleApply(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 */, 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);
+ }
+
+ @Override
+ public String getRootViewTitle() {
+ if (mViewRoot == null) {
+ return null;
+ }
+ return mViewRoot.getTitle().toString();
+ }
+
+ @Override
+ public int dipToPx(int dips) {
+ if (mViewRoot != null) {
+ return mViewRoot.dipToPx(dips);
+ }
+ return 0;
+ }
+
+ @Override
+ public IBinder getWindowToken() {
+ if (mViewRoot == null) {
+ return null;
+ }
+ final View view = mViewRoot.getView();
+ if (view == null) {
+ return null;
+ }
+ return view.getWindowToken();
+ }
+}