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