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