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