diff options
| author | 2021-03-11 12:13:37 -0800 | |
|---|---|---|
| committer | 2021-03-30 04:10:05 +0000 | |
| commit | ee90cd4871121ae02da9b0b4d3fd7573084d729e (patch) | |
| tree | 219dd74c302eba9533dc2edeab8f94f0d44157fb | |
| parent | 64f83419987f126fe7bd1a0edfe95caa7076f8ac (diff) | |
Expose API for using SurfaceControl with ViewRootImpl
This API is appropriately called "ViewRoot". So far we just expose
an API surface to reparent SurfaceControl to the ViewRoot (but without
exposing the ViewRoot's SurfaceControl, to encourage developers not
to shoot themselves in the foot) and to synchronize with the drawing
of the ViewRoot SurfaceControl.
Bug: 173463039
Test: ViewRootSyncTests
Change-Id: I8ce0ed4b3efe50cdb3b71ae0f05ce25438d42368
| -rw-r--r-- | core/api/current.txt | 7 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 20 | ||||
| -rw-r--r-- | core/java/android/view/ViewRoot.java | 53 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 19 | ||||
| -rw-r--r-- | core/java/android/view/Window.java | 10 | ||||
| -rw-r--r-- | core/java/com/android/internal/policy/PhoneWindow.java | 6 |
6 files changed, 114 insertions, 1 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index fb32055a45c2..3ec255311af5 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -48706,6 +48706,7 @@ package android.view { method @Nullable public android.graphics.drawable.Drawable getVerticalScrollbarThumbDrawable(); method @Nullable public android.graphics.drawable.Drawable getVerticalScrollbarTrackDrawable(); method public int getVerticalScrollbarWidth(); + method @Nullable public android.view.ViewRoot getViewRoot(); method @Nullable public android.view.translation.ViewTranslationCallback getViewTranslationCallback(); method public android.view.ViewTreeObserver getViewTreeObserver(); method public int getVisibility(); @@ -49782,6 +49783,11 @@ package android.view { method public android.view.ViewPropertyAnimator zBy(float); } + @UiThread public interface ViewRoot { + method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction); + method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl); + } + public abstract class ViewStructure { ctor public ViewStructure(); method public abstract int addChildCount(int); @@ -49977,6 +49983,7 @@ package android.view { method @NonNull public java.util.List<android.graphics.Rect> getSystemGestureExclusionRects(); method public long getTransitionBackgroundFadeDuration(); method public android.transition.TransitionManager getTransitionManager(); + method @Nullable public android.view.ViewRoot getViewRoot(); method public abstract int getVolumeControlStream(); method public android.view.WindowManager getWindowManager(); method public final android.content.res.TypedArray getWindowStyle(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 615dd82fb848..612058ebcea5 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -29541,6 +29541,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return mScrollCaptureInternal; } + ViewRoot getViewRoot() { + return mViewRootImpl; + } + public void dump(String prefix, PrintWriter writer) { String innerPrefix = prefix + " "; writer.println(prefix + "AttachInfo:"); @@ -30928,4 +30932,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN); } } + + /** + * @return The {@link android.view.ViewRoot} interface for this View. This will only + * return a non-null value when called between {@link #onAttachedToWindow} and + * {@link #onDetachedFromWindow}. + * + * The ViewRoot itself is not a View, it is just the interface to the windowing-system + * object that contains the entire view hierarchy. For the root View of a given hierarchy + * see {@link #getRootView}. + */ + public @Nullable ViewRoot getViewRoot() { + if (mAttachInfo != null) { + return mAttachInfo.getViewRoot(); + } + return null; + } } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java new file mode 100644 index 000000000000..3c755981a440 --- /dev/null +++ b/core/java/android/view/ViewRoot.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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 android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UiThread; + +/** + * Provides an interface to the root-Surface of a View Hierarchy or Window. This + * is used in combination with the {@link android.view.SurfaceControl} API to enable + * attaching app created SurfaceControl to the ViewRoot's surface hierarchy, and enable + * SurfaceTransactions to be performed in sync with the ViewRoot drawing. This object + * is obtained from {@link android.view.View#getViewRoot} and + * {@link android.view.Window#getViewRoot}. It must be used from the UI thread of + * the object it was obtained from. + */ +@UiThread +public interface ViewRoot { + /** + * Create a transaction which will reparent {@param child} to the ViewRoot. See + * {@link SurfaceControl.Transaction#reparent}. This transacton must be applied + * or merged in to another transaction by the caller, otherwise it will have + * no effect. + * + * @param child The SurfaceControl to reparent. + * @return A new transaction which performs the reparent operation when applied. + */ + @Nullable SurfaceControl.Transaction buildReparentTransaction(@NonNull SurfaceControl child); + + /** + * Consume the passed in transaction, and request the ViewRoot to apply it with the + * next draw. This transaction will be merged with the buffer transaction from the ViewRoot + * and they will show up on-screen atomically synced. + * + * This will not cause a draw to be scheduled, and if there are no other changes + * to the View hierarchy you may need to call {@link android.view.View#invalidate} + */ + boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t); +} diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 426c9504c4f9..c3770f0ef478 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -224,7 +224,7 @@ import java.util.concurrent.CountDownLatch; */ @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) public final class ViewRootImpl implements ViewParent, - View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks { + View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, ViewRoot { private static final String TAG = "ViewRootImpl"; private static final boolean DBG = false; private static final boolean LOCAL_LOGV = false; @@ -10249,4 +10249,21 @@ public final class ViewRootImpl implements ViewParent, t.apply(); } } + + @Override + @Nullable public SurfaceControl.Transaction buildReparentTransaction( + @NonNull SurfaceControl child) { + if (mSurfaceControl.isValid()) { + return new SurfaceControl.Transaction().reparent(child, mSurfaceControl); + } + return null; + } + + @Override + public boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t) { + registerRtFrameCallback(frame -> { + mergeWithNextTransaction(t, frame); + }); + return true; + } } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index c814e5add1b7..eacb639ac53a 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -2717,4 +2717,14 @@ public abstract class Window { public @Nullable WindowInsetsController getInsetsController() { return null; } + + /** + * This will be null before a content view is added, e.g. via + * {@link #setContentView} or {@link #addContentView}. + * + * @return The {@link android.view.ViewRoot} interface for this Window + */ + public @Nullable ViewRoot getViewRoot() { + return null; + } } diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 611fe29f4fcf..a6dc4e04bf36 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -75,6 +75,7 @@ import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.util.TypedValue; +import android.view.ViewRoot; import android.view.ContextThemeWrapper; import android.view.CrossWindowBlurListeners; import android.view.Gravity; @@ -3981,4 +3982,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public View getNavigationBarBackgroundView() { return mDecor != null ? mDecor.getNavigationBarBackgroundView() : null; } + + @Override + public ViewRoot getViewRoot() { + return getViewRootImplOrNull(); + } } |