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