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