Loading api/test-current.txt +13 −0 Original line number Original line Diff line number Diff line Loading @@ -5506,6 +5506,19 @@ package android.widget { } } package android.widget.inline { public class InlineContentView extends android.view.ViewGroup { method public void setChildSurfacePackageUpdater(@Nullable android.widget.inline.InlineContentView.SurfacePackageUpdater); } public static interface InlineContentView.SurfacePackageUpdater { method public void getSurfacePackage(@NonNull java.util.function.Consumer<android.view.SurfaceControlViewHost.SurfacePackage>); method public void onSurfacePackageReleased(); } } package android.window { package android.window { public final class DisplayAreaInfo implements android.os.Parcelable { public final class DisplayAreaInfo implements android.os.Parcelable { Loading core/java/android/view/SurfaceControl.java +135 −10 Original line number Original line Diff line number Diff line Loading @@ -63,8 +63,10 @@ import dalvik.system.CloseGuard; import libcore.util.NativeAllocationRegistry; import libcore.util.NativeAllocationRegistry; import java.io.Closeable; import java.io.Closeable; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Objects; import java.util.Objects; /** /** Loading Loading @@ -226,24 +228,86 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject, private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject, int transformHint); 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 final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; private String mName; /** /** * @hide * @hide */ */ public long mNativeObject; public long mNativeObject; private long mNativeHandle; private long mNativeHandle; // TODO: Move this to native. // TODO: Move width/height to native and fix locking through out. private final Object mSizeLock = new Object(); private final Object mLock = new Object(); @GuardedBy("mSizeLock") @GuardedBy("mLock") private int mWidth; private int mWidth; @GuardedBy("mSizeLock") @GuardedBy("mLock") private int mHeight; private int mHeight; private WeakReference<View> mLocalOwnerView; static Transaction sGlobalTransaction; static Transaction sGlobalTransaction; static long sTransactionNestCount = 0; 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) */ /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */ /** /** Loading Loading @@ -455,6 +519,7 @@ public final class SurfaceControl implements Parcelable { mName = other.mName; mName = other.mName; mWidth = other.mWidth; mWidth = other.mWidth; mHeight = other.mHeight; mHeight = other.mHeight; mLocalOwnerView = other.mLocalOwnerView; assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject)); assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject)); } } Loading Loading @@ -553,6 +618,7 @@ public final class SurfaceControl implements Parcelable { private int mHeight; private int mHeight; private int mFormat = PixelFormat.OPAQUE; private int mFormat = PixelFormat.OPAQUE; private String mName; private String mName; private WeakReference<View> mLocalOwnerView; private SurfaceControl mParent; private SurfaceControl mParent; private SparseIntArray mMetadata; private SparseIntArray mMetadata; Loading Loading @@ -587,7 +653,8 @@ public final class SurfaceControl implements Parcelable { "Only buffer layers can set a valid buffer size."); "Only buffer layers can set a valid buffer size."); } } return new SurfaceControl( return new SurfaceControl( mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata); mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata, mLocalOwnerView); } } /** /** Loading @@ -601,6 +668,27 @@ public final class SurfaceControl implements Parcelable { return this; return this; } } /** * 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. * Set the initial size of the controlled surface's buffers in pixels. * * Loading Loading @@ -858,7 +946,7 @@ public final class SurfaceControl implements Parcelable { * @throws throws OutOfResourcesException If the SurfaceControl cannot be created. * @throws throws OutOfResourcesException If the SurfaceControl cannot be created. */ */ private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags, 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 { throws OutOfResourcesException, IllegalArgumentException { if (name == null) { if (name == null) { throw new IllegalArgumentException("name must not be null"); throw new IllegalArgumentException("name must not be null"); Loading @@ -867,6 +955,7 @@ public final class SurfaceControl implements Parcelable { mName = name; mName = name; mWidth = w; mWidth = w; mHeight = h; mHeight = h; mLocalOwnerView = localOwnerView; Parcel metaParcel = Parcel.obtain(); Parcel metaParcel = Parcel.obtain(); try { try { if (metadata != null && metadata.size() > 0) { if (metadata != null && metadata.size() > 0) { Loading Loading @@ -1307,7 +1396,7 @@ public final class SurfaceControl implements Parcelable { * @hide * @hide */ */ public int getWidth() { public int getWidth() { synchronized (mSizeLock) { synchronized (mLock) { return mWidth; return mWidth; } } } } Loading @@ -1316,11 +1405,22 @@ public final class SurfaceControl implements Parcelable { * @hide * @hide */ */ public int getHeight() { public int getHeight() { synchronized (mSizeLock) { synchronized (mLock) { return mHeight; 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 @Override public String toString() { public String toString() { return "Surface(name=" + mName + ")/@0x" + return "Surface(name=" + mName + ")/@0x" + Loading Loading @@ -2165,6 +2265,9 @@ public final class SurfaceControl implements Parcelable { public long mNativeObject; public long mNativeObject; private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>(); private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>(); private final ArrayMap<SurfaceControl, SurfaceControl> mReparentedSurfaces = new ArrayMap<>(); Runnable mFreeNativeResources; Runnable mFreeNativeResources; private static final float[] INVALID_COLOR = {-1, -1, -1}; private static final float[] INVALID_COLOR = {-1, -1, -1}; Loading Loading @@ -2205,6 +2308,8 @@ public final class SurfaceControl implements Parcelable { */ */ @Override @Override public void close() { public void close() { mResizedSurfaces.clear(); mReparentedSurfaces.clear(); mFreeNativeResources.run(); mFreeNativeResources.run(); mNativeObject = 0; mNativeObject = 0; } } Loading @@ -2215,6 +2320,7 @@ public final class SurfaceControl implements Parcelable { */ */ public void apply(boolean sync) { public void apply(boolean sync) { applyResizedSurfaces(); applyResizedSurfaces(); notifyReparentedSurfaces(); nativeApplyTransaction(mNativeObject, sync); nativeApplyTransaction(mNativeObject, sync); } } Loading @@ -2222,7 +2328,7 @@ public final class SurfaceControl implements Parcelable { for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) { for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) { final Point size = mResizedSurfaces.valueAt(i); final Point size = mResizedSurfaces.valueAt(i); final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i); final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i); synchronized (surfaceControl.mSizeLock) { synchronized (surfaceControl.mLock) { surfaceControl.mWidth = size.x; surfaceControl.mWidth = size.x; surfaceControl.mHeight = size.y; surfaceControl.mHeight = size.y; } } Loading @@ -2230,6 +2336,22 @@ public final class SurfaceControl implements Parcelable { mResizedSurfaces.clear(); 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. * Toggle the visibility of a given Layer and it's sub-tree. * * Loading Loading @@ -2632,6 +2754,7 @@ public final class SurfaceControl implements Parcelable { otherObject = newParent.mNativeObject; otherObject = newParent.mNativeObject; } } nativeReparent(mNativeObject, sc.mNativeObject, otherObject); nativeReparent(mNativeObject, sc.mNativeObject, otherObject); mReparentedSurfaces.put(sc, newParent); return this; return this; } } Loading Loading @@ -2912,6 +3035,8 @@ public final class SurfaceControl implements Parcelable { } } mResizedSurfaces.putAll(other.mResizedSurfaces); mResizedSurfaces.putAll(other.mResizedSurfaces); other.mResizedSurfaces.clear(); other.mResizedSurfaces.clear(); mReparentedSurfaces.putAll(other.mReparentedSurfaces); other.mReparentedSurfaces.clear(); nativeMergeTransaction(mNativeObject, other.mNativeObject); nativeMergeTransaction(mNativeObject, other.mNativeObject); return this; return this; } } Loading core/java/android/view/SurfaceView.java +57 −11 Original line number Original line Diff line number Diff line Loading @@ -44,7 +44,6 @@ import android.os.SystemClock; import android.util.AttributeSet; import android.util.AttributeSet; import android.util.Log; import android.util.Log; import android.view.SurfaceControl.Transaction; import android.view.SurfaceControl.Transaction; import android.view.SurfaceControlViewHost; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityEmbeddedConnection; import android.view.accessibility.IAccessibilityEmbeddedConnection; Loading Loading @@ -988,6 +987,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName(name) .setName(name) .setLocalOwnerView(this) .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) .setFormat(mFormat) Loading @@ -996,6 +996,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall .build(); .build(); mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Background for -" + name) .setName("Background for -" + name) .setLocalOwnerView(this) .setOpaque(true) .setOpaque(true) .setColorLayer() .setColorLayer() .setParent(mSurfaceControl) .setParent(mSurfaceControl) Loading Loading @@ -1051,11 +1052,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall // we still need to latch a buffer). // we still need to latch a buffer). // b/28866173 // b/28866173 if (sizeChanged || creating || !mRtHandlingPositionUpdates) { if (sizeChanged || creating || !mRtHandlingPositionUpdates) { mTmpTransaction.setPosition(mSurfaceControl, mScreenRect.left, onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl, mScreenRect.top); mScreenRect.left, /*positionLeft*/ mTmpTransaction.setMatrix(mSurfaceControl, mScreenRect.top /*positionTop*/ , mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f, mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/, mScreenRect.height() / (float) mSurfaceHeight); mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/); // Set a window crop when creating the surface or changing its size to // 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 // crop the buffer to the surface size since the buffer producer may // use SCALING_MODE_SCALE and submit a larger size than the surface // use SCALING_MODE_SCALE and submit a larger size than the surface Loading Loading @@ -1211,6 +1213,40 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall Surface viewRootSurface, long nextViewRootFrameNumber) { 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, private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t, Rect position, long frameNumber) { Rect position, long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); final ViewRootImpl viewRoot = getViewRootImpl(); Loading @@ -1219,16 +1255,26 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall frameNumber); frameNumber); } } t.setPosition(surface, position.left, position.top); onSetSurfacePositionAndScaleRT(t, surface, t.setMatrix(surface, position.left /*positionLeft*/, position.width() / (float) mSurfaceWidth, position.top /*positionTop*/, 0.0f, 0.0f, position.width() / (float) mSurfaceWidth /*postScaleX*/, position.height() / (float) mSurfaceHeight); position.height() / (float) mSurfaceHeight /*postScaleY*/); if (mViewVisibility) { if (mViewVisibility) { t.show(surface); 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) { private void setParentSpaceRectangle(Rect position, long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); final ViewRootImpl viewRoot = getViewRootImpl(); final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction(); final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction(); Loading core/java/android/widget/inline/InlineContentView.java +145 −18 Original line number Original line Diff line number Diff line Loading @@ -18,18 +18,22 @@ package android.widget.inline; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.TestApi; import android.content.Context; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Rect; import android.graphics.PointF; import android.util.AttributeSet; import android.util.AttributeSet; import android.util.Log; import android.util.Log; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.SurfaceControlViewHost; import android.view.SurfaceHolder; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnPreDrawListener; import android.view.ViewTreeObserver; import java.lang.ref.WeakReference; import java.util.function.Consumer; import java.util.function.Consumer; /** /** Loading Loading @@ -88,8 +92,10 @@ public class InlineContentView extends ViewGroup { * * * @hide * @hide */ */ @TestApi public interface SurfacePackageUpdater { public interface SurfacePackageUpdater { /** /** * Called when the previous surface package is released due to view being detached * Called when the previous surface package is released due to view being detached * from the window. * from the window. Loading @@ -101,14 +107,16 @@ public class InlineContentView extends ViewGroup { * * * @param consumer consumes the updated surface package. * @param consumer consumes the updated surface package. */ */ void getSurfacePackage(Consumer<SurfaceControlViewHost.SurfacePackage> consumer); void getSurfacePackage(@NonNull Consumer<SurfaceControlViewHost.SurfacePackage> consumer); } } @NonNull @NonNull private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() { private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() { @Override @Override public void surfaceCreated(@NonNull SurfaceHolder holder) { public void surfaceCreated(@NonNull SurfaceHolder holder) { mSurfaceControlCallback.onCreated(mSurfaceView.getSurfaceControl()); final SurfaceControl surfaceControl = mSurfaceView.getSurfaceControl(); surfaceControl.addOnReparentListener(mOnReparentListener); mSurfaceControlCallback.onCreated(surfaceControl); } } @Override @Override Loading @@ -119,29 +127,58 @@ public class InlineContentView extends ViewGroup { @Override @Override public void surfaceDestroyed(@NonNull SurfaceHolder holder) { 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); } } }; }; @NonNull @NonNull private final SurfaceView mSurfaceView; private final SurfaceView mSurfaceView; @Nullable private WeakReference<SurfaceView> mParentSurfaceOwnerView; @Nullable private int[] mParentPosition; @Nullable private PointF mParentScale; @Nullable @Nullable private SurfaceControlCallback mSurfaceControlCallback; private SurfaceControlCallback mSurfaceControlCallback; @Nullable @Nullable private SurfacePackageUpdater mSurfacePackageUpdater; 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 * @inheritDoc * @hide * @hide Loading Loading @@ -192,10 +229,33 @@ public class InlineContentView extends ViewGroup { public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs, public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, 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.setZOrderOnTop(true); mSurfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT); mSurfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT); addView(mSurfaceView); addView(mSurfaceView); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); } } /** /** Loading @@ -203,6 +263,7 @@ public class InlineContentView extends ViewGroup { * * * @hide * @hide */ */ @TestApi public void setChildSurfacePackageUpdater( public void setChildSurfacePackageUpdater( @Nullable SurfacePackageUpdater surfacePackageUpdater) { @Nullable SurfacePackageUpdater surfacePackageUpdater) { mSurfacePackageUpdater = surfacePackageUpdater; mSurfacePackageUpdater = surfacePackageUpdater; Loading @@ -221,8 +282,9 @@ public class InlineContentView extends ViewGroup { } } }); }); } } mSurfaceView.setVisibility(VISIBLE); getViewTreeObserver().addOnPreDrawListener(mDrawListener); mSurfaceView.setVisibility(getVisibility()); getViewTreeObserver().addOnDrawListener(mOnDrawListener); } } @Override @Override Loading @@ -232,7 +294,9 @@ public class InlineContentView extends ViewGroup { if (mSurfacePackageUpdater != null) { if (mSurfacePackageUpdater != null) { mSurfacePackageUpdater.onSurfacePackageReleased(); mSurfacePackageUpdater.onSurfacePackageReleased(); } } getViewTreeObserver().removeOnPreDrawListener(mDrawListener); getViewTreeObserver().removeOnDrawListener(mOnDrawListener); mSurfaceView.setVisibility(View.GONE); } } @Override @Override Loading Loading @@ -279,4 +343,67 @@ public class InlineContentView extends ViewGroup { public boolean setZOrderedOnTop(boolean onTop) { public boolean setZOrderedOnTop(boolean onTop) { return mSurfaceView.setZOrderedOnTop(onTop, /*allowDynamicChange*/ true); 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(); } } } } Loading
api/test-current.txt +13 −0 Original line number Original line Diff line number Diff line Loading @@ -5506,6 +5506,19 @@ package android.widget { } } package android.widget.inline { public class InlineContentView extends android.view.ViewGroup { method public void setChildSurfacePackageUpdater(@Nullable android.widget.inline.InlineContentView.SurfacePackageUpdater); } public static interface InlineContentView.SurfacePackageUpdater { method public void getSurfacePackage(@NonNull java.util.function.Consumer<android.view.SurfaceControlViewHost.SurfacePackage>); method public void onSurfacePackageReleased(); } } package android.window { package android.window { public final class DisplayAreaInfo implements android.os.Parcelable { public final class DisplayAreaInfo implements android.os.Parcelable { Loading
core/java/android/view/SurfaceControl.java +135 −10 Original line number Original line Diff line number Diff line Loading @@ -63,8 +63,10 @@ import dalvik.system.CloseGuard; import libcore.util.NativeAllocationRegistry; import libcore.util.NativeAllocationRegistry; import java.io.Closeable; import java.io.Closeable; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Objects; import java.util.Objects; /** /** Loading Loading @@ -226,24 +228,86 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject, private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject, int transformHint); 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 final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; private String mName; /** /** * @hide * @hide */ */ public long mNativeObject; public long mNativeObject; private long mNativeHandle; private long mNativeHandle; // TODO: Move this to native. // TODO: Move width/height to native and fix locking through out. private final Object mSizeLock = new Object(); private final Object mLock = new Object(); @GuardedBy("mSizeLock") @GuardedBy("mLock") private int mWidth; private int mWidth; @GuardedBy("mSizeLock") @GuardedBy("mLock") private int mHeight; private int mHeight; private WeakReference<View> mLocalOwnerView; static Transaction sGlobalTransaction; static Transaction sGlobalTransaction; static long sTransactionNestCount = 0; 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) */ /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */ /** /** Loading Loading @@ -455,6 +519,7 @@ public final class SurfaceControl implements Parcelable { mName = other.mName; mName = other.mName; mWidth = other.mWidth; mWidth = other.mWidth; mHeight = other.mHeight; mHeight = other.mHeight; mLocalOwnerView = other.mLocalOwnerView; assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject)); assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject)); } } Loading Loading @@ -553,6 +618,7 @@ public final class SurfaceControl implements Parcelable { private int mHeight; private int mHeight; private int mFormat = PixelFormat.OPAQUE; private int mFormat = PixelFormat.OPAQUE; private String mName; private String mName; private WeakReference<View> mLocalOwnerView; private SurfaceControl mParent; private SurfaceControl mParent; private SparseIntArray mMetadata; private SparseIntArray mMetadata; Loading Loading @@ -587,7 +653,8 @@ public final class SurfaceControl implements Parcelable { "Only buffer layers can set a valid buffer size."); "Only buffer layers can set a valid buffer size."); } } return new SurfaceControl( return new SurfaceControl( mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata); mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata, mLocalOwnerView); } } /** /** Loading @@ -601,6 +668,27 @@ public final class SurfaceControl implements Parcelable { return this; return this; } } /** * 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. * Set the initial size of the controlled surface's buffers in pixels. * * Loading Loading @@ -858,7 +946,7 @@ public final class SurfaceControl implements Parcelable { * @throws throws OutOfResourcesException If the SurfaceControl cannot be created. * @throws throws OutOfResourcesException If the SurfaceControl cannot be created. */ */ private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags, 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 { throws OutOfResourcesException, IllegalArgumentException { if (name == null) { if (name == null) { throw new IllegalArgumentException("name must not be null"); throw new IllegalArgumentException("name must not be null"); Loading @@ -867,6 +955,7 @@ public final class SurfaceControl implements Parcelable { mName = name; mName = name; mWidth = w; mWidth = w; mHeight = h; mHeight = h; mLocalOwnerView = localOwnerView; Parcel metaParcel = Parcel.obtain(); Parcel metaParcel = Parcel.obtain(); try { try { if (metadata != null && metadata.size() > 0) { if (metadata != null && metadata.size() > 0) { Loading Loading @@ -1307,7 +1396,7 @@ public final class SurfaceControl implements Parcelable { * @hide * @hide */ */ public int getWidth() { public int getWidth() { synchronized (mSizeLock) { synchronized (mLock) { return mWidth; return mWidth; } } } } Loading @@ -1316,11 +1405,22 @@ public final class SurfaceControl implements Parcelable { * @hide * @hide */ */ public int getHeight() { public int getHeight() { synchronized (mSizeLock) { synchronized (mLock) { return mHeight; 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 @Override public String toString() { public String toString() { return "Surface(name=" + mName + ")/@0x" + return "Surface(name=" + mName + ")/@0x" + Loading Loading @@ -2165,6 +2265,9 @@ public final class SurfaceControl implements Parcelable { public long mNativeObject; public long mNativeObject; private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>(); private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>(); private final ArrayMap<SurfaceControl, SurfaceControl> mReparentedSurfaces = new ArrayMap<>(); Runnable mFreeNativeResources; Runnable mFreeNativeResources; private static final float[] INVALID_COLOR = {-1, -1, -1}; private static final float[] INVALID_COLOR = {-1, -1, -1}; Loading Loading @@ -2205,6 +2308,8 @@ public final class SurfaceControl implements Parcelable { */ */ @Override @Override public void close() { public void close() { mResizedSurfaces.clear(); mReparentedSurfaces.clear(); mFreeNativeResources.run(); mFreeNativeResources.run(); mNativeObject = 0; mNativeObject = 0; } } Loading @@ -2215,6 +2320,7 @@ public final class SurfaceControl implements Parcelable { */ */ public void apply(boolean sync) { public void apply(boolean sync) { applyResizedSurfaces(); applyResizedSurfaces(); notifyReparentedSurfaces(); nativeApplyTransaction(mNativeObject, sync); nativeApplyTransaction(mNativeObject, sync); } } Loading @@ -2222,7 +2328,7 @@ public final class SurfaceControl implements Parcelable { for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) { for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) { final Point size = mResizedSurfaces.valueAt(i); final Point size = mResizedSurfaces.valueAt(i); final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i); final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i); synchronized (surfaceControl.mSizeLock) { synchronized (surfaceControl.mLock) { surfaceControl.mWidth = size.x; surfaceControl.mWidth = size.x; surfaceControl.mHeight = size.y; surfaceControl.mHeight = size.y; } } Loading @@ -2230,6 +2336,22 @@ public final class SurfaceControl implements Parcelable { mResizedSurfaces.clear(); 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. * Toggle the visibility of a given Layer and it's sub-tree. * * Loading Loading @@ -2632,6 +2754,7 @@ public final class SurfaceControl implements Parcelable { otherObject = newParent.mNativeObject; otherObject = newParent.mNativeObject; } } nativeReparent(mNativeObject, sc.mNativeObject, otherObject); nativeReparent(mNativeObject, sc.mNativeObject, otherObject); mReparentedSurfaces.put(sc, newParent); return this; return this; } } Loading Loading @@ -2912,6 +3035,8 @@ public final class SurfaceControl implements Parcelable { } } mResizedSurfaces.putAll(other.mResizedSurfaces); mResizedSurfaces.putAll(other.mResizedSurfaces); other.mResizedSurfaces.clear(); other.mResizedSurfaces.clear(); mReparentedSurfaces.putAll(other.mReparentedSurfaces); other.mReparentedSurfaces.clear(); nativeMergeTransaction(mNativeObject, other.mNativeObject); nativeMergeTransaction(mNativeObject, other.mNativeObject); return this; return this; } } Loading
core/java/android/view/SurfaceView.java +57 −11 Original line number Original line Diff line number Diff line Loading @@ -44,7 +44,6 @@ import android.os.SystemClock; import android.util.AttributeSet; import android.util.AttributeSet; import android.util.Log; import android.util.Log; import android.view.SurfaceControl.Transaction; import android.view.SurfaceControl.Transaction; import android.view.SurfaceControlViewHost; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityEmbeddedConnection; import android.view.accessibility.IAccessibilityEmbeddedConnection; Loading Loading @@ -988,6 +987,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName(name) .setName(name) .setLocalOwnerView(this) .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) .setFormat(mFormat) Loading @@ -996,6 +996,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall .build(); .build(); mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Background for -" + name) .setName("Background for -" + name) .setLocalOwnerView(this) .setOpaque(true) .setOpaque(true) .setColorLayer() .setColorLayer() .setParent(mSurfaceControl) .setParent(mSurfaceControl) Loading Loading @@ -1051,11 +1052,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall // we still need to latch a buffer). // we still need to latch a buffer). // b/28866173 // b/28866173 if (sizeChanged || creating || !mRtHandlingPositionUpdates) { if (sizeChanged || creating || !mRtHandlingPositionUpdates) { mTmpTransaction.setPosition(mSurfaceControl, mScreenRect.left, onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl, mScreenRect.top); mScreenRect.left, /*positionLeft*/ mTmpTransaction.setMatrix(mSurfaceControl, mScreenRect.top /*positionTop*/ , mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f, mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/, mScreenRect.height() / (float) mSurfaceHeight); mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/); // Set a window crop when creating the surface or changing its size to // 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 // crop the buffer to the surface size since the buffer producer may // use SCALING_MODE_SCALE and submit a larger size than the surface // use SCALING_MODE_SCALE and submit a larger size than the surface Loading Loading @@ -1211,6 +1213,40 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall Surface viewRootSurface, long nextViewRootFrameNumber) { 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, private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t, Rect position, long frameNumber) { Rect position, long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); final ViewRootImpl viewRoot = getViewRootImpl(); Loading @@ -1219,16 +1255,26 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall frameNumber); frameNumber); } } t.setPosition(surface, position.left, position.top); onSetSurfacePositionAndScaleRT(t, surface, t.setMatrix(surface, position.left /*positionLeft*/, position.width() / (float) mSurfaceWidth, position.top /*positionTop*/, 0.0f, 0.0f, position.width() / (float) mSurfaceWidth /*postScaleX*/, position.height() / (float) mSurfaceHeight); position.height() / (float) mSurfaceHeight /*postScaleY*/); if (mViewVisibility) { if (mViewVisibility) { t.show(surface); 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) { private void setParentSpaceRectangle(Rect position, long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); final ViewRootImpl viewRoot = getViewRootImpl(); final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction(); final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction(); Loading
core/java/android/widget/inline/InlineContentView.java +145 −18 Original line number Original line Diff line number Diff line Loading @@ -18,18 +18,22 @@ package android.widget.inline; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.TestApi; import android.content.Context; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Rect; import android.graphics.PointF; import android.util.AttributeSet; import android.util.AttributeSet; import android.util.Log; import android.util.Log; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.SurfaceControlViewHost; import android.view.SurfaceHolder; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnPreDrawListener; import android.view.ViewTreeObserver; import java.lang.ref.WeakReference; import java.util.function.Consumer; import java.util.function.Consumer; /** /** Loading Loading @@ -88,8 +92,10 @@ public class InlineContentView extends ViewGroup { * * * @hide * @hide */ */ @TestApi public interface SurfacePackageUpdater { public interface SurfacePackageUpdater { /** /** * Called when the previous surface package is released due to view being detached * Called when the previous surface package is released due to view being detached * from the window. * from the window. Loading @@ -101,14 +107,16 @@ public class InlineContentView extends ViewGroup { * * * @param consumer consumes the updated surface package. * @param consumer consumes the updated surface package. */ */ void getSurfacePackage(Consumer<SurfaceControlViewHost.SurfacePackage> consumer); void getSurfacePackage(@NonNull Consumer<SurfaceControlViewHost.SurfacePackage> consumer); } } @NonNull @NonNull private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() { private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() { @Override @Override public void surfaceCreated(@NonNull SurfaceHolder holder) { public void surfaceCreated(@NonNull SurfaceHolder holder) { mSurfaceControlCallback.onCreated(mSurfaceView.getSurfaceControl()); final SurfaceControl surfaceControl = mSurfaceView.getSurfaceControl(); surfaceControl.addOnReparentListener(mOnReparentListener); mSurfaceControlCallback.onCreated(surfaceControl); } } @Override @Override Loading @@ -119,29 +127,58 @@ public class InlineContentView extends ViewGroup { @Override @Override public void surfaceDestroyed(@NonNull SurfaceHolder holder) { 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); } } }; }; @NonNull @NonNull private final SurfaceView mSurfaceView; private final SurfaceView mSurfaceView; @Nullable private WeakReference<SurfaceView> mParentSurfaceOwnerView; @Nullable private int[] mParentPosition; @Nullable private PointF mParentScale; @Nullable @Nullable private SurfaceControlCallback mSurfaceControlCallback; private SurfaceControlCallback mSurfaceControlCallback; @Nullable @Nullable private SurfacePackageUpdater mSurfacePackageUpdater; 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 * @inheritDoc * @hide * @hide Loading Loading @@ -192,10 +229,33 @@ public class InlineContentView extends ViewGroup { public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs, public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, 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.setZOrderOnTop(true); mSurfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT); mSurfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT); addView(mSurfaceView); addView(mSurfaceView); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); } } /** /** Loading @@ -203,6 +263,7 @@ public class InlineContentView extends ViewGroup { * * * @hide * @hide */ */ @TestApi public void setChildSurfacePackageUpdater( public void setChildSurfacePackageUpdater( @Nullable SurfacePackageUpdater surfacePackageUpdater) { @Nullable SurfacePackageUpdater surfacePackageUpdater) { mSurfacePackageUpdater = surfacePackageUpdater; mSurfacePackageUpdater = surfacePackageUpdater; Loading @@ -221,8 +282,9 @@ public class InlineContentView extends ViewGroup { } } }); }); } } mSurfaceView.setVisibility(VISIBLE); getViewTreeObserver().addOnPreDrawListener(mDrawListener); mSurfaceView.setVisibility(getVisibility()); getViewTreeObserver().addOnDrawListener(mOnDrawListener); } } @Override @Override Loading @@ -232,7 +294,9 @@ public class InlineContentView extends ViewGroup { if (mSurfacePackageUpdater != null) { if (mSurfacePackageUpdater != null) { mSurfacePackageUpdater.onSurfacePackageReleased(); mSurfacePackageUpdater.onSurfacePackageReleased(); } } getViewTreeObserver().removeOnPreDrawListener(mDrawListener); getViewTreeObserver().removeOnDrawListener(mOnDrawListener); mSurfaceView.setVisibility(View.GONE); } } @Override @Override Loading Loading @@ -279,4 +343,67 @@ public class InlineContentView extends ViewGroup { public boolean setZOrderedOnTop(boolean onTop) { public boolean setZOrderedOnTop(boolean onTop) { return mSurfaceView.setZOrderedOnTop(onTop, /*allowDynamicChange*/ true); 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(); } } } }