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