1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view;
18 
19 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
20 import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
21 import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
22 import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
23 
24 import android.annotation.IntDef;
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.content.Context;
29 import android.content.res.CompatibilityInfo.Translator;
30 import android.graphics.BLASTBufferQueue;
31 import android.graphics.BlendMode;
32 import android.graphics.Canvas;
33 import android.graphics.Color;
34 import android.graphics.Matrix;
35 import android.graphics.Paint;
36 import android.graphics.PixelFormat;
37 import android.graphics.Rect;
38 import android.graphics.Region;
39 import android.graphics.RenderNode;
40 import android.os.Build;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.Looper;
44 import android.os.RemoteException;
45 import android.os.SystemClock;
46 import android.util.ArraySet;
47 import android.util.AttributeSet;
48 import android.util.Log;
49 import android.view.SurfaceControl.Transaction;
50 import android.view.accessibility.AccessibilityNodeInfo;
51 import android.view.accessibility.IAccessibilityEmbeddedConnection;
52 import android.window.SurfaceSyncGroup;
53 
54 import com.android.internal.view.SurfaceCallbackHelper;
55 
56 import java.lang.annotation.Retention;
57 import java.lang.annotation.RetentionPolicy;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.concurrent.ConcurrentLinkedQueue;
61 import java.util.concurrent.CountDownLatch;
62 import java.util.concurrent.locks.ReentrantLock;
63 import java.util.function.Consumer;
64 
65 /**
66  * Provides a dedicated drawing surface embedded inside of a view hierarchy.
67  * You can control the format of this surface and, if you like, its size; the
68  * SurfaceView takes care of placing the surface at the correct location on the
69  * screen
70  *
71  * <p>The surface is Z ordered so that it is behind the window holding its
72  * SurfaceView; the SurfaceView punches a hole in its window to allow its
73  * surface to be displayed. The view hierarchy will take care of correctly
74  * compositing with the Surface any siblings of the SurfaceView that would
75  * normally appear on top of it. This can be used to place overlays such as
76  * buttons on top of the Surface, though note however that it can have an
77  * impact on performance since a full alpha-blended composite will be performed
78  * each time the Surface changes.
79  *
80  * <p> The transparent region that makes the surface visible is based on the
81  * layout positions in the view hierarchy. If the post-layout transform
82  * properties are used to draw a sibling view on top of the SurfaceView, the
83  * view may not be properly composited with the surface.
84  *
85  * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
86  * which can be retrieved by calling {@link #getHolder}.
87  *
88  * <p>The Surface will be created for you while the SurfaceView's window is
89  * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
90  * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
91  * Surface is created and destroyed as the window is shown and hidden.
92  *
93  * <p>One of the purposes of this class is to provide a surface in which a
94  * secondary thread can render into the screen. If you are going to use it
95  * this way, you need to be aware of some threading semantics:
96  *
97  * <ul>
98  * <li> All SurfaceView and
99  * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
100  * from the thread running the SurfaceView's window (typically the main thread
101  * of the application). They thus need to correctly synchronize with any
102  * state that is also touched by the drawing thread.
103  * <li> You must ensure that the drawing thread only touches the underlying
104  * Surface while it is valid -- between
105  * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
106  * and
107  * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
108  * </ul>
109  *
110  * <p class="note"><strong>Note:</strong> Starting in platform version
111  * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
112  * updated synchronously with other View rendering. This means that translating
113  * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
114  * artifacts may occur on previous versions of the platform when its window is
115  * positioned asynchronously.</p>
116  *
117  * <p class="note"><strong>Note:</strong> Starting in platform version
118  * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, SurfaceView will support arbitrary
119  * alpha blending. Prior platform versions ignored alpha values on the SurfaceView if they were
120  * between 0 and 1. If the SurfaceView is configured with Z-above, then the alpha is applied
121  * directly to the Surface. If the SurfaceView is configured with Z-below, then the alpha is
122  * applied to the hole punch directly. Note that when using Z-below, overlapping SurfaceViews
123  * may not blend properly as a consequence of not applying alpha to the surface content directly.
124  */
125 public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback {
126     /** @hide */
127     @Retention(RetentionPolicy.SOURCE)
128     @IntDef(prefix = {"SURFACE_LIFECYCLE_"},
129             value = {SURFACE_LIFECYCLE_DEFAULT,
130                      SURFACE_LIFECYCLE_FOLLOWS_VISIBILITY,
131                      SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT})
132     public @interface SurfaceLifecycleStrategy {}
133 
134     /**
135      * Default lifecycle of the Surface owned by this SurfaceView.
136      *
137      * The default lifecycle matches {@link #SURFACE_LIFECYCLE_FOLLOWS_VISIBILITY}.
138      */
139     public static final int SURFACE_LIFECYCLE_DEFAULT = 0;
140 
141     /**
142      * The Surface lifecycle is tied to SurfaceView visibility.
143      *
144      * The Surface is created when the SurfaceView becomes visible, and is destroyed when the
145      * SurfaceView is no longer visible.
146      */
147     public static final int SURFACE_LIFECYCLE_FOLLOWS_VISIBILITY = 1;
148 
149     /**
150      * The Surface lifecycle is tied to SurfaceView attachment.
151      * The Surface is created when the SurfaceView first becomes attached, but is not destroyed
152      * until this SurfaceView has been detached from the current window.
153      */
154     public static final int SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT = 2;
155 
156     private static final String TAG = "SurfaceView";
157     private static final boolean DEBUG = false;
158     private static final boolean DEBUG_POSITION = false;
159 
160     @UnsupportedAppUsage(
161             maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
162             publicAlternatives = "Track {@link SurfaceHolder#addCallback} instead")
163     final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<>();
164 
165     final int[] mLocation = new int[2];
166 
167     @UnsupportedAppUsage(
168             maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
169             publicAlternatives = "Use {@link SurfaceHolder#lockCanvas} instead")
170     final ReentrantLock mSurfaceLock = new ReentrantLock();
171     @UnsupportedAppUsage(
172             maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
173             publicAlternatives = "Use {@link SurfaceHolder#getSurface} instead")
174     final Surface mSurface = new Surface();       // Current surface in use
175     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
176                          publicAlternatives = "Use {@link View#getVisibility} instead")
177     boolean mDrawingStopped = true;
178     // We use this to track if the application has produced a frame
179     // in to the Surface. Up until that point, we should be careful not to punch
180     // holes.
181     boolean mDrawFinished = false;
182 
183     final Rect mScreenRect = new Rect();
184     private final SurfaceSession mSurfaceSession = new SurfaceSession();
185 
186     SurfaceControl mSurfaceControl;
187     SurfaceControl mBackgroundControl;
188     private boolean mDisableBackgroundLayer = false;
189 
190     @SurfaceLifecycleStrategy
191     private int mRequestedSurfaceLifecycleStrategy = SURFACE_LIFECYCLE_DEFAULT;
192     @SurfaceLifecycleStrategy
193     private int mSurfaceLifecycleStrategy = SURFACE_LIFECYCLE_DEFAULT;
194 
195     /**
196      * We use this lock to protect access to mSurfaceControl. Both are accessed on the UI
197      * thread and the render thread via RenderNode.PositionUpdateListener#positionLost.
198      */
199     final Object mSurfaceControlLock = new Object();
200     final Rect mTmpRect = new Rect();
201 
202     Paint mRoundedViewportPaint;
203 
204     int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
205     int mRequestedSubLayer = APPLICATION_MEDIA_SUBLAYER;
206 
207     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
208                          publicAlternatives = "Use {@link SurfaceHolder#isCreating} instead")
209     boolean mIsCreating = false;
210 
211     private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener =
212             this::updateSurface;
213 
214     @UnsupportedAppUsage(
215             maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
216             publicAlternatives = "Rely on {@link ViewTreeObserver#dispatchOnPreDraw} instead")
217     private final ViewTreeObserver.OnPreDrawListener mDrawListener = () -> {
218         // reposition ourselves where the surface is
219         mHaveFrame = getWidth() > 0 && getHeight() > 0;
220         updateSurface();
221         return true;
222     };
223 
224     boolean mRequestedVisible = false;
225     boolean mWindowVisibility = false;
226     boolean mLastWindowVisibility = false;
227     boolean mViewVisibility = false;
228     boolean mWindowStopped = false;
229 
230     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
231                          publicAlternatives = "Use {@link View#getWidth} instead")
232     int mRequestedWidth = -1;
233     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
234                          publicAlternatives = "Use {@link View#getHeight} instead")
235     int mRequestedHeight = -1;
236     /* Set SurfaceView's format to 565 by default to maintain backward
237      * compatibility with applications assuming this format.
238      */
239     @UnsupportedAppUsage(
240             maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
241             publicAlternatives = "Use {@code SurfaceHolder.Callback#surfaceChanged} instead")
242     int mRequestedFormat = PixelFormat.RGB_565;
243 
244     float mAlpha = 1f;
245     boolean mClipSurfaceToBounds;
246     int mBackgroundColor = Color.BLACK;
247 
248     @UnsupportedAppUsage(
249             maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
250             publicAlternatives = "Use {@link View#getWidth} and {@link View#getHeight} to "
251                     + "determine if the SurfaceView is onscreen and has a frame")
252     boolean mHaveFrame = false;
253     boolean mSurfaceCreated = false;
254     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
255                          publicAlternatives = "Time {@link SurfaceHolder#lockCanvas} instead")
256     long mLastLockTime = 0;
257 
258     boolean mVisible = false;
259     int mWindowSpaceLeft = -1;
260     int mWindowSpaceTop = -1;
261     int mSurfaceWidth = -1;
262     int mSurfaceHeight = -1;
263     float mCornerRadius;
264     @UnsupportedAppUsage(
265             maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
266             publicAlternatives = "Use {@code SurfaceHolder.Callback#surfaceChanged} "
267             + "instead")
268     int mFormat = -1;
269     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
270                          publicAlternatives = "Use {@link SurfaceHolder#getSurfaceFrame} instead")
271     final Rect mSurfaceFrame = new Rect();
272     int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
273     @SurfaceControl.BufferTransform int mTransformHint = 0;
274 
275     private boolean mGlobalListenersAdded;
276     private boolean mAttachedToWindow;
277 
278     private int mSurfaceFlags = SurfaceControl.HIDDEN;
279 
280     private final ArraySet<SurfaceSyncGroup> mSyncGroups = new ArraySet<>();
281 
282     /**
283      * Transaction that should be used from the render thread. This transaction is only thread safe
284      * with other calls directly from the render thread.
285      */
286     private final SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
287 
288     /**
289      * Transaction that should be used whe
290      * {@link HardwareRenderer.FrameDrawingCallback#onFrameDraw} is invoked. All
291      * frame callbacks can use the same transaction since they will be thread safe
292      */
293     private final SurfaceControl.Transaction mFrameCallbackTransaction =
294             new SurfaceControl.Transaction();
295 
296     private int mParentSurfaceSequenceId;
297 
298     private RemoteAccessibilityController mRemoteAccessibilityController =
299         new RemoteAccessibilityController(this);
300 
301     private final Matrix mTmpMatrix = new Matrix();
302 
303     SurfaceControlViewHost.SurfacePackage mSurfacePackage;
304 
305 
306     private SurfaceControl mBlastSurfaceControl;
307     private BLASTBufferQueue mBlastBufferQueue;
308 
309     private final ConcurrentLinkedQueue<WindowManager.LayoutParams> mEmbeddedWindowParams =
310             new ConcurrentLinkedQueue<>();
311 
312     private final ISurfaceControlViewHostParent mSurfaceControlViewHostParent =
313             new ISurfaceControlViewHostParent.Stub() {
314         @Override
315         public void updateParams(WindowManager.LayoutParams[] childAttrs) {
316             mEmbeddedWindowParams.clear();
317             mEmbeddedWindowParams.addAll(Arrays.asList(childAttrs));
318 
319             if (isAttachedToWindow()) {
320                 runOnUiThread(() -> {
321                     if (mParent != null) {
322                         mParent.recomputeViewAttributes(SurfaceView.this);
323                     }
324                 });
325             }
326         }
327     };
328 
SurfaceView(Context context)329     public SurfaceView(Context context) {
330         this(context, null);
331     }
332 
SurfaceView(Context context, AttributeSet attrs)333     public SurfaceView(Context context, AttributeSet attrs) {
334         this(context, attrs, 0);
335     }
336 
SurfaceView(Context context, AttributeSet attrs, int defStyleAttr)337     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
338         this(context, attrs, defStyleAttr, 0);
339     }
340 
SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)341     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
342         this(context, attrs, defStyleAttr, defStyleRes, false);
343     }
344 
345     /** @hide */
SurfaceView(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes, boolean disableBackgroundLayer)346     public SurfaceView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
347             int defStyleRes, boolean disableBackgroundLayer) {
348         super(context, attrs, defStyleAttr, defStyleRes);
349         setWillNotDraw(true);
350         mDisableBackgroundLayer = disableBackgroundLayer;
351     }
352 
353     /**
354      * Return the SurfaceHolder providing access and control over this
355      * SurfaceView's underlying surface.
356      *
357      * @return SurfaceHolder The holder of the surface.
358      */
getHolder()359     public SurfaceHolder getHolder() {
360         return mSurfaceHolder;
361     }
362 
updateRequestedVisibility()363     private void updateRequestedVisibility() {
364         mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
365     }
366 
setWindowStopped(boolean stopped)367     private void setWindowStopped(boolean stopped) {
368         mWindowStopped = stopped;
369         updateRequestedVisibility();
370         updateSurface();
371     }
372 
373     @Override
onAttachedToWindow()374     protected void onAttachedToWindow() {
375         super.onAttachedToWindow();
376 
377         getViewRootImpl().addSurfaceChangedCallback(this);
378         mWindowStopped = false;
379 
380         mViewVisibility = getVisibility() == VISIBLE;
381         updateRequestedVisibility();
382 
383         mAttachedToWindow = true;
384         mParent.requestTransparentRegion(SurfaceView.this);
385         if (!mGlobalListenersAdded) {
386             ViewTreeObserver observer = getViewTreeObserver();
387             observer.addOnScrollChangedListener(mScrollChangedListener);
388             observer.addOnPreDrawListener(mDrawListener);
389             mGlobalListenersAdded = true;
390         }
391     }
392 
393     @Override
onWindowVisibilityChanged(int visibility)394     protected void onWindowVisibilityChanged(int visibility) {
395         super.onWindowVisibilityChanged(visibility);
396         mWindowVisibility = visibility == VISIBLE;
397         updateRequestedVisibility();
398         updateSurface();
399     }
400 
401     @Override
setVisibility(int visibility)402     public void setVisibility(int visibility) {
403         super.setVisibility(visibility);
404         mViewVisibility = visibility == VISIBLE;
405         boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
406         if (newRequestedVisible != mRequestedVisible) {
407             // our base class (View) invalidates the layout only when
408             // we go from/to the GONE state. However, SurfaceView needs
409             // to request a re-layout when the visibility changes at all.
410             // This is needed because the transparent region is computed
411             // as part of the layout phase, and it changes (obviously) when
412             // the visibility changes.
413             requestLayout();
414         }
415         mRequestedVisible = newRequestedVisible;
416         updateSurface();
417     }
418 
419     /**
420      * Make alpha value of this view reflect onto the surface. This can only be called from at most
421      * one SurfaceView within a view tree.
422      *
423      * <p class="note"><strong>Note:</strong> Alpha value of the view is ignored and the underlying
424      * surface is rendered opaque by default.</p>
425      *
426      * @hide
427      */
setUseAlpha()428     public void setUseAlpha() {
429         // TODO(b/241474646): Remove me
430         return;
431     }
432 
433     @Override
setAlpha(float alpha)434     public void setAlpha(float alpha) {
435         if (DEBUG) {
436             Log.d(TAG, System.identityHashCode(this)
437                     + " setAlpha: alpha=" + alpha);
438         }
439         super.setAlpha(alpha);
440     }
441 
442     @Override
onSetAlpha(int alpha)443     protected boolean onSetAlpha(int alpha) {
444         if (Math.round(mAlpha * 255) != alpha) {
445             updateSurface();
446         }
447         return true;
448     }
449 
performDrawFinished()450     private void performDrawFinished() {
451         mDrawFinished = true;
452         if (mAttachedToWindow) {
453             mParent.requestTransparentRegion(SurfaceView.this);
454             invalidate();
455         }
456     }
457 
458     @Override
onDetachedFromWindow()459     protected void onDetachedFromWindow() {
460         ViewRootImpl viewRoot = getViewRootImpl();
461         // It's possible to create a SurfaceView using the default constructor and never
462         // attach it to a view hierarchy, this is a common use case when dealing with
463         // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
464         // the lifecycle. Instead of attaching it to a view, they can just pass
465         // the SurfaceHolder forward, most live wallpapers do it.
466         if (viewRoot != null) {
467             viewRoot.removeSurfaceChangedCallback(this);
468         }
469 
470         mAttachedToWindow = false;
471         if (mGlobalListenersAdded) {
472             ViewTreeObserver observer = getViewTreeObserver();
473             observer.removeOnScrollChangedListener(mScrollChangedListener);
474             observer.removeOnPreDrawListener(mDrawListener);
475             mGlobalListenersAdded = false;
476         }
477         if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " Detaching SV");
478 
479         mRequestedVisible = false;
480 
481         updateSurface();
482         releaseSurfaces(true /* releaseSurfacePackage*/);
483 
484         mHaveFrame = false;
485         super.onDetachedFromWindow();
486     }
487 
488     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)489     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
490         int width = mRequestedWidth >= 0
491                 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
492                 : getDefaultSize(0, widthMeasureSpec);
493         int height = mRequestedHeight >= 0
494                 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
495                 : getDefaultSize(0, heightMeasureSpec);
496         setMeasuredDimension(width, height);
497     }
498 
499     /** @hide */
500     @Override
501     @UnsupportedAppUsage
setFrame(int left, int top, int right, int bottom)502     protected boolean setFrame(int left, int top, int right, int bottom) {
503         boolean result = super.setFrame(left, top, right, bottom);
504         updateSurface();
505         return result;
506     }
507 
508     @Override
gatherTransparentRegion(Region region)509     public boolean gatherTransparentRegion(Region region) {
510         if (isAboveParent() || !mDrawFinished) {
511             return super.gatherTransparentRegion(region);
512         }
513 
514         boolean opaque = true;
515         if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
516             // this view draws, remove it from the transparent region
517             opaque = super.gatherTransparentRegion(region);
518         } else if (region != null) {
519             int w = getWidth();
520             int h = getHeight();
521             if (w>0 && h>0) {
522                 getLocationInWindow(mLocation);
523                 // otherwise, punch a hole in the whole hierarchy
524                 int l = mLocation[0];
525                 int t = mLocation[1];
526                 region.op(l, t, l+w, t+h, Region.Op.UNION);
527             }
528         }
529         if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
530             opaque = false;
531         }
532         return opaque;
533     }
534 
535     @Override
draw(Canvas canvas)536     public void draw(Canvas canvas) {
537         if (mDrawFinished && !isAboveParent()) {
538             // draw() is not called when SKIP_DRAW is set
539             if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
540                 // punch a whole in the view-hierarchy below us
541                 clearSurfaceViewPort(canvas);
542             }
543         }
544         super.draw(canvas);
545     }
546 
547     @Override
dispatchDraw(Canvas canvas)548     protected void dispatchDraw(Canvas canvas) {
549         if (mDrawFinished && !isAboveParent()) {
550             // draw() is not called when SKIP_DRAW is set
551             if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
552                 // punch a whole in the view-hierarchy below us
553                 clearSurfaceViewPort(canvas);
554             }
555         }
556         super.dispatchDraw(canvas);
557     }
558 
559     /**
560      * Control whether the surface is clipped to the same bounds as the View. If true, then
561      * the bounds set by {@link #setClipBounds(Rect)} are applied to the surface as window-crop.
562      *
563      * @param enabled whether to enable surface clipping
564      * @hide
565      */
setEnableSurfaceClipping(boolean enabled)566     public void setEnableSurfaceClipping(boolean enabled) {
567         mClipSurfaceToBounds = enabled;
568         invalidate();
569     }
570 
571     @Override
setClipBounds(Rect clipBounds)572     public void setClipBounds(Rect clipBounds) {
573         super.setClipBounds(clipBounds);
574 
575         if (!mClipSurfaceToBounds || mSurfaceControl == null) {
576             return;
577         }
578 
579         // When cornerRadius is non-zero, a draw() is required to update
580         // the viewport (rounding the corners of the clipBounds).
581         if (mCornerRadius > 0f && !isAboveParent()) {
582             invalidate();
583         }
584 
585         if (mClipBounds != null) {
586             mTmpRect.set(mClipBounds);
587         } else {
588             mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
589         }
590         final Transaction transaction = new Transaction();
591         transaction.setWindowCrop(mSurfaceControl, mTmpRect);
592         applyTransactionOnVriDraw(transaction);
593         invalidate();
594     }
595 
596     @Override
hasOverlappingRendering()597     public boolean hasOverlappingRendering() {
598         // SurfaceViews only alpha composite by modulating the Surface alpha for Z-above, or
599         // applying alpha on the hole punch for Z-below - no deferral to a layer is necessary.
600         return false;
601     }
602 
clearSurfaceViewPort(Canvas canvas)603     private void clearSurfaceViewPort(Canvas canvas) {
604         final float alpha = getAlpha();
605         if (mCornerRadius > 0f) {
606             canvas.getClipBounds(mTmpRect);
607             if (mClipSurfaceToBounds && mClipBounds != null) {
608                 mTmpRect.intersect(mClipBounds);
609             }
610             canvas.punchHole(
611                     mTmpRect.left,
612                     mTmpRect.top,
613                     mTmpRect.right,
614                     mTmpRect.bottom,
615                     mCornerRadius,
616                     mCornerRadius,
617                     alpha
618             );
619         } else {
620             canvas.punchHole(0f, 0f, getWidth(), getHeight(), 0f, 0f, alpha);
621         }
622     }
623 
624     /**
625      * Sets the corner radius for the SurfaceView. This will round both the corners of the
626      * underlying surface, as well as the corners of the hole created to expose the surface.
627      *
628      * @param cornerRadius the new radius of the corners in pixels
629      * @hide
630      */
setCornerRadius(float cornerRadius)631     public void setCornerRadius(float cornerRadius) {
632         mCornerRadius = cornerRadius;
633         if (mCornerRadius > 0f && mRoundedViewportPaint == null) {
634             mRoundedViewportPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
635             mRoundedViewportPaint.setBlendMode(BlendMode.CLEAR);
636             mRoundedViewportPaint.setColor(0);
637         }
638         invalidate();
639     }
640 
641     /**
642      * Returns the corner radius for the SurfaceView.
643 
644      * @return the radius of the corners in pixels
645      * @hide
646      */
getCornerRadius()647     public float getCornerRadius() {
648         return mCornerRadius;
649     }
650 
651     /**
652      * Control whether the surface view's surface is placed on top of another
653      * regular surface view in the window (but still behind the window itself).
654      * This is typically used to place overlays on top of an underlying media
655      * surface view.
656      *
657      * <p>Note that this must be set before the surface view's containing
658      * window is attached to the window manager.
659      *
660      * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
661      */
setZOrderMediaOverlay(boolean isMediaOverlay)662     public void setZOrderMediaOverlay(boolean isMediaOverlay) {
663         mRequestedSubLayer = isMediaOverlay
664             ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
665     }
666 
667     /**
668      * Control whether the surface view's surface is placed on top of its
669      * window.  Normally it is placed behind the window, to allow it to
670      * (for the most part) appear to composite with the views in the
671      * hierarchy.  By setting this, you cause it to be placed above the
672      * window.  This means that none of the contents of the window this
673      * SurfaceView is in will be visible on top of its surface.
674      *
675      * <p>Note that this must be set before the surface view's containing
676      * window is attached to the window manager. If you target {@link Build.VERSION_CODES#R}
677      * the Z ordering can be changed dynamically if the backing surface is
678      * created, otherwise it would be applied at surface construction time.
679      *
680      * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
681      *
682      * @param onTop Whether to show the surface on top of this view's window.
683      */
setZOrderOnTop(boolean onTop)684     public void setZOrderOnTop(boolean onTop) {
685         // In R and above we allow dynamic layer changes.
686         final boolean allowDynamicChange = getContext().getApplicationInfo().targetSdkVersion
687                 > Build.VERSION_CODES.Q;
688         setZOrderedOnTop(onTop, allowDynamicChange);
689     }
690 
691     /**
692      * @return Whether the surface backing this view appears on top of its parent.
693      *
694      * @hide
695      */
isZOrderedOnTop()696     public boolean isZOrderedOnTop() {
697         return mRequestedSubLayer > 0;
698     }
699 
700     /**
701      * Controls whether the surface view's surface is placed on top of its
702      * window. Normally it is placed behind the window, to allow it to
703      * (for the most part) appear to composite with the views in the
704      * hierarchy. By setting this, you cause it to be placed above the
705      * window. This means that none of the contents of the window this
706      * SurfaceView is in will be visible on top of its surface.
707      *
708      * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
709      *
710      * @param onTop Whether to show the surface on top of this view's window.
711      * @param allowDynamicChange Whether this can happen after the surface is created.
712      * @return Whether the Z ordering changed.
713      *
714      * @hide
715      */
setZOrderedOnTop(boolean onTop, boolean allowDynamicChange)716     public boolean setZOrderedOnTop(boolean onTop, boolean allowDynamicChange) {
717         final int subLayer;
718         if (onTop) {
719             subLayer = APPLICATION_PANEL_SUBLAYER;
720         } else {
721             subLayer = APPLICATION_MEDIA_SUBLAYER;
722         }
723         if (mRequestedSubLayer == subLayer) {
724             return false;
725         }
726         mRequestedSubLayer = subLayer;
727 
728         if (!allowDynamicChange) {
729             return false;
730         }
731         if (mSurfaceControl == null) {
732             return true;
733         }
734         final ViewRootImpl viewRoot = getViewRootImpl();
735         if (viewRoot == null) {
736             return true;
737         }
738 
739         updateSurface();
740         invalidate();
741         return true;
742     }
743 
744     /**
745      * Control whether the surface view's content should be treated as secure,
746      * preventing it from appearing in screenshots or from being viewed on
747      * non-secure displays.
748      *
749      * <p>Note that this must be set before the surface view's containing
750      * window is attached to the window manager.
751      *
752      * <p>See {@link android.view.Display#FLAG_SECURE} for details.
753      *
754      * @param isSecure True if the surface view is secure.
755      */
setSecure(boolean isSecure)756     public void setSecure(boolean isSecure) {
757         if (isSecure) {
758             mSurfaceFlags |= SurfaceControl.SECURE;
759         } else {
760             mSurfaceFlags &= ~SurfaceControl.SECURE;
761         }
762     }
763 
764     /**
765      * Controls the lifecycle of the Surface owned by this SurfaceView.
766      *
767      * <p>By default, the lifecycycle strategy employed by the SurfaceView is
768      * {@link #SURFACE_LIFECYCLE_DEFAULT}.
769      *
770      * @param lifecycleStrategy The strategy for the lifecycle of the Surface owned by this
771      * SurfaceView.
772      */
setSurfaceLifecycle(@urfaceLifecycleStrategy int lifecycleStrategy)773     public void setSurfaceLifecycle(@SurfaceLifecycleStrategy int lifecycleStrategy) {
774         mRequestedSurfaceLifecycleStrategy = lifecycleStrategy;
775         updateSurface();
776     }
777 
updateOpaqueFlag()778     private void updateOpaqueFlag() {
779         if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
780             mSurfaceFlags |= SurfaceControl.OPAQUE;
781         } else {
782             mSurfaceFlags &= ~SurfaceControl.OPAQUE;
783         }
784     }
785 
updateBackgroundVisibility(Transaction t)786     private void updateBackgroundVisibility(Transaction t) {
787         if (mBackgroundControl == null) {
788             return;
789         }
790         if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
791                 && !mDisableBackgroundLayer) {
792             t.show(mBackgroundControl);
793         } else {
794             t.hide(mBackgroundControl);
795         }
796     }
797 
updateBackgroundColor(Transaction t)798     private Transaction updateBackgroundColor(Transaction t) {
799         final float[] colorComponents = new float[] { Color.red(mBackgroundColor) / 255.f,
800                 Color.green(mBackgroundColor) / 255.f, Color.blue(mBackgroundColor) / 255.f };
801         t.setColor(mBackgroundControl, colorComponents);
802         return t;
803     }
804 
releaseSurfaces(boolean releaseSurfacePackage)805     private void releaseSurfaces(boolean releaseSurfacePackage) {
806         mAlpha = 1f;
807         mSurface.destroy();
808         synchronized (mSurfaceControlLock) {
809             if (mBlastBufferQueue != null) {
810                 mBlastBufferQueue.destroy();
811                 mBlastBufferQueue = null;
812             }
813 
814             final Transaction transaction = new Transaction();
815             if (mSurfaceControl != null) {
816                 transaction.remove(mSurfaceControl);
817                 mSurfaceControl = null;
818             }
819             if (mBackgroundControl != null) {
820                 transaction.remove(mBackgroundControl);
821                 mBackgroundControl = null;
822             }
823             if (mBlastSurfaceControl != null) {
824                 transaction.remove(mBlastSurfaceControl);
825                 mBlastSurfaceControl = null;
826             }
827 
828             if (mSurfacePackage != null) {
829                 try {
830                     mSurfacePackage.getRemoteInterface().attachParentInterface(null);
831                     mEmbeddedWindowParams.clear();
832                 } catch (RemoteException e) {
833                     Log.d(TAG, "Failed to remove parent interface from SCVH. Likely SCVH is "
834                             + "already dead");
835                 }
836                 if (releaseSurfacePackage) {
837                     mSurfacePackage.release();
838                     mSurfacePackage = null;
839                 }
840             }
841 
842             applyTransactionOnVriDraw(transaction);
843         }
844     }
845 
846     // The position update listener is used to safely share the surface size between render thread
847     // workers and the UI thread. Both threads need to know the surface size to determine the scale.
848     // The parent layer scales the surface size to view size. The child (BBQ) layer scales
849     // the buffer to the surface size. Both scales along with the window crop must be applied
850     // synchronously otherwise we may see flickers.
851     // When the listener is updated, we will get at least a single position update call so we can
852     // guarantee any changes we post will be applied.
replacePositionUpdateListener(int surfaceWidth, int surfaceHeight)853     private void replacePositionUpdateListener(int surfaceWidth, int surfaceHeight) {
854         if (mPositionListener != null) {
855             mRenderNode.removePositionUpdateListener(mPositionListener);
856         }
857         mPositionListener = new SurfaceViewPositionUpdateListener(surfaceWidth, surfaceHeight);
858         mRenderNode.addPositionUpdateListener(mPositionListener);
859     }
860 
performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator, boolean creating, boolean sizeChanged, boolean hintChanged, boolean relativeZChanged, Transaction surfaceUpdateTransaction)861     private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
862             boolean creating, boolean sizeChanged, boolean hintChanged, boolean relativeZChanged,
863             Transaction surfaceUpdateTransaction) {
864         boolean realSizeChanged = false;
865 
866         mSurfaceLock.lock();
867         try {
868             mDrawingStopped = !surfaceShouldExist();
869 
870             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
871                     + "Cur surface: " + mSurface);
872 
873             // If we are creating the surface control or the parent surface has not
874             // changed, then set relative z. Otherwise allow the parent
875             // SurfaceChangedCallback to update the relative z. This is needed so that
876             // we do not change the relative z before the server is ready to swap the
877             // parent surface.
878             if (creating) {
879                 updateRelativeZ(surfaceUpdateTransaction);
880                 if (mSurfacePackage != null) {
881                     reparentSurfacePackage(surfaceUpdateTransaction, mSurfacePackage);
882                 }
883             }
884             mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId();
885 
886             // Only control visibility if we're not hardware-accelerated. Otherwise we'll
887             // let renderthread drive since offscreen SurfaceControls should not be visible.
888             if (!isHardwareAccelerated()) {
889                 if (mViewVisibility) {
890                     surfaceUpdateTransaction.show(mSurfaceControl);
891                 } else {
892                     surfaceUpdateTransaction.hide(mSurfaceControl);
893                 }
894             }
895 
896             updateBackgroundVisibility(surfaceUpdateTransaction);
897             updateBackgroundColor(surfaceUpdateTransaction);
898             if (isAboveParent()) {
899                 float alpha = getAlpha();
900                 surfaceUpdateTransaction.setAlpha(mSurfaceControl, alpha);
901             }
902 
903             if (relativeZChanged) {
904                 if (!isAboveParent()) {
905                     // If we're moving from z-above to z-below, then restore the surface alpha back to 1
906                     // and let the holepunch drive visibility and blending.
907                     surfaceUpdateTransaction.setAlpha(mSurfaceControl, 1.f);
908                 }
909                 updateRelativeZ(surfaceUpdateTransaction);
910             }
911 
912             surfaceUpdateTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
913             if ((sizeChanged || hintChanged) && !creating) {
914                 setBufferSize(surfaceUpdateTransaction);
915             }
916             if (sizeChanged || creating || !isHardwareAccelerated()) {
917 
918                 // Set a window crop when creating the surface or changing its size to
919                 // crop the buffer to the surface size since the buffer producer may
920                 // use SCALING_MODE_SCALE and submit a larger size than the surface
921                 // size.
922                 if (mClipSurfaceToBounds && mClipBounds != null) {
923                     surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
924                 } else {
925                     surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
926                             mSurfaceHeight);
927                 }
928 
929                 surfaceUpdateTransaction.setDesintationFrame(mBlastSurfaceControl, mSurfaceWidth,
930                             mSurfaceHeight);
931 
932                 if (isHardwareAccelerated()) {
933                     // This will consume the passed in transaction and the transaction will be
934                     // applied on a render worker thread.
935                     replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight);
936                 } else {
937                     onSetSurfacePositionAndScale(surfaceUpdateTransaction, mSurfaceControl,
938                             mScreenRect.left /*positionLeft*/,
939                             mScreenRect.top /*positionTop*/,
940                             mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
941                             mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
942                 }
943                 if (DEBUG_POSITION) {
944                     Log.d(TAG, String.format(
945                             "%d performSurfaceTransaction %s "
946                                 + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
947                             System.identityHashCode(this),
948                             isHardwareAccelerated() ? "RenderWorker" : "UI Thread",
949                             mScreenRect.left, mScreenRect.top, mScreenRect.right,
950                             mScreenRect.bottom, mSurfaceWidth, mSurfaceHeight));
951                 }
952             }
953             applyTransactionOnVriDraw(surfaceUpdateTransaction);
954             updateEmbeddedAccessibilityMatrix(false);
955 
956             mSurfaceFrame.left = 0;
957             mSurfaceFrame.top = 0;
958             if (translator == null) {
959                 mSurfaceFrame.right = mSurfaceWidth;
960                 mSurfaceFrame.bottom = mSurfaceHeight;
961             } else {
962                 float appInvertedScale = translator.applicationInvertedScale;
963                 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
964                 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
965             }
966             final int surfaceWidth = mSurfaceFrame.right;
967             final int surfaceHeight = mSurfaceFrame.bottom;
968             realSizeChanged = mLastSurfaceWidth != surfaceWidth
969                     || mLastSurfaceHeight != surfaceHeight;
970             mLastSurfaceWidth = surfaceWidth;
971             mLastSurfaceHeight = surfaceHeight;
972         } finally {
973             mSurfaceLock.unlock();
974         }
975 
976         return realSizeChanged;
977     }
978 
requiresSurfaceControlCreation(boolean formatChanged, boolean visibleChanged)979     private boolean requiresSurfaceControlCreation(boolean formatChanged, boolean visibleChanged) {
980         if (mSurfaceLifecycleStrategy == SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT) {
981             return (mSurfaceControl == null || formatChanged) && mAttachedToWindow;
982         }
983 
984         return (mSurfaceControl == null || formatChanged || visibleChanged) && mRequestedVisible;
985     }
986 
surfaceShouldExist()987     private boolean surfaceShouldExist() {
988         final boolean respectVisibility =
989                 mSurfaceLifecycleStrategy != SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT;
990         return mVisible || (!respectVisibility && mAttachedToWindow);
991     }
992 
993     /** @hide */
updateSurface()994     protected void updateSurface() {
995         if (!mHaveFrame) {
996             if (DEBUG) {
997                 Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
998             }
999             return;
1000         }
1001         final ViewRootImpl viewRoot = getViewRootImpl();
1002 
1003         if (viewRoot == null) {
1004             return;
1005         }
1006 
1007         if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
1008             notifySurfaceDestroyed();
1009             releaseSurfaces(false /* releaseSurfacePackage*/);
1010             return;
1011         }
1012 
1013         final Translator translator = viewRoot.mTranslator;
1014         if (translator != null) {
1015             mSurface.setCompatibilityTranslator(translator);
1016         }
1017 
1018         int myWidth = mRequestedWidth;
1019         if (myWidth <= 0) myWidth = getWidth();
1020         int myHeight = mRequestedHeight;
1021         if (myHeight <= 0) myHeight = getHeight();
1022 
1023         final float alpha = getAlpha();
1024         final boolean formatChanged = mFormat != mRequestedFormat;
1025         final boolean visibleChanged = mVisible != mRequestedVisible;
1026         final boolean alphaChanged = mAlpha != alpha;
1027         final boolean creating = requiresSurfaceControlCreation(formatChanged, visibleChanged);
1028         final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
1029         final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
1030         getLocationInWindow(mLocation);
1031         final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
1032             || mWindowSpaceTop != mLocation[1];
1033         final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
1034             || getHeight() != mScreenRect.height();
1035         final boolean hintChanged = (viewRoot.getBufferTransformHint() != mTransformHint)
1036                 && mRequestedVisible;
1037         final boolean relativeZChanged = mSubLayer != mRequestedSubLayer;
1038         final boolean surfaceLifecycleStrategyChanged =
1039                 mSurfaceLifecycleStrategy != mRequestedSurfaceLifecycleStrategy;
1040 
1041         if (creating || formatChanged || sizeChanged || visibleChanged
1042                 || alphaChanged || windowVisibleChanged || positionChanged
1043                 || layoutSizeChanged || hintChanged || relativeZChanged || !mAttachedToWindow
1044                 || surfaceLifecycleStrategyChanged) {
1045 
1046             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1047                     + "Changes: creating=" + creating
1048                     + " format=" + formatChanged + " size=" + sizeChanged
1049                     + " visible=" + visibleChanged + " alpha=" + alphaChanged
1050                     + " hint=" + hintChanged
1051                     + " visible=" + visibleChanged
1052                     + " left=" + (mWindowSpaceLeft != mLocation[0])
1053                     + " top=" + (mWindowSpaceTop != mLocation[1])
1054                     + " z=" + relativeZChanged
1055                     + " attached=" + mAttachedToWindow
1056                     + " lifecycleStrategy=" + surfaceLifecycleStrategyChanged);
1057 
1058             try {
1059                 mVisible = mRequestedVisible;
1060                 mWindowSpaceLeft = mLocation[0];
1061                 mWindowSpaceTop = mLocation[1];
1062                 mSurfaceWidth = myWidth;
1063                 mSurfaceHeight = myHeight;
1064                 mFormat = mRequestedFormat;
1065                 mAlpha = alpha;
1066                 mLastWindowVisibility = mWindowVisibility;
1067                 mTransformHint = viewRoot.getBufferTransformHint();
1068                 mSubLayer = mRequestedSubLayer;
1069 
1070                 final int previousSurfaceLifecycleStrategy = mSurfaceLifecycleStrategy;
1071                 mSurfaceLifecycleStrategy = mRequestedSurfaceLifecycleStrategy;
1072 
1073                 mScreenRect.left = mWindowSpaceLeft;
1074                 mScreenRect.top = mWindowSpaceTop;
1075                 mScreenRect.right = mWindowSpaceLeft + getWidth();
1076                 mScreenRect.bottom = mWindowSpaceTop + getHeight();
1077                 if (translator != null) {
1078                     translator.translateRectInAppWindowToScreen(mScreenRect);
1079                 }
1080 
1081                 final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
1082                 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
1083                 // Collect all geometry changes and apply these changes on the RenderThread worker
1084                 // via the RenderNode.PositionUpdateListener.
1085                 final Transaction surfaceUpdateTransaction = new Transaction();
1086                 if (creating) {
1087                     updateOpaqueFlag();
1088                     final String name = "SurfaceView[" + viewRoot.getTitle().toString() + "]";
1089                     createBlastSurfaceControls(viewRoot, name, surfaceUpdateTransaction);
1090                 } else if (mSurfaceControl == null) {
1091                     return;
1092                 }
1093 
1094                 final boolean redrawNeeded = sizeChanged || creating || hintChanged
1095                         || (mVisible && !mDrawFinished) || alphaChanged || relativeZChanged;
1096                 boolean shouldSyncBuffer = redrawNeeded && viewRoot.wasRelayoutRequested()
1097                         && viewRoot.isInWMSRequestedSync();
1098                 SyncBufferTransactionCallback syncBufferTransactionCallback = null;
1099                 if (shouldSyncBuffer) {
1100                     syncBufferTransactionCallback = new SyncBufferTransactionCallback();
1101                     mBlastBufferQueue.syncNextTransaction(
1102                             false /* acquireSingleBuffer */,
1103                             syncBufferTransactionCallback::onTransactionReady);
1104                 }
1105 
1106                 final boolean realSizeChanged = performSurfaceTransaction(viewRoot, translator,
1107                         creating, sizeChanged, hintChanged, relativeZChanged,
1108                         surfaceUpdateTransaction);
1109 
1110                 try {
1111                     SurfaceHolder.Callback[] callbacks = null;
1112 
1113                     final boolean surfaceChanged = creating;
1114                     final boolean respectVisibility =
1115                             mSurfaceLifecycleStrategy != SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT;
1116                     final boolean previouslyDidNotRespectVisibility =
1117                             previousSurfaceLifecycleStrategy
1118                                     == SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT;
1119                     final boolean lifecycleNewlyRespectsVisibility = respectVisibility
1120                             && previouslyDidNotRespectVisibility;
1121                     if (mSurfaceCreated) {
1122                         if (surfaceChanged || (!respectVisibility && !mAttachedToWindow)
1123                                 || (respectVisibility && !mVisible
1124                                         && (visibleChanged || lifecycleNewlyRespectsVisibility))) {
1125                             mSurfaceCreated = false;
1126                             notifySurfaceDestroyed();
1127                         }
1128                     }
1129 
1130                     copySurface(creating /* surfaceControlCreated */, sizeChanged);
1131 
1132                     if (surfaceShouldExist() && mSurface.isValid()) {
1133                         if (!mSurfaceCreated
1134                                 && (surfaceChanged || (respectVisibility && visibleChanged))) {
1135                             mSurfaceCreated = true;
1136                             mIsCreating = true;
1137                             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1138                                     + "visibleChanged -- surfaceCreated");
1139                             callbacks = getSurfaceCallbacks();
1140                             for (SurfaceHolder.Callback c : callbacks) {
1141                                 c.surfaceCreated(mSurfaceHolder);
1142                             }
1143                         }
1144                         if (creating || formatChanged || sizeChanged || hintChanged
1145                                 || (respectVisibility && visibleChanged) || realSizeChanged) {
1146                             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1147                                     + "surfaceChanged -- format=" + mFormat
1148                                     + " w=" + myWidth + " h=" + myHeight);
1149                             if (callbacks == null) {
1150                                 callbacks = getSurfaceCallbacks();
1151                             }
1152                             for (SurfaceHolder.Callback c : callbacks) {
1153                                 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
1154                             }
1155                         }
1156                         if (redrawNeeded) {
1157                             if (DEBUG) {
1158                                 Log.i(TAG, System.identityHashCode(this) + " surfaceRedrawNeeded");
1159                             }
1160                             if (callbacks == null) {
1161                                 callbacks = getSurfaceCallbacks();
1162                             }
1163 
1164                             if (shouldSyncBuffer) {
1165                                 handleSyncBufferCallback(callbacks, syncBufferTransactionCallback);
1166                             } else {
1167                                 handleSyncNoBuffer(callbacks);
1168                             }
1169                         }
1170                     }
1171                 } finally {
1172                     mIsCreating = false;
1173                     if (mSurfaceControl != null && !mSurfaceCreated) {
1174                         releaseSurfaces(false /* releaseSurfacePackage*/);
1175                     }
1176                 }
1177             } catch (Exception ex) {
1178                 Log.e(TAG, "Exception configuring surface", ex);
1179             }
1180             if (DEBUG) Log.v(
1181                 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
1182                 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
1183                 + ", frame=" + mSurfaceFrame);
1184         }
1185     }
1186 
1187     /**
1188      * @hide
1189      */
getName()1190     public String getName() {
1191         ViewRootImpl viewRoot = getViewRootImpl();
1192         String viewRootName = viewRoot == null ? "detached" : viewRoot.getTitle().toString();
1193         return "SurfaceView[" + viewRootName + "]";
1194     }
1195 
1196     /**
1197      * If SV is trying to be part of the VRI sync, we need to add SV to the VRI sync before
1198      * invoking the redrawNeeded call to the owner. This is to ensure we can set up the SV in
1199      * the sync before the SV owner knows it needs to draw a new frame.
1200      * Once the redrawNeeded callback is invoked, we can stop the continuous sync transaction
1201      * call which will invoke the syncTransaction callback that contains the buffer. The
1202      * code waits until we can retrieve the transaction that contains the buffer before
1203      * notifying the syncer that the buffer is ready.
1204      */
handleSyncBufferCallback(SurfaceHolder.Callback[] callbacks, SyncBufferTransactionCallback syncBufferTransactionCallback)1205     private void handleSyncBufferCallback(SurfaceHolder.Callback[] callbacks,
1206             SyncBufferTransactionCallback syncBufferTransactionCallback) {
1207 
1208         final SurfaceSyncGroup surfaceSyncGroup = new SurfaceSyncGroup(getName());
1209         getViewRootImpl().addToSync(surfaceSyncGroup);
1210         redrawNeededAsync(callbacks, () -> {
1211             Transaction t = null;
1212             if (mBlastBufferQueue != null) {
1213                 mBlastBufferQueue.stopContinuousSyncTransaction();
1214                 t = syncBufferTransactionCallback.waitForTransaction();
1215             }
1216 
1217             surfaceSyncGroup.addTransaction(t);
1218             surfaceSyncGroup.markSyncReady();
1219             onDrawFinished();
1220         });
1221     }
1222 
handleSyncNoBuffer(SurfaceHolder.Callback[] callbacks)1223     private void handleSyncNoBuffer(SurfaceHolder.Callback[] callbacks) {
1224         final SurfaceSyncGroup surfaceSyncGroup = new SurfaceSyncGroup(getName());
1225         synchronized (mSyncGroups) {
1226             mSyncGroups.add(surfaceSyncGroup);
1227         }
1228 
1229         redrawNeededAsync(callbacks, () -> {
1230             synchronized (mSyncGroups) {
1231                 mSyncGroups.remove(surfaceSyncGroup);
1232             }
1233             surfaceSyncGroup.markSyncReady();
1234             onDrawFinished();
1235         });
1236 
1237     }
1238 
redrawNeededAsync(SurfaceHolder.Callback[] callbacks, Runnable callbacksCollected)1239     private void redrawNeededAsync(SurfaceHolder.Callback[] callbacks,
1240             Runnable callbacksCollected) {
1241         SurfaceCallbackHelper sch = new SurfaceCallbackHelper(callbacksCollected);
1242         sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
1243     }
1244 
1245     /**
1246      * @hide
1247      */
1248     @Override
vriDrawStarted(boolean isWmSync)1249     public void vriDrawStarted(boolean isWmSync) {
1250         ViewRootImpl viewRoot = getViewRootImpl();
1251         synchronized (mSyncGroups) {
1252             if (isWmSync && viewRoot != null) {
1253                 for (SurfaceSyncGroup syncGroup : mSyncGroups) {
1254                     viewRoot.addToSync(syncGroup);
1255                 }
1256             }
1257             mSyncGroups.clear();
1258         }
1259     }
1260 
1261     private static class SyncBufferTransactionCallback {
1262         private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
1263         private Transaction mTransaction;
1264 
waitForTransaction()1265         Transaction waitForTransaction() {
1266             try {
1267                 mCountDownLatch.await();
1268             } catch (InterruptedException e) {
1269             }
1270             return mTransaction;
1271         }
1272 
onTransactionReady(Transaction t)1273         void onTransactionReady(Transaction t) {
1274             mTransaction = t;
1275             mCountDownLatch.countDown();
1276         }
1277     }
1278 
1279     /**
1280      * Copy the Surface from the SurfaceControl or the blast adapter.
1281      *
1282      * @param surfaceControlCreated true if we created the SurfaceControl and need to update our
1283      *                              Surface if needed.
1284      * @param bufferSizeChanged true if the BufferSize has changed and we need to recreate the
1285      *                          Surface for compatibility reasons.
1286      */
copySurface(boolean surfaceControlCreated, boolean bufferSizeChanged)1287     private void copySurface(boolean surfaceControlCreated, boolean bufferSizeChanged) {
1288         if (surfaceControlCreated) {
1289             mSurface.copyFrom(mBlastBufferQueue);
1290         }
1291 
1292         if (bufferSizeChanged && getContext().getApplicationInfo().targetSdkVersion
1293                 < Build.VERSION_CODES.O) {
1294             // Some legacy applications use the underlying native {@link Surface} object
1295             // as a key to whether anything has changed. In these cases, updates to the
1296             // existing {@link Surface} will be ignored when the size changes.
1297             // Therefore, we must explicitly recreate the {@link Surface} in these
1298             // cases.
1299             if (mBlastBufferQueue != null) {
1300                 mSurface.transferFrom(mBlastBufferQueue.createSurfaceWithHandle());
1301             }
1302         }
1303     }
1304 
setBufferSize(Transaction transaction)1305     private void setBufferSize(Transaction transaction) {
1306         mBlastSurfaceControl.setTransformHint(mTransformHint);
1307         if (mBlastBufferQueue != null) {
1308             mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight,
1309                         mFormat);
1310         }
1311     }
1312 
1313 
1314     /**
1315      * Creates the surface control hierarchy as follows
1316      *   ViewRootImpl surface
1317      *     bounds layer (crops all child surfaces to parent surface insets)
1318      *       * SurfaceView surface (drawn relative to ViewRootImpl surface)
1319      *           * Blast surface (if enabled)
1320      *       * Background color layer (drawn behind all SurfaceView surfaces)
1321      *
1322      *  The bounds layer is used to crop the surface view so it does not draw into the parent
1323      *  surface inset region. Since there can be multiple surface views below or above the parent
1324      *  surface, one option is to create multiple bounds layer for each z order. The other option,
1325      *  the one implement is to create a single bounds layer and set z order for each child surface
1326      *  relative to the parent surface.
1327      *  When creating the surface view, we parent it to the bounds layer and then set the relative z
1328      *  order. When the parent surface changes, we have to make sure to update the relative z via
1329      *  ViewRootImpl.SurfaceChangedCallback.
1330      *
1331      *  We don't recreate the surface controls but only recreate the adapter. Since the blast layer
1332      *  is still alive, the old buffers will continue to be presented until replaced by buffers from
1333      *  the new adapter. This means we do not need to track the old surface control and destroy it
1334      *  after the client has drawn to avoid any flickers.
1335      *
1336      */
createBlastSurfaceControls(ViewRootImpl viewRoot, String name, Transaction surfaceUpdateTransaction)1337     private void createBlastSurfaceControls(ViewRootImpl viewRoot, String name,
1338             Transaction surfaceUpdateTransaction) {
1339         if (mSurfaceControl == null) {
1340             mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
1341                     .setName(name)
1342                     .setLocalOwnerView(this)
1343                     .setParent(viewRoot.updateAndGetBoundsLayer(surfaceUpdateTransaction))
1344                     .setCallsite("SurfaceView.updateSurface")
1345                     .setContainerLayer()
1346                     .build();
1347         }
1348 
1349         if (mBlastSurfaceControl == null) {
1350             mBlastSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
1351                     .setName(name + "(BLAST)")
1352                     .setLocalOwnerView(this)
1353                     .setParent(mSurfaceControl)
1354                     .setFlags(mSurfaceFlags)
1355                     .setHidden(false)
1356                     .setBLASTLayer()
1357                     .setCallsite("SurfaceView.updateSurface")
1358                     .build();
1359         } else {
1360             // update blast layer
1361             surfaceUpdateTransaction
1362                     .setOpaque(mBlastSurfaceControl, (mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
1363                     .setSecure(mBlastSurfaceControl, (mSurfaceFlags & SurfaceControl.SECURE) != 0)
1364                     .show(mBlastSurfaceControl);
1365         }
1366 
1367         if (mBackgroundControl == null) {
1368             mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
1369                     .setName("Background for " + name)
1370                     .setLocalOwnerView(this)
1371                     .setOpaque(true)
1372                     .setColorLayer()
1373                     .setParent(mSurfaceControl)
1374                     .setCallsite("SurfaceView.updateSurface")
1375                     .build();
1376         }
1377 
1378         // Always recreate the IGBP for compatibility. This can be optimized in the future but
1379         // the behavior change will need to be gated by SDK version.
1380         if (mBlastBufferQueue != null) {
1381             mBlastBufferQueue.destroy();
1382         }
1383         mTransformHint = viewRoot.getBufferTransformHint();
1384         mBlastSurfaceControl.setTransformHint(mTransformHint);
1385 
1386         mBlastBufferQueue = new BLASTBufferQueue(name, false /* updateDestinationFrame */);
1387         mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat);
1388         mBlastBufferQueue.setTransactionHangCallback(ViewRootImpl.sTransactionHangCallback);
1389     }
1390 
onDrawFinished()1391     private void onDrawFinished() {
1392         if (DEBUG) {
1393             Log.i(TAG, System.identityHashCode(this) + " "
1394                     + "finishedDrawing");
1395         }
1396 
1397         runOnUiThread(this::performDrawFinished);
1398     }
1399 
1400     /**
1401      * Sets the surface position and scale. Can be called on
1402      * the UI thread as well as on the renderer thread.
1403      *
1404      * @param transaction Transaction in which to execute.
1405      * @param surface Surface whose location to set.
1406      * @param positionLeft The left position to set.
1407      * @param positionTop The top position to set.
1408      * @param postScaleX The X axis post scale
1409      * @param postScaleY The Y axis post scale
1410      *
1411      * @hide
1412      */
onSetSurfacePositionAndScale(@onNull Transaction transaction, @NonNull SurfaceControl surface, int positionLeft, int positionTop, float postScaleX, float postScaleY)1413     protected void onSetSurfacePositionAndScale(@NonNull Transaction transaction,
1414             @NonNull SurfaceControl surface, int positionLeft, int positionTop,
1415             float postScaleX, float postScaleY) {
1416         transaction.setPosition(surface, positionLeft, positionTop);
1417         transaction.setMatrix(surface, postScaleX /*dsdx*/, 0f /*dtdx*/,
1418                 0f /*dtdy*/, postScaleY /*dsdy*/);
1419     }
1420 
1421     /** @hide */
requestUpdateSurfacePositionAndScale()1422     public void requestUpdateSurfacePositionAndScale() {
1423         if (mSurfaceControl == null) {
1424             return;
1425         }
1426         final Transaction transaction = new Transaction();
1427         onSetSurfacePositionAndScale(transaction, mSurfaceControl,
1428                 mScreenRect.left, /*positionLeft*/
1429                 mScreenRect.top/*positionTop*/ ,
1430                 mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
1431                 mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
1432         applyTransactionOnVriDraw(transaction);
1433         invalidate();
1434     }
1435 
1436     /**
1437      * @return The last render position of the backing surface or an empty rect.
1438      *
1439      * @hide
1440      */
getSurfaceRenderPosition()1441     public @NonNull Rect getSurfaceRenderPosition() {
1442         return mRTLastReportedPosition;
1443     }
1444 
applyOrMergeTransaction(Transaction t, long frameNumber)1445     private void applyOrMergeTransaction(Transaction t, long frameNumber) {
1446         final ViewRootImpl viewRoot = getViewRootImpl();
1447         if (viewRoot != null) {
1448             // If we are using BLAST, merge the transaction with the viewroot buffer transaction.
1449             viewRoot.mergeWithNextTransaction(t, frameNumber);
1450         } else {
1451             t.apply();
1452         }
1453     }
1454 
1455     private final Rect mRTLastReportedPosition = new Rect();
1456 
1457     private class SurfaceViewPositionUpdateListener implements RenderNode.PositionUpdateListener {
1458         private final int mRtSurfaceWidth;
1459         private final int mRtSurfaceHeight;
1460         private final SurfaceControl.Transaction mPositionChangedTransaction =
1461                 new SurfaceControl.Transaction();
1462 
SurfaceViewPositionUpdateListener(int surfaceWidth, int surfaceHeight)1463         SurfaceViewPositionUpdateListener(int surfaceWidth, int surfaceHeight) {
1464             mRtSurfaceWidth = surfaceWidth;
1465             mRtSurfaceHeight = surfaceHeight;
1466         }
1467 
1468         @Override
positionChanged(long frameNumber, int left, int top, int right, int bottom)1469         public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
1470             try {
1471                 if (DEBUG_POSITION) {
1472                     Log.d(TAG, String.format(
1473                             "%d updateSurfacePosition RenderWorker, frameNr = %d, "
1474                                     + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
1475                             System.identityHashCode(SurfaceView.this), frameNumber,
1476                             left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight));
1477                 }
1478                 synchronized (mSurfaceControlLock) {
1479                     if (mSurfaceControl == null) return;
1480 
1481                     mRTLastReportedPosition.set(left, top, right, bottom);
1482                     onSetSurfacePositionAndScale(mPositionChangedTransaction, mSurfaceControl,
1483                             mRTLastReportedPosition.left /*positionLeft*/,
1484                             mRTLastReportedPosition.top /*positionTop*/,
1485                             mRTLastReportedPosition.width()
1486                                     / (float) mRtSurfaceWidth /*postScaleX*/,
1487                             mRTLastReportedPosition.height()
1488                                     / (float) mRtSurfaceHeight /*postScaleY*/);
1489 
1490                     mPositionChangedTransaction.show(mSurfaceControl);
1491                 }
1492                 applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
1493             } catch (Exception ex) {
1494                 Log.e(TAG, "Exception from repositionChild", ex);
1495             }
1496         }
1497 
1498         @Override
applyStretch(long frameNumber, float width, float height, float vecX, float vecY, float maxStretchX, float maxStretchY, float childRelativeLeft, float childRelativeTop, float childRelativeRight, float childRelativeBottom)1499         public void applyStretch(long frameNumber, float width, float height,
1500                 float vecX, float vecY, float maxStretchX, float maxStretchY,
1501                 float childRelativeLeft, float childRelativeTop, float childRelativeRight,
1502                 float childRelativeBottom) {
1503             mRtTransaction.setStretchEffect(mSurfaceControl, width, height, vecX, vecY,
1504                     maxStretchX, maxStretchY, childRelativeLeft, childRelativeTop,
1505                     childRelativeRight, childRelativeBottom);
1506             applyOrMergeTransaction(mRtTransaction, frameNumber);
1507         }
1508 
1509         @Override
positionLost(long frameNumber)1510         public void positionLost(long frameNumber) {
1511             if (DEBUG_POSITION) {
1512                 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
1513                         System.identityHashCode(this), frameNumber));
1514             }
1515             mRTLastReportedPosition.setEmpty();
1516 
1517             // positionLost can be called while UI thread is un-paused.
1518             synchronized (mSurfaceControlLock) {
1519                 if (mSurfaceControl == null) return;
1520                 // b/131239825
1521                 mRtTransaction.hide(mSurfaceControl);
1522                 applyOrMergeTransaction(mRtTransaction, frameNumber);
1523             }
1524         }
1525     }
1526 
1527     private SurfaceViewPositionUpdateListener mPositionListener = null;
1528 
getSurfaceCallbacks()1529     private SurfaceHolder.Callback[] getSurfaceCallbacks() {
1530         SurfaceHolder.Callback[] callbacks;
1531         synchronized (mCallbacks) {
1532             callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
1533             mCallbacks.toArray(callbacks);
1534         }
1535         return callbacks;
1536     }
1537 
runOnUiThread(Runnable runnable)1538     private void runOnUiThread(Runnable runnable) {
1539         Handler handler = getHandler();
1540         if (handler != null && handler.getLooper() != Looper.myLooper()) {
1541             handler.post(runnable);
1542         } else {
1543             runnable.run();
1544         }
1545     }
1546 
1547     /**
1548      * Check to see if the surface has fixed size dimensions or if the surface's
1549      * dimensions are dimensions are dependent on its current layout.
1550      *
1551      * @return true if the surface has dimensions that are fixed in size
1552      * @hide
1553      */
1554     @UnsupportedAppUsage(
1555             maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
1556             publicAlternatives = "Track {@link SurfaceHolder#setFixedSize} instead")
isFixedSize()1557     public boolean isFixedSize() {
1558         return (mRequestedWidth != -1 || mRequestedHeight != -1);
1559     }
1560 
isAboveParent()1561     private boolean isAboveParent() {
1562         return mSubLayer >= 0;
1563     }
1564 
1565     /**
1566      * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
1567      * and size of the content hasn't updated yet. This color will fill the expanded area when the
1568      * view becomes larger.
1569      * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
1570      * @hide
1571      */
setResizeBackgroundColor(int bgColor)1572     public void setResizeBackgroundColor(int bgColor) {
1573         final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
1574         setResizeBackgroundColor(transaction, bgColor);
1575         applyTransactionOnVriDraw(transaction);
1576         invalidate();
1577     }
1578 
1579     /**
1580      * Version of {@link #setResizeBackgroundColor(int)} that allows you to provide
1581      * {@link SurfaceControl.Transaction}.
1582      * @hide
1583      */
setResizeBackgroundColor(@onNull SurfaceControl.Transaction t, int bgColor)1584     public void setResizeBackgroundColor(@NonNull SurfaceControl.Transaction t, int bgColor) {
1585         if (mBackgroundControl == null) {
1586             return;
1587         }
1588         mBackgroundColor = bgColor;
1589         updateBackgroundColor(t);
1590     }
1591 
1592     @UnsupportedAppUsage(
1593             maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
1594             publicAlternatives = "Use {@link SurfaceView#getHolder} instead")
1595     private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
1596         private static final String LOG_TAG = "SurfaceHolder";
1597 
1598         @Override
1599         public boolean isCreating() {
1600             return mIsCreating;
1601         }
1602 
1603         @Override
1604         public void addCallback(Callback callback) {
1605             synchronized (mCallbacks) {
1606                 // This is a linear search, but in practice we'll
1607                 // have only a couple callbacks, so it doesn't matter.
1608                 if (!mCallbacks.contains(callback)) {
1609                     mCallbacks.add(callback);
1610                 }
1611             }
1612         }
1613 
1614         @Override
1615         public void removeCallback(Callback callback) {
1616             synchronized (mCallbacks) {
1617                 mCallbacks.remove(callback);
1618             }
1619         }
1620 
1621         @Override
1622         public void setFixedSize(int width, int height) {
1623             if (mRequestedWidth != width || mRequestedHeight != height) {
1624                 if (DEBUG_POSITION) {
1625                     Log.d(TAG, String.format("%d setFixedSize %dx%d -> %dx%d",
1626                             System.identityHashCode(this), mRequestedWidth, mRequestedHeight, width,
1627                                     height));
1628                 }
1629                 mRequestedWidth = width;
1630                 mRequestedHeight = height;
1631                 requestLayout();
1632             }
1633         }
1634 
1635         @Override
1636         public void setSizeFromLayout() {
1637             if (mRequestedWidth != -1 || mRequestedHeight != -1) {
1638                 if (DEBUG_POSITION) {
1639                     Log.d(TAG, String.format("%d setSizeFromLayout was %dx%d",
1640                             System.identityHashCode(this), mRequestedWidth, mRequestedHeight));
1641                 }
1642                 mRequestedWidth = mRequestedHeight = -1;
1643                 requestLayout();
1644             }
1645         }
1646 
1647         @Override
1648         public void setFormat(int format) {
1649             // for backward compatibility reason, OPAQUE always
1650             // means 565 for SurfaceView
1651             if (format == PixelFormat.OPAQUE)
1652                 format = PixelFormat.RGB_565;
1653 
1654             mRequestedFormat = format;
1655             if (mSurfaceControl != null) {
1656                 updateSurface();
1657             }
1658         }
1659 
1660         /**
1661          * @deprecated setType is now ignored.
1662          */
1663         @Override
1664         @Deprecated
1665         public void setType(int type) { }
1666 
1667         @Override
1668         public void setKeepScreenOn(boolean screenOn) {
1669             runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
1670         }
1671 
1672         /**
1673          * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1674          *
1675          * After drawing into the provided {@link Canvas}, the caller must
1676          * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1677          *
1678          * The caller must redraw the entire surface.
1679          * @return A canvas for drawing into the surface.
1680          */
1681         @Override
1682         public Canvas lockCanvas() {
1683             return internalLockCanvas(null, false);
1684         }
1685 
1686         /**
1687          * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1688          *
1689          * After drawing into the provided {@link Canvas}, the caller must
1690          * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1691          *
1692          * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1693          * to redraw.  This function may choose to expand the dirty rectangle if for example
1694          * the surface has been resized or if the previous contents of the surface were
1695          * not available.  The caller must redraw the entire dirty region as represented
1696          * by the contents of the inOutDirty rectangle upon return from this function.
1697          * The caller may also pass <code>null</code> instead, in the case where the
1698          * entire surface should be redrawn.
1699          * @return A canvas for drawing into the surface.
1700          */
1701         @Override
1702         public Canvas lockCanvas(Rect inOutDirty) {
1703             return internalLockCanvas(inOutDirty, false);
1704         }
1705 
1706         @Override
1707         public Canvas lockHardwareCanvas() {
1708             return internalLockCanvas(null, true);
1709         }
1710 
1711         private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
1712             mSurfaceLock.lock();
1713 
1714             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
1715                     + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
1716 
1717             Canvas c = null;
1718             if (!mDrawingStopped && mSurfaceControl != null) {
1719                 try {
1720                     if (hardware) {
1721                         c = mSurface.lockHardwareCanvas();
1722                     } else {
1723                         c = mSurface.lockCanvas(dirty);
1724                     }
1725                 } catch (Exception e) {
1726                     Log.e(LOG_TAG, "Exception locking surface", e);
1727                 }
1728             }
1729 
1730             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
1731             if (c != null) {
1732                 mLastLockTime = SystemClock.uptimeMillis();
1733                 return c;
1734             }
1735 
1736             // If the Surface is not ready to be drawn, then return null,
1737             // but throttle calls to this function so it isn't called more
1738             // than every 100ms.
1739             long now = SystemClock.uptimeMillis();
1740             long nextTime = mLastLockTime + 100;
1741             if (nextTime > now) {
1742                 try {
1743                     Thread.sleep(nextTime-now);
1744                 } catch (InterruptedException e) {
1745                 }
1746                 now = SystemClock.uptimeMillis();
1747             }
1748             mLastLockTime = now;
1749             mSurfaceLock.unlock();
1750 
1751             return null;
1752         }
1753 
1754         /**
1755          * Posts the new contents of the {@link Canvas} to the surface and
1756          * releases the {@link Canvas}.
1757          *
1758          * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1759          */
1760         @Override
1761         public void unlockCanvasAndPost(Canvas canvas) {
1762             try {
1763                 mSurface.unlockCanvasAndPost(canvas);
1764             } finally {
1765                 mSurfaceLock.unlock();
1766             }
1767         }
1768 
1769         @Override
1770         public Surface getSurface() {
1771             return mSurface;
1772         }
1773 
1774         @Override
1775         public Rect getSurfaceFrame() {
1776             return mSurfaceFrame;
1777         }
1778     };
1779 
1780     /**
1781      * Return a SurfaceControl which can be used for parenting Surfaces to this SurfaceView.
1782      *
1783      * Note that this SurfaceControl is effectively read-only. Its only well-defined usage is in
1784      * using the SurfaceControl as a parent for an application's hierarchy of SurfaceControls. All
1785      * other properties of the SurfaceControl, such as its position, may be mutated by the
1786      * SurfaceView at any time which will override what the application is requesting. Do not apply
1787      * any {@link SurfaceControl.Transaction} to this SurfaceControl except for reparenting
1788      * child SurfaceControls. See: {@link SurfaceControl.Transaction#reparent}.
1789      *
1790      * @return The SurfaceControl for this SurfaceView.
1791      */
getSurfaceControl()1792     public SurfaceControl getSurfaceControl() {
1793         return mSurfaceControl;
1794     }
1795 
1796     /**
1797      * A token used for constructing {@link SurfaceControlViewHost}. This token should
1798      * be passed from the host process to the client process.
1799      *
1800      * @return The token
1801      */
getHostToken()1802     public @Nullable IBinder getHostToken() {
1803         final ViewRootImpl viewRoot = getViewRootImpl();
1804         if (viewRoot == null) {
1805             return null;
1806         }
1807         return viewRoot.getInputToken();
1808     }
1809 
1810     /**
1811      * Set window stopped to false and update surface visibility when ViewRootImpl surface is
1812      * created.
1813      * @hide
1814      */
1815     @Override
surfaceCreated(SurfaceControl.Transaction t)1816     public void surfaceCreated(SurfaceControl.Transaction t) {
1817         setWindowStopped(false);
1818     }
1819 
1820     /**
1821      * Set window stopped to true and update surface visibility when ViewRootImpl surface is
1822      * destroyed.
1823      * @hide
1824      */
1825     @Override
surfaceDestroyed()1826     public void surfaceDestroyed() {
1827         setWindowStopped(true);
1828         mRemoteAccessibilityController.disassosciateHierarchy();
1829     }
1830 
1831     /**
1832      * Called when a valid ViewRootImpl surface is replaced by another valid surface. In this
1833      * case update relative z to the new parent surface.
1834      * @hide
1835      */
1836     @Override
surfaceReplaced(Transaction t)1837     public void surfaceReplaced(Transaction t) {
1838         if (mSurfaceControl != null && mBackgroundControl != null) {
1839             updateRelativeZ(t);
1840         }
1841     }
1842 
updateRelativeZ(Transaction t)1843     private void updateRelativeZ(Transaction t) {
1844         final ViewRootImpl viewRoot = getViewRootImpl();
1845         if (viewRoot == null) {
1846             // We were just detached.
1847             return;
1848         }
1849         final SurfaceControl viewRootControl = viewRoot.getSurfaceControl();
1850         t.setRelativeLayer(mBackgroundControl, viewRootControl, Integer.MIN_VALUE);
1851         t.setRelativeLayer(mSurfaceControl, viewRootControl, mSubLayer);
1852     }
1853 
1854     /**
1855      * Display the view-hierarchy embedded within a {@link SurfaceControlViewHost.SurfacePackage}
1856      * within this SurfaceView.
1857      *
1858      * This can be called independently of the SurfaceView lifetime callbacks. SurfaceView
1859      * will internally manage reparenting the package to our Surface as it is created
1860      * and destroyed.
1861      *
1862      * If this SurfaceView is above its host Surface (see
1863      * {@link #setZOrderOnTop} then the embedded Surface hierarchy will be able to receive
1864      * input.
1865      *
1866      * This will take ownership of the SurfaceControl contained inside the SurfacePackage
1867      * and free the caller of the obligation to call
1868      * {@link SurfaceControlViewHost.SurfacePackage#release}. However, note that
1869      * {@link SurfaceControlViewHost.SurfacePackage#release} and
1870      * {@link SurfaceControlViewHost#release} are not the same. While the ownership
1871      * of this particular {@link SurfaceControlViewHost.SurfacePackage} will be taken by the
1872      * SurfaceView the underlying {@link SurfaceControlViewHost} remains managed by it's original
1873      * remote-owner.
1874      *
1875      * @param p The SurfacePackage to embed.
1876      */
setChildSurfacePackage(@onNull SurfaceControlViewHost.SurfacePackage p)1877     public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
1878         final SurfaceControl lastSc = mSurfacePackage != null ?
1879                 mSurfacePackage.getSurfaceControl() : null;
1880         final SurfaceControl.Transaction transaction = new Transaction();
1881         if (mSurfaceControl != null) {
1882             if (lastSc != null) {
1883                 transaction.reparent(lastSc, null);
1884                 mSurfacePackage.release();
1885             }
1886             reparentSurfacePackage(transaction, p);
1887             applyTransactionOnVriDraw(transaction);
1888         }
1889         mSurfacePackage = p;
1890         try {
1891             mSurfacePackage.getRemoteInterface().attachParentInterface(
1892                     mSurfaceControlViewHostParent);
1893         } catch (RemoteException e) {
1894             Log.d(TAG, "Failed to attach parent interface to SCVH. Likely SCVH is already dead.");
1895         }
1896 
1897         if (isFocused()) {
1898             requestEmbeddedFocus(true);
1899         }
1900         invalidate();
1901     }
1902 
reparentSurfacePackage(SurfaceControl.Transaction t, SurfaceControlViewHost.SurfacePackage p)1903     private void reparentSurfacePackage(SurfaceControl.Transaction t,
1904             SurfaceControlViewHost.SurfacePackage p) {
1905         final SurfaceControl sc = p.getSurfaceControl();
1906         if (sc == null || !sc.isValid()) {
1907             return;
1908         }
1909         initEmbeddedHierarchyForAccessibility(p);
1910         t.reparent(sc, mBlastSurfaceControl).show(sc);
1911     }
1912 
1913     /** @hide */
1914     @Override
onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info)1915     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1916         super.onInitializeAccessibilityNodeInfoInternal(info);
1917         if (!mRemoteAccessibilityController.connected()) {
1918             return;
1919         }
1920         // Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
1921         // leashed child would return the root node in the embedded hierarchy
1922         info.addChild(mRemoteAccessibilityController.getLeashToken());
1923     }
1924 
1925     @Override
getImportantForAccessibility()1926     public int getImportantForAccessibility() {
1927         final int mode = super.getImportantForAccessibility();
1928         // If developers explicitly set the important mode for it, don't change the mode.
1929         // Only change the mode to important when this SurfaceView isn't explicitly set and has
1930         // an embedded hierarchy.
1931         if ((mRemoteAccessibilityController!= null && !mRemoteAccessibilityController.connected())
1932                 || mode != IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
1933             return mode;
1934         }
1935         return IMPORTANT_FOR_ACCESSIBILITY_YES;
1936     }
1937 
initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p)1938     private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
1939         final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
1940         if (mRemoteAccessibilityController.alreadyAssociated(connection)) {
1941             return;
1942         }
1943         mRemoteAccessibilityController.assosciateHierarchy(connection,
1944             getViewRootImpl().mLeashToken, getAccessibilityViewId());
1945 
1946         updateEmbeddedAccessibilityMatrix(true);
1947     }
1948 
notifySurfaceDestroyed()1949     private void notifySurfaceDestroyed() {
1950         if (mSurface.isValid()) {
1951             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1952                     + "surfaceDestroyed");
1953             SurfaceHolder.Callback[] callbacks = getSurfaceCallbacks();
1954             for (SurfaceHolder.Callback c : callbacks) {
1955                 c.surfaceDestroyed(mSurfaceHolder);
1956             }
1957             // Since Android N the same surface may be reused and given to us
1958             // again by the system server at a later point. However
1959             // as we didn't do this in previous releases, clients weren't
1960             // necessarily required to clean up properly in
1961             // surfaceDestroyed. This leads to problems for example when
1962             // clients don't destroy their EGL context, and try
1963             // and create a new one on the same surface following reuse.
1964             // Since there is no valid use of the surface in-between
1965             // surfaceDestroyed and surfaceCreated, we force a disconnect,
1966             // so the next connect will always work if we end up reusing
1967             // the surface.
1968             if (mSurface.isValid()) {
1969                 mSurface.forceScopedDisconnect();
1970             }
1971         }
1972     }
1973 
updateEmbeddedAccessibilityMatrix(boolean force)1974     void updateEmbeddedAccessibilityMatrix(boolean force) {
1975         if (!mRemoteAccessibilityController.connected()) {
1976             return;
1977         }
1978         getBoundsOnScreen(mTmpRect);
1979 
1980         // To compute the node bounds of the node on the embedded window,
1981         // apply this matrix to get the bounds in host window-relative coordinates,
1982         // then using the global transform to get the actual bounds on screen.
1983         mTmpRect.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
1984         mTmpMatrix.reset();
1985         mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
1986         mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
1987                 mScreenRect.height() / (float) mSurfaceHeight);
1988         mRemoteAccessibilityController.setWindowMatrix(mTmpMatrix, force);
1989     }
1990 
1991     @Override
onFocusChanged(boolean gainFocus, @FocusDirection int direction, @Nullable Rect previouslyFocusedRect)1992     protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
1993             @Nullable Rect previouslyFocusedRect) {
1994         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
1995         requestEmbeddedFocus(gainFocus);
1996     }
1997 
requestEmbeddedFocus(boolean gainFocus)1998     private void requestEmbeddedFocus(boolean gainFocus) {
1999         final ViewRootImpl viewRoot = getViewRootImpl();
2000         if (mSurfacePackage == null || viewRoot == null) {
2001             return;
2002         }
2003         try {
2004             viewRoot.mWindowSession.grantEmbeddedWindowFocus(viewRoot.mWindow,
2005                     mSurfacePackage.getInputToken(), gainFocus);
2006         } catch (Exception e) {
2007             Log.e(TAG, System.identityHashCode(this)
2008                     + "Exception requesting focus on embedded window", e);
2009         }
2010     }
2011 
applyTransactionOnVriDraw(Transaction t)2012     private void applyTransactionOnVriDraw(Transaction t) {
2013         final ViewRootImpl viewRoot = getViewRootImpl();
2014         if (viewRoot != null) {
2015             // If we are using BLAST, merge the transaction with the viewroot buffer transaction.
2016             viewRoot.applyTransactionOnDraw(t);
2017         } else {
2018             t.apply();
2019         }
2020     }
2021 
2022     /**
2023      * @hide
2024      */
syncNextFrame(Consumer<Transaction> t)2025     public void syncNextFrame(Consumer<Transaction> t) {
2026         mBlastBufferQueue.syncNextTransaction(t);
2027     }
2028 
2029     /**
2030      * Adds a transaction that would be applied synchronously with displaying the SurfaceView's next
2031      * frame.
2032      *
2033      * Note that the exact frame that the transaction is applied with is only well-defined when
2034      * SurfaceView rendering is paused prior to calling applyTransactionToFrame(), so that the
2035      * transaction is applied with the next frame rendered after applyTransactionToFrame() is
2036      * called. If frames are continuously rendering to the SurfaceView when
2037      * applyTransactionToFrame() is called, then it is undefined which frame the transaction is
2038      * applied with. It is also possible for the transaction to not be applied if no new frames are
2039      * rendered to the SurfaceView after this is called.
2040      *
2041      * @param transaction The transaction to apply. The system takes ownership of the transaction
2042      *                    and promises to eventually apply the transaction.
2043      * @throws IllegalStateException if the underlying Surface does not exist (and therefore
2044      *         there is no next frame).
2045      */
applyTransactionToFrame(@onNull SurfaceControl.Transaction transaction)2046     public void applyTransactionToFrame(@NonNull SurfaceControl.Transaction transaction) {
2047         synchronized (mSurfaceControlLock) {
2048             if (mBlastBufferQueue == null) {
2049                 throw new IllegalStateException("Surface does not exist!");
2050             }
2051 
2052             long frameNumber = mBlastBufferQueue.getLastAcquiredFrameNum() + 1;
2053             mBlastBufferQueue.mergeWithNextTransaction(transaction, frameNumber);
2054         }
2055     }
2056 
2057     @Override
performCollectViewAttributes(AttachInfo attachInfo, int visibility)2058     void performCollectViewAttributes(AttachInfo attachInfo, int visibility) {
2059         super.performCollectViewAttributes(attachInfo, visibility);
2060         if (mEmbeddedWindowParams.isEmpty()) {
2061             return;
2062         }
2063 
2064         for (WindowManager.LayoutParams embeddedWindowAttr : mEmbeddedWindowParams) {
2065             if ((embeddedWindowAttr.flags & FLAG_KEEP_SCREEN_ON) == FLAG_KEEP_SCREEN_ON) {
2066                 attachInfo.mKeepScreenOn = true;
2067                 break;
2068             }
2069         }
2070     }
2071 }
2072