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