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