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