diff options
| author | Svetoslav Ganov <svetoslavganov@google.com> | 2020-06-24 06:28:59 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-06-24 06:28:59 +0000 |
| commit | f8b9ddea71a0b330c07156a5d6345b8be057fb5b (patch) | |
| tree | 2a23d50b802ca40b85b6e5f73aa55e0e4416b041 /core/java/android | |
| parent | c8c2bf13c565a3f0651f4079d3b809b7e1f4c63d (diff) | |
| parent | a5b4990d966a2958d53cf602910cd5b15b02ac14 (diff) | |
Merge "Handle reperenting of InlineContentView" into rvc-dev
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/view/SurfaceControl.java | 145 | ||||
| -rw-r--r-- | core/java/android/view/SurfaceView.java | 68 | ||||
| -rw-r--r-- | core/java/android/widget/inline/InlineContentView.java | 163 |
3 files changed, 337 insertions, 39 deletions
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 3b3836582b16..9f7c5e46b49a 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -63,8 +63,10 @@ import dalvik.system.CloseGuard; import libcore.util.NativeAllocationRegistry; import java.io.Closeable; +import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.ArrayList; import java.util.Objects; /** @@ -226,24 +228,86 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject, int transformHint); + @Nullable + @GuardedBy("sLock") + private ArrayList<OnReparentListener> mReparentListeners; + + /** + * Listener to observe surface reparenting. + * + * @hide + */ + public interface OnReparentListener { + + /** + * Callback for reparenting surfaces. + * + * Important: You should only interact with the provided surface control + * only if you have a contract with its owner to avoid them closing it + * under you or vise versa. + * + * @param transaction The transaction that would commit reparenting. + * @param parent The future parent surface. + */ + void onReparent(@NonNull Transaction transaction, @Nullable SurfaceControl parent); + } + private final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; - /** + + /** * @hide */ public long mNativeObject; private long mNativeHandle; - // TODO: Move this to native. - private final Object mSizeLock = new Object(); - @GuardedBy("mSizeLock") + // TODO: Move width/height to native and fix locking through out. + private final Object mLock = new Object(); + @GuardedBy("mLock") private int mWidth; - @GuardedBy("mSizeLock") + @GuardedBy("mLock") private int mHeight; + private WeakReference<View> mLocalOwnerView; + static Transaction sGlobalTransaction; static long sTransactionNestCount = 0; + /** + * Adds a reparenting listener. + * + * @param listener The listener. + * @return Whether listener was added. + * + * @hide + */ + public boolean addOnReparentListener(@NonNull OnReparentListener listener) { + synchronized (mLock) { + if (mReparentListeners == null) { + mReparentListeners = new ArrayList<>(1); + } + return mReparentListeners.add(listener); + } + } + + /** + * Removes a reparenting listener. + * + * @param listener The listener. + * @return Whether listener was removed. + * + * @hide + */ + public boolean removeOnReparentListener(@NonNull OnReparentListener listener) { + synchronized (mLock) { + final boolean removed = mReparentListeners.remove(listener); + if (mReparentListeners.isEmpty()) { + mReparentListeners = null; + } + return removed; + } + } + /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */ /** @@ -455,6 +519,7 @@ public final class SurfaceControl implements Parcelable { mName = other.mName; mWidth = other.mWidth; mHeight = other.mHeight; + mLocalOwnerView = other.mLocalOwnerView; assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject)); } @@ -553,6 +618,7 @@ public final class SurfaceControl implements Parcelable { private int mHeight; private int mFormat = PixelFormat.OPAQUE; private String mName; + private WeakReference<View> mLocalOwnerView; private SurfaceControl mParent; private SparseIntArray mMetadata; @@ -587,7 +653,8 @@ public final class SurfaceControl implements Parcelable { "Only buffer layers can set a valid buffer size."); } return new SurfaceControl( - mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata); + mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata, + mLocalOwnerView); } /** @@ -602,6 +669,27 @@ public final class SurfaceControl implements Parcelable { } /** + * Set the local owner view for the surface. This view is only + * valid in the same process and is not transferred in an IPC. + * + * Note: This is used for cases where we want to know the view + * that manages the surface control while intercepting reparenting. + * A specific example is InlineContentView which exposes is surface + * control for reparenting as a way to implement clipping of several + * InlineContentView instances within a certain area. + * + * @param view The owner view. + * @return This builder. + * + * @hide + */ + @NonNull + public Builder setLocalOwnerView(@NonNull View view) { + mLocalOwnerView = new WeakReference<>(view); + return this; + } + + /** * Set the initial size of the controlled surface's buffers in pixels. * * @param width The buffer width in pixels. @@ -858,7 +946,7 @@ public final class SurfaceControl implements Parcelable { * @throws throws OutOfResourcesException If the SurfaceControl cannot be created. */ private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags, - SurfaceControl parent, SparseIntArray metadata) + SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView) throws OutOfResourcesException, IllegalArgumentException { if (name == null) { throw new IllegalArgumentException("name must not be null"); @@ -867,6 +955,7 @@ public final class SurfaceControl implements Parcelable { mName = name; mWidth = w; mHeight = h; + mLocalOwnerView = localOwnerView; Parcel metaParcel = Parcel.obtain(); try { if (metadata != null && metadata.size() > 0) { @@ -1307,7 +1396,7 @@ public final class SurfaceControl implements Parcelable { * @hide */ public int getWidth() { - synchronized (mSizeLock) { + synchronized (mLock) { return mWidth; } } @@ -1316,11 +1405,22 @@ public final class SurfaceControl implements Parcelable { * @hide */ public int getHeight() { - synchronized (mSizeLock) { + synchronized (mLock) { return mHeight; } } + /** + * Gets the local view that owns this surface. + * + * @return The owner view. + * + * @hide + */ + public @Nullable View getLocalOwnerView() { + return (mLocalOwnerView != null) ? mLocalOwnerView.get() : null; + } + @Override public String toString() { return "Surface(name=" + mName + ")/@0x" + @@ -2165,6 +2265,9 @@ public final class SurfaceControl implements Parcelable { public long mNativeObject; private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>(); + private final ArrayMap<SurfaceControl, SurfaceControl> mReparentedSurfaces = + new ArrayMap<>(); + Runnable mFreeNativeResources; private static final float[] INVALID_COLOR = {-1, -1, -1}; @@ -2205,6 +2308,8 @@ public final class SurfaceControl implements Parcelable { */ @Override public void close() { + mResizedSurfaces.clear(); + mReparentedSurfaces.clear(); mFreeNativeResources.run(); mNativeObject = 0; } @@ -2215,6 +2320,7 @@ public final class SurfaceControl implements Parcelable { */ public void apply(boolean sync) { applyResizedSurfaces(); + notifyReparentedSurfaces(); nativeApplyTransaction(mNativeObject, sync); } @@ -2222,7 +2328,7 @@ public final class SurfaceControl implements Parcelable { for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) { final Point size = mResizedSurfaces.valueAt(i); final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i); - synchronized (surfaceControl.mSizeLock) { + synchronized (surfaceControl.mLock) { surfaceControl.mWidth = size.x; surfaceControl.mHeight = size.y; } @@ -2230,6 +2336,22 @@ public final class SurfaceControl implements Parcelable { mResizedSurfaces.clear(); } + private void notifyReparentedSurfaces() { + final int reparentCount = mReparentedSurfaces.size(); + for (int i = reparentCount - 1; i >= 0; i--) { + final SurfaceControl child = mReparentedSurfaces.keyAt(i); + synchronized (child.mLock) { + final int listenerCount = (child.mReparentListeners != null) + ? child.mReparentListeners.size() : 0; + for (int j = 0; j < listenerCount; j++) { + final OnReparentListener listener = child.mReparentListeners.get(j); + listener.onReparent(this, mReparentedSurfaces.valueAt(i)); + } + mReparentedSurfaces.removeAt(i); + } + } + } + /** * Toggle the visibility of a given Layer and it's sub-tree. * @@ -2632,6 +2754,7 @@ public final class SurfaceControl implements Parcelable { otherObject = newParent.mNativeObject; } nativeReparent(mNativeObject, sc.mNativeObject, otherObject); + mReparentedSurfaces.put(sc, newParent); return this; } @@ -2912,6 +3035,8 @@ public final class SurfaceControl implements Parcelable { } mResizedSurfaces.putAll(other.mResizedSurfaces); other.mResizedSurfaces.clear(); + mReparentedSurfaces.putAll(other.mReparentedSurfaces); + other.mReparentedSurfaces.clear(); nativeMergeTransaction(mNativeObject, other.mNativeObject); return this; } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 90e1eab09fd6..5b6e5c1acea2 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -44,7 +44,6 @@ import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceControl.Transaction; -import android.view.SurfaceControlViewHost; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityEmbeddedConnection; @@ -988,6 +987,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName(name) + .setLocalOwnerView(this) .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) @@ -996,6 +996,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall .build(); mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Background for -" + name) + .setLocalOwnerView(this) .setOpaque(true) .setColorLayer() .setParent(mSurfaceControl) @@ -1051,11 +1052,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall // we still need to latch a buffer). // b/28866173 if (sizeChanged || creating || !mRtHandlingPositionUpdates) { - mTmpTransaction.setPosition(mSurfaceControl, mScreenRect.left, - mScreenRect.top); - mTmpTransaction.setMatrix(mSurfaceControl, - mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f, - mScreenRect.height() / (float) mSurfaceHeight); + onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl, + mScreenRect.left, /*positionLeft*/ + mScreenRect.top /*positionTop*/ , + mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/, + mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/); + // Set a window crop when creating the surface or changing its size to // crop the buffer to the surface size since the buffer producer may // use SCALING_MODE_SCALE and submit a larger size than the surface @@ -1211,6 +1213,40 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall Surface viewRootSurface, long nextViewRootFrameNumber) { } + /** + * Sets the surface position and scale. Can be called on + * the UI thread as well as on the renderer thread. + * + * @param transaction Transaction in which to execute. + * @param surface Surface whose location to set. + * @param positionLeft The left position to set. + * @param positionTop The top position to set. + * @param postScaleX The X axis post scale + * @param postScaleY The Y axis post scale + * + * @hide + */ + protected void onSetSurfacePositionAndScaleRT(@NonNull Transaction transaction, + @NonNull SurfaceControl surface, int positionLeft, int positionTop, + float postScaleX, float postScaleY) { + transaction.setPosition(surface, positionLeft, positionTop); + transaction.setMatrix(surface, postScaleX /*dsdx*/, 0f /*dtdx*/, + 0f /*dsdy*/, postScaleY /*dtdy*/); + } + + /** @hide */ + public void requestUpdateSurfacePositionAndScale() { + if (mSurfaceControl == null) { + return; + } + onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl, + mScreenRect.left, /*positionLeft*/ + mScreenRect.top/*positionTop*/ , + mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/, + mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/); + mTmpTransaction.apply(); + } + private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t, Rect position, long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); @@ -1219,16 +1255,26 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall frameNumber); } - t.setPosition(surface, position.left, position.top); - t.setMatrix(surface, - position.width() / (float) mSurfaceWidth, - 0.0f, 0.0f, - position.height() / (float) mSurfaceHeight); + onSetSurfacePositionAndScaleRT(t, surface, + position.left /*positionLeft*/, + position.top /*positionTop*/, + position.width() / (float) mSurfaceWidth /*postScaleX*/, + position.height() / (float) mSurfaceHeight /*postScaleY*/); + if (mViewVisibility) { t.show(surface); } } + /** + * @return The last render position of the backing surface or an empty rect. + * + * @hide + */ + public @NonNull Rect getSurfaceRenderPosition() { + return mRTLastReportedPosition; + } + private void setParentSpaceRectangle(Rect position, long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction(); diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java index 9e3a292440ab..be7c6966ce38 100644 --- a/core/java/android/widget/inline/InlineContentView.java +++ b/core/java/android/widget/inline/InlineContentView.java @@ -18,18 +18,22 @@ package android.widget.inline; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.PointF; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.SurfaceHolder; import android.view.SurfaceView; +import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver.OnPreDrawListener; +import android.view.ViewTreeObserver; +import java.lang.ref.WeakReference; import java.util.function.Consumer; /** @@ -88,8 +92,10 @@ public class InlineContentView extends ViewGroup { * * @hide */ + @TestApi public interface SurfacePackageUpdater { + /** * Called when the previous surface package is released due to view being detached * from the window. @@ -101,14 +107,16 @@ public class InlineContentView extends ViewGroup { * * @param consumer consumes the updated surface package. */ - void getSurfacePackage(Consumer<SurfaceControlViewHost.SurfacePackage> consumer); + void getSurfacePackage(@NonNull Consumer<SurfaceControlViewHost.SurfacePackage> consumer); } @NonNull private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(@NonNull SurfaceHolder holder) { - mSurfaceControlCallback.onCreated(mSurfaceView.getSurfaceControl()); + final SurfaceControl surfaceControl = mSurfaceView.getSurfaceControl(); + surfaceControl.addOnReparentListener(mOnReparentListener); + mSurfaceControlCallback.onCreated(surfaceControl); } @Override @@ -119,7 +127,37 @@ public class InlineContentView extends ViewGroup { @Override public void surfaceDestroyed(@NonNull SurfaceHolder holder) { - mSurfaceControlCallback.onDestroyed(mSurfaceView.getSurfaceControl()); + final SurfaceControl surfaceControl = mSurfaceView.getSurfaceControl(); + surfaceControl.removeOnReparentListener(mOnReparentListener); + mSurfaceControlCallback.onDestroyed(surfaceControl); + } + }; + + @NonNull + private final SurfaceControl.OnReparentListener mOnReparentListener = + new SurfaceControl.OnReparentListener() { + @Override + public void onReparent(SurfaceControl.Transaction transaction, + SurfaceControl parent) { + final View parentSurfaceOwnerView = (parent != null) + ? parent.getLocalOwnerView() : null; + if (parentSurfaceOwnerView instanceof SurfaceView) { + mParentSurfaceOwnerView = new WeakReference<>( + (SurfaceView) parentSurfaceOwnerView); + } else { + mParentSurfaceOwnerView = null; + } + } + }; + + @NonNull + private final ViewTreeObserver.OnDrawListener mOnDrawListener = + new ViewTreeObserver.OnDrawListener() { + @Override + public void onDraw() { + computeParentPositionAndScale(); + final int visibility = InlineContentView.this.isShown() ? VISIBLE : GONE; + mSurfaceView.setVisibility(visibility); } }; @@ -127,21 +165,20 @@ public class InlineContentView extends ViewGroup { private final SurfaceView mSurfaceView; @Nullable + private WeakReference<SurfaceView> mParentSurfaceOwnerView; + + @Nullable + private int[] mParentPosition; + + @Nullable + private PointF mParentScale; + + @Nullable private SurfaceControlCallback mSurfaceControlCallback; @Nullable private SurfacePackageUpdater mSurfacePackageUpdater; - @NonNull - private final OnPreDrawListener mDrawListener = new OnPreDrawListener() { - @Override - public boolean onPreDraw() { - int visibility = InlineContentView.this.isShown() ? VISIBLE : GONE; - mSurfaceView.setVisibility(visibility); - return true; - } - }; - /** * @inheritDoc * @hide @@ -192,10 +229,33 @@ public class InlineContentView extends ViewGroup { public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mSurfaceView = new SurfaceView(context, attrs, defStyleAttr, defStyleRes); + mSurfaceView = new SurfaceView(context, attrs, defStyleAttr, defStyleRes) { + @Override + protected void onSetSurfacePositionAndScaleRT( + @NonNull SurfaceControl.Transaction transaction, + @NonNull SurfaceControl surface, int positionLeft, int positionTop, + float postScaleX, float postScaleY) { + // If we have a parent position, we need to make our coordinates relative + // to the parent in the rendering space. + if (mParentPosition != null) { + positionLeft = (int) ((positionLeft - mParentPosition[0]) / mParentScale.x); + positionTop = (int) ((positionTop - mParentPosition[1]) / mParentScale.y); + } + + // Any scaling done to the parent or its predecessors would be applied + // via the surfaces parent -> child relation, so we only propagate any + // scaling set on the InlineContentView itself. + postScaleX = InlineContentView.this.getScaleX(); + postScaleY = InlineContentView.this.getScaleY(); + + super.onSetSurfacePositionAndScaleRT(transaction, surface, positionLeft, + positionTop, postScaleX, postScaleY); + } + }; mSurfaceView.setZOrderOnTop(true); mSurfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT); addView(mSurfaceView); + setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); } /** @@ -203,6 +263,7 @@ public class InlineContentView extends ViewGroup { * * @hide */ + @TestApi public void setChildSurfacePackageUpdater( @Nullable SurfacePackageUpdater surfacePackageUpdater) { mSurfacePackageUpdater = surfacePackageUpdater; @@ -221,8 +282,9 @@ public class InlineContentView extends ViewGroup { } }); } - mSurfaceView.setVisibility(VISIBLE); - getViewTreeObserver().addOnPreDrawListener(mDrawListener); + + mSurfaceView.setVisibility(getVisibility()); + getViewTreeObserver().addOnDrawListener(mOnDrawListener); } @Override @@ -232,7 +294,9 @@ public class InlineContentView extends ViewGroup { if (mSurfacePackageUpdater != null) { mSurfacePackageUpdater.onSurfacePackageReleased(); } - getViewTreeObserver().removeOnPreDrawListener(mDrawListener); + + getViewTreeObserver().removeOnDrawListener(mOnDrawListener); + mSurfaceView.setVisibility(View.GONE); } @Override @@ -279,4 +343,67 @@ public class InlineContentView extends ViewGroup { public boolean setZOrderedOnTop(boolean onTop) { return mSurfaceView.setZOrderedOnTop(onTop, /*allowDynamicChange*/ true); } + + + private void computeParentPositionAndScale() { + boolean contentPositionOrScaleChanged = false; + + // This method can be called on the UI or render thread but for the cases + // it is called these threads are not running concurrently, so no need to lock. + final SurfaceView parentSurfaceOwnerView = (mParentSurfaceOwnerView != null) + ? mParentSurfaceOwnerView.get() : null; + + if (parentSurfaceOwnerView != null) { + if (mParentPosition == null) { + mParentPosition = new int[2]; + } + final int oldParentPositionX = mParentPosition[0]; + final int oldParentPositionY = mParentPosition[1]; + parentSurfaceOwnerView.getLocationInSurface(mParentPosition); + if (oldParentPositionX != mParentPosition[0] + || oldParentPositionY != mParentPosition[1]) { + contentPositionOrScaleChanged = true; + } + + if (mParentScale == null) { + mParentScale = new PointF(); + } + + final float lastParentSurfaceWidth = parentSurfaceOwnerView + .getSurfaceRenderPosition().width(); + final float oldParentScaleX = mParentScale.x; + if (lastParentSurfaceWidth > 0) { + mParentScale.x = lastParentSurfaceWidth / + (float) parentSurfaceOwnerView.getWidth(); + } else { + mParentScale.x = 1.0f; + } + if (!contentPositionOrScaleChanged + && Float.compare(oldParentScaleX, mParentScale.x) != 0) { + contentPositionOrScaleChanged = true; + } + + final float lastParentSurfaceHeight = parentSurfaceOwnerView + .getSurfaceRenderPosition().height(); + final float oldParentScaleY = mParentScale.y; + if (lastParentSurfaceHeight > 0) { + mParentScale.y = lastParentSurfaceHeight + / (float) parentSurfaceOwnerView.getHeight(); + } else { + mParentScale.y = 1.0f; + } + if (!contentPositionOrScaleChanged + && Float.compare(oldParentScaleY, mParentScale.y) != 0) { + contentPositionOrScaleChanged = true; + } + } else if (mParentPosition != null || mParentScale != null) { + contentPositionOrScaleChanged = true; + mParentPosition = null; + mParentScale = null; + } + + if (contentPositionOrScaleChanged) { + mSurfaceView.requestUpdateSurfacePositionAndScale(); + } + } } |
