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