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