blob: 5566e0e4292eea18a7495694ad7eda83f4ffbdb0 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
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
17package android.view;
18
Adrian Roose99bc052017-11-20 17:55:31 +010019import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
20import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
21import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
Robert Carrd5c7dd62017-03-08 10:39:30 -080022
Robert Carr30ad6182019-12-18 01:46:04 -080023import android.annotation.NonNull;
Vishnu Nair5cf253192019-11-07 15:33:20 -080024import android.annotation.Nullable;
Artur Satayevad9254c2019-12-10 17:47:54 +000025import android.compat.annotation.UnsupportedAppUsage;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070026import android.content.Context;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070027import android.content.res.CompatibilityInfo.Translator;
Mark Renouf34d04f32019-05-13 15:53:18 -040028import android.graphics.BlendMode;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070029import android.graphics.Canvas;
Andrii Kuliancf8f6832018-01-23 19:43:30 -080030import android.graphics.Color;
Jackal Guoac234d62020-02-03 15:05:43 +080031import android.graphics.Matrix;
Mark Renouf34d04f32019-05-13 15:53:18 -040032import android.graphics.Paint;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070033import android.graphics.PixelFormat;
34import android.graphics.PorterDuff;
35import android.graphics.Rect;
36import android.graphics.Region;
John Reck32f140aa62018-10-04 15:08:24 -070037import android.graphics.RenderNode;
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070038import android.os.Build;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070039import android.os.Handler;
Vishnu Nair5cf253192019-11-07 15:33:20 -080040import android.os.IBinder;
John Reck79925002017-05-26 13:57:14 -070041import android.os.Looper;
Jackal Guoac234d62020-02-03 15:05:43 +080042import android.os.RemoteException;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070043import android.os.SystemClock;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070044import android.util.AttributeSet;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070045import android.util.Log;
Vishnu Nair8cb00ae2019-08-02 15:20:29 -070046import android.view.SurfaceControl.Transaction;
Robert Carr30ad6182019-12-18 01:46:04 -080047import android.view.SurfaceControlViewHost;
Valerie Hau779af292020-02-07 10:53:32 -080048import android.view.accessibility.AccessibilityNodeInfo;
Jackal Guoac234d62020-02-03 15:05:43 +080049import android.view.accessibility.IAccessibilityEmbeddedConnection;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070050
Robert Carr25cfa132016-11-16 13:24:09 -080051import com.android.internal.view.SurfaceCallbackHelper;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070052
Jon Larimer9bdf5762009-01-02 18:55:15 -050053import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070054import java.util.concurrent.locks.ReentrantLock;
55
56/**
57 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
58 * You can control the format of this surface and, if you like, its size; the
59 * SurfaceView takes care of placing the surface at the correct location on the
60 * screen
Igor Murashkina86ab6402013-08-30 12:58:36 -070061 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070062 * <p>The surface is Z ordered so that it is behind the window holding its
63 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070064 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070065 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070066 * normally appear on top of it. This can be used to place overlays such as
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070067 * buttons on top of the Surface, though note however that it can have an
68 * impact on performance since a full alpha-blended composite will be performed
69 * each time the Surface changes.
Igor Murashkina86ab6402013-08-30 12:58:36 -070070 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070071 * <p> The transparent region that makes the surface visible is based on the
72 * layout positions in the view hierarchy. If the post-layout transform
73 * properties are used to draw a sibling view on top of the SurfaceView, the
74 * view may not be properly composited with the surface.
75 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070076 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
77 * which can be retrieved by calling {@link #getHolder}.
Igor Murashkina86ab6402013-08-30 12:58:36 -070078 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070079 * <p>The Surface will be created for you while the SurfaceView's window is
80 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
81 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
82 * Surface is created and destroyed as the window is shown and hidden.
Igor Murashkina86ab6402013-08-30 12:58:36 -070083 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070084 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070085 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070086 * this way, you need to be aware of some threading semantics:
Igor Murashkina86ab6402013-08-30 12:58:36 -070087 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070088 * <ul>
89 * <li> All SurfaceView and
90 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
91 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070092 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070093 * state that is also touched by the drawing thread.
94 * <li> You must ensure that the drawing thread only touches the underlying
95 * Surface while it is valid -- between
96 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
97 * and
98 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
99 * </ul>
Chris Craik6ee192f2016-05-17 14:29:10 -0700100 *
101 * <p class="note"><strong>Note:</strong> Starting in platform version
102 * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
103 * updated synchronously with other View rendering. This means that translating
104 * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
105 * artifacts may occur on previous versions of the platform when its window is
106 * positioned asynchronously.</p>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700107 */
Vishnu Nair3b037f72019-07-22 12:55:58 -0700108public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800109 private static final String TAG = "SurfaceView";
110 private static final boolean DEBUG = false;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200111 private static final boolean DEBUG_POSITION = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700112
Mathew Inwooda570dee2018-08-17 14:56:00 +0100113 @UnsupportedAppUsage
Issei Suzukif0412592019-07-02 12:31:34 +0200114 final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<>();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700115
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800116 final int[] mLocation = new int[2];
Igor Murashkina86ab6402013-08-30 12:58:36 -0700117
Mathew Inwooda570dee2018-08-17 14:56:00 +0100118 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700119 final ReentrantLock mSurfaceLock = new ReentrantLock();
Mathew Inwooda570dee2018-08-17 14:56:00 +0100120 @UnsupportedAppUsage
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800121 final Surface mSurface = new Surface(); // Current surface in use
Mathew Inwood31755f92018-12-20 13:53:36 +0000122 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700123 boolean mDrawingStopped = true;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800124 // We use this to track if the application has produced a frame
125 // in to the Surface. Up until that point, we should be careful not to punch
126 // holes.
127 boolean mDrawFinished = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700128
Robert Carrd5c7dd62017-03-08 10:39:30 -0800129 final Rect mScreenRect = new Rect();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700130 private final SurfaceSession mSurfaceSession = new SurfaceSession();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800131
Robert Carrb923f542019-05-13 12:27:51 -0700132 SurfaceControl mSurfaceControl;
Robert Carr3bc95b52017-03-20 21:57:23 -0700133 // In the case of format changes we switch out the surface in-place
134 // we need to preserve the old one until the new one has drawn.
Robert Carrb923f542019-05-13 12:27:51 -0700135 SurfaceControl mDeferredDestroySurfaceControl;
136 SurfaceControl mBackgroundControl;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200137 final Object mSurfaceControlLock = new Object();
Robert Carr33879132016-09-06 14:41:40 -0700138 final Rect mTmpRect = new Rect();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700139
Mark Renouf34d04f32019-05-13 15:53:18 -0400140 Paint mRoundedViewportPaint;
141
Robert Carrd5c7dd62017-03-08 10:39:30 -0800142 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700143
Mathew Inwood31755f92018-12-20 13:53:36 +0000144 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700145 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700146 private volatile boolean mRtHandlingPositionUpdates = false;
Robert Carr005c63e2019-09-20 14:31:24 -0700147 private volatile boolean mRtReleaseSurfaces = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700148
Issei Suzukif0412592019-07-02 12:31:34 +0200149 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener =
150 this::updateSurface;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700151
Mathew Inwooda570dee2018-08-17 14:56:00 +0100152 @UnsupportedAppUsage
Issei Suzukif0412592019-07-02 12:31:34 +0200153 private final ViewTreeObserver.OnPreDrawListener mDrawListener = () -> {
154 // reposition ourselves where the surface is
155 mHaveFrame = getWidth() > 0 && getHeight() > 0;
156 updateSurface();
157 return true;
158 };
John Reckf6481082016-02-02 15:18:23 -0800159
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700160 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700161 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800162 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700163 boolean mViewVisibility = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700164 boolean mWindowStopped = false;
165
Mathew Inwood31755f92018-12-20 13:53:36 +0000166 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700167 int mRequestedWidth = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000168 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700169 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700170 /* Set SurfaceView's format to 565 by default to maintain backward
171 * compatibility with applications assuming this format.
172 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100173 @UnsupportedAppUsage
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700174 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700175
Issei Suzuki006b71f2019-06-17 15:56:57 +0200176 boolean mUseAlpha = false;
177 float mSurfaceAlpha = 1f;
Mark Renoufe574ad02019-08-12 16:22:15 -0400178 boolean mClipSurfaceToBounds;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200179
Mathew Inwooda570dee2018-08-17 14:56:00 +0100180 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700181 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800182 boolean mSurfaceCreated = false;
Mathew Inwood31755f92018-12-20 13:53:36 +0000183 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700184 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700185
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700186 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800187 int mWindowSpaceLeft = -1;
188 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800189 int mSurfaceWidth = -1;
190 int mSurfaceHeight = -1;
Mark Renouf34d04f32019-05-13 15:53:18 -0400191 float mCornerRadius;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100192 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700193 int mFormat = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000194 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700195 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700196 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Romain Guyf2499fa2011-01-26 18:31:23 -0800197
Romain Guy01d5edc2011-01-28 11:28:53 -0800198 private boolean mGlobalListenersAdded;
Robert Carr8508bb22017-03-27 15:46:27 -0700199 private boolean mAttachedToWindow;
Romain Guyf2499fa2011-01-26 18:31:23 -0800200
Robert Carrd5c7dd62017-03-08 10:39:30 -0800201 private int mSurfaceFlags = SurfaceControl.HIDDEN;
202
Robert Carr8508bb22017-03-27 15:46:27 -0700203 private int mPendingReportDraws;
204
Robert Carr27a800a2018-03-16 13:33:45 -0700205 private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
chaviw9f6171e2019-06-07 16:33:50 -0700206 private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700207 private int mParentSurfaceGenerationId;
Robert Carr27a800a2018-03-16 13:33:45 -0700208
Jackal Guoac234d62020-02-03 15:05:43 +0800209 private RemoteAccessibilityEmbeddedConnection mRemoteAccessibilityEmbeddedConnection;
210
211 private final Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
212 private final Matrix mTmpMatrix = new Matrix();
213 private final float[] mMatrixValues = new float[9];
214
Robert Carr30ad6182019-12-18 01:46:04 -0800215 SurfaceControlViewHost.SurfacePackage mSurfacePackage;
Jackal Guo79b182e2019-11-18 11:44:52 +0800216
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700217 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400218 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700219 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700220
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700221 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400222 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700223 }
224
Alan Viverette617feb92013-09-09 18:09:13 -0700225 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400226 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700227 }
228
229 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
230 super(context, attrs, defStyleAttr, defStyleRes);
Adam Powell769b8632019-02-04 11:28:22 -0800231 mRenderNode.addPositionUpdateListener(mPositionListener);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700232
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700233 setWillNotDraw(true);
234 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700235
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700236 /**
237 * Return the SurfaceHolder providing access and control over this
238 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700239 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700240 * @return SurfaceHolder The holder of the surface.
241 */
242 public SurfaceHolder getHolder() {
243 return mSurfaceHolder;
244 }
245
Robert Carr414ebc62017-04-12 12:01:00 -0700246 private void updateRequestedVisibility() {
247 mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
248 }
249
Vishnu Nair3b037f72019-07-22 12:55:58 -0700250 private void setWindowStopped(boolean stopped) {
Robert Carr414ebc62017-04-12 12:01:00 -0700251 mWindowStopped = stopped;
252 updateRequestedVisibility();
253 updateSurface();
254 }
255
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700256 @Override
257 protected void onAttachedToWindow() {
258 super.onAttachedToWindow();
Robert Carr414ebc62017-04-12 12:01:00 -0700259
Vishnu Nair3b037f72019-07-22 12:55:58 -0700260 getViewRootImpl().addSurfaceChangedCallback(this);
Robert Carr00177cc2017-05-15 15:49:17 -0700261 mWindowStopped = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700262
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700263 mViewVisibility = getVisibility() == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700264 updateRequestedVisibility();
Romain Guy01d5edc2011-01-28 11:28:53 -0800265
Robert Carr8508bb22017-03-27 15:46:27 -0700266 mAttachedToWindow = true;
Karthik Ravi Shankara59c3a52017-09-11 17:36:25 -0700267 mParent.requestTransparentRegion(SurfaceView.this);
Romain Guy01d5edc2011-01-28 11:28:53 -0800268 if (!mGlobalListenersAdded) {
269 ViewTreeObserver observer = getViewTreeObserver();
270 observer.addOnScrollChangedListener(mScrollChangedListener);
271 observer.addOnPreDrawListener(mDrawListener);
272 mGlobalListenersAdded = true;
273 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700274 }
275
276 @Override
277 protected void onWindowVisibilityChanged(int visibility) {
278 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700279 mWindowVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700280 updateRequestedVisibility();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800281 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700282 }
283
284 @Override
285 public void setVisibility(int visibility) {
286 super.setVisibility(visibility);
287 mViewVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700288 boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700289 if (newRequestedVisible != mRequestedVisible) {
290 // our base class (View) invalidates the layout only when
291 // we go from/to the GONE state. However, SurfaceView needs
292 // to request a re-layout when the visibility changes at all.
293 // This is needed because the transparent region is computed
294 // as part of the layout phase, and it changes (obviously) when
295 // the visibility changes.
296 requestLayout();
297 }
298 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800299 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700300 }
Romain Guyafc3e112010-06-07 17:04:33 -0700301
Issei Suzuki006b71f2019-06-17 15:56:57 +0200302 /**
303 * Make alpha value of this view reflect onto the surface. This can only be called from at most
304 * one SurfaceView within a view tree.
305 *
306 * <p class="note"><strong>Note:</strong> Alpha value of the view is ignored and the underlying
307 * surface is rendered opaque by default.</p>
308 *
309 * @hide
310 */
311 public void setUseAlpha() {
312 if (!mUseAlpha) {
313 mUseAlpha = true;
314 updateSurfaceAlpha();
315 }
316 }
317
318 @Override
319 public void setAlpha(float alpha) {
320 // Sets the opacity of the view to a value, where 0 means the view is completely transparent
321 // and 1 means the view is completely opaque.
322 //
323 // Note: Alpha value of this view is ignored by default. To enable alpha blending, you need
324 // to call setUseAlpha() as well.
325 // This view doesn't support translucent opacity if the view is located z-below, since the
326 // logic to punch a hole in the view hierarchy cannot handle such case. See also
327 // #clearSurfaceViewPort(Canvas)
328 if (DEBUG) {
329 Log.d(TAG, System.identityHashCode(this)
330 + " setAlpha: mUseAlpha = " + mUseAlpha + " alpha=" + alpha);
331 }
332 super.setAlpha(alpha);
333 updateSurfaceAlpha();
334 }
335
336 private float getFixedAlpha() {
337 // Compute alpha value to be set on the underlying surface.
338 final float alpha = getAlpha();
339 return mUseAlpha && (mSubLayer > 0 || alpha == 0f) ? alpha : 1f;
340 }
341
342 private void updateSurfaceAlpha() {
343 if (!mUseAlpha) {
344 if (DEBUG) {
345 Log.d(TAG, System.identityHashCode(this)
346 + " updateSurfaceAlpha: setUseAlpha() is not called, ignored.");
347 }
348 return;
349 }
350 final float viewAlpha = getAlpha();
351 if (mSubLayer < 0 && 0f < viewAlpha && viewAlpha < 1f) {
352 Log.w(TAG, System.identityHashCode(this)
353 + " updateSurfaceAlpha:"
354 + " translucent color is not supported for a surface placed z-below.");
355 }
356 if (!mHaveFrame) {
357 if (DEBUG) {
358 Log.d(TAG, System.identityHashCode(this)
359 + " updateSurfaceAlpha: has no surface.");
360 }
361 return;
362 }
363 final ViewRootImpl viewRoot = getViewRootImpl();
364 if (viewRoot == null) {
365 if (DEBUG) {
366 Log.d(TAG, System.identityHashCode(this)
367 + " updateSurfaceAlpha: ViewRootImpl not available.");
368 }
369 return;
370 }
371 if (mSurfaceControl == null) {
372 if (DEBUG) {
373 Log.d(TAG, System.identityHashCode(this)
374 + "updateSurfaceAlpha:"
375 + " surface is not yet created, or already released.");
376 }
377 return;
378 }
379 final Surface parent = viewRoot.mSurface;
380 if (parent == null || !parent.isValid()) {
381 if (DEBUG) {
382 Log.d(TAG, System.identityHashCode(this)
383 + " updateSurfaceAlpha: ViewRootImpl has no valid surface");
384 }
385 return;
386 }
387 final float alpha = getFixedAlpha();
388 if (alpha != mSurfaceAlpha) {
389 if (isHardwareAccelerated()) {
390 /*
391 * Schedule a callback that reflects an alpha value onto the underlying surfaces.
392 * This gets called on a RenderThread worker thread, so members accessed here must
393 * be protected by a lock.
394 */
Valerie Haubdb905a2020-02-10 15:07:36 -0800395 final boolean useBLAST = WindowManagerGlobal.useBLAST();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200396 viewRoot.registerRtFrameCallback(frame -> {
397 try {
Robert Carr85bb9402019-12-19 01:33:24 -0800398 final SurfaceControl.Transaction t = useBLAST ?
399 viewRoot.getBLASTSyncTransaction() : new SurfaceControl.Transaction();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200400 synchronized (mSurfaceControlLock) {
401 if (!parent.isValid()) {
402 if (DEBUG) {
403 Log.d(TAG, System.identityHashCode(this)
404 + " updateSurfaceAlpha RT:"
405 + " ViewRootImpl has no valid surface");
406 }
407 return;
408 }
409 if (mSurfaceControl == null) {
410 if (DEBUG) {
411 Log.d(TAG, System.identityHashCode(this)
412 + "updateSurfaceAlpha RT:"
413 + " mSurfaceControl has already released");
414 }
415 return;
416 }
417 if (DEBUG) {
418 Log.d(TAG, System.identityHashCode(this)
419 + " updateSurfaceAlpha RT: set alpha=" + alpha);
420 }
421 t.setAlpha(mSurfaceControl, alpha);
Robert Carr85bb9402019-12-19 01:33:24 -0800422 if (!useBLAST) {
Robert Carrcef9a282020-01-14 09:08:05 -0800423 t.deferTransactionUntil(mSurfaceControl,
424 viewRoot.getRenderSurfaceControl(), frame);
Robert Carr85bb9402019-12-19 01:33:24 -0800425 }
Issei Suzuki006b71f2019-06-17 15:56:57 +0200426 }
427 // It's possible that mSurfaceControl is released in the UI thread before
428 // the transaction completes. If that happens, an exception is thrown, which
429 // must be caught immediately.
430 t.apply();
431 } catch (Exception e) {
432 Log.e(TAG, System.identityHashCode(this)
433 + "updateSurfaceAlpha RT: Exception during surface transaction", e);
434 }
435 });
436 damageInParent();
437 } else {
438 if (DEBUG) {
439 Log.d(TAG, System.identityHashCode(this)
440 + " updateSurfaceAlpha: set alpha=" + alpha);
441 }
chaviw619da692019-06-10 15:39:40 -0700442 mTmpTransaction.setAlpha(mSurfaceControl, alpha).apply();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200443 }
444 mSurfaceAlpha = alpha;
445 }
446 }
447
Robert Carrb53670a2017-05-25 18:20:49 -0700448 private void performDrawFinished() {
449 if (mPendingReportDraws > 0) {
450 mDrawFinished = true;
451 if (mAttachedToWindow) {
Pengfei Zhao15617202019-02-28 17:07:41 +0800452 mParent.requestTransparentRegion(SurfaceView.this);
Robert Carrb53670a2017-05-25 18:20:49 -0700453 notifyDrawFinished();
454 invalidate();
455 }
456 } else {
457 Log.e(TAG, System.identityHashCode(this) + "finished drawing"
458 + " but no pending report draw (extra call"
459 + " to draw completion runnable?)");
460 }
461 }
462
Robert Carr8508bb22017-03-27 15:46:27 -0700463 void notifyDrawFinished() {
464 ViewRootImpl viewRoot = getViewRootImpl();
465 if (viewRoot != null) {
466 viewRoot.pendingDrawFinished();
467 }
468 mPendingReportDraws--;
469 }
470
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700471 @Override
John Reck77e4a522014-10-01 10:38:07 -0700472 protected void onDetachedFromWindow() {
Lucas Dupin0c207342017-04-14 19:47:23 -0700473 ViewRootImpl viewRoot = getViewRootImpl();
474 // It's possible to create a SurfaceView using the default constructor and never
475 // attach it to a view hierarchy, this is a common use case when dealing with
476 // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
477 // the lifecycle. Instead of attaching it to a view, he/she can just pass
478 // the SurfaceHolder forward, most live wallpapers do it.
479 if (viewRoot != null) {
Vishnu Nair3b037f72019-07-22 12:55:58 -0700480 viewRoot.removeSurfaceChangedCallback(this);
Lucas Dupin0c207342017-04-14 19:47:23 -0700481 }
Robert Carr414ebc62017-04-12 12:01:00 -0700482
Robert Carr8508bb22017-03-27 15:46:27 -0700483 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800484 if (mGlobalListenersAdded) {
485 ViewTreeObserver observer = getViewTreeObserver();
486 observer.removeOnScrollChangedListener(mScrollChangedListener);
487 observer.removeOnPreDrawListener(mDrawListener);
488 mGlobalListenersAdded = false;
489 }
490
Robert Carr8508bb22017-03-27 15:46:27 -0700491 while (mPendingReportDraws > 0) {
492 notifyDrawFinished();
493 }
494
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700495 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800496
Robert Carrd5c7dd62017-03-08 10:39:30 -0800497 updateSurface();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200498 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800499 mHaveFrame = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700500
John Reck77e4a522014-10-01 10:38:07 -0700501 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700502 }
503
504 @Override
505 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800506 int width = mRequestedWidth >= 0
507 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
508 : getDefaultSize(0, widthMeasureSpec);
509 int height = mRequestedHeight >= 0
510 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
511 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700512 setMeasuredDimension(width, height);
513 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700514
Mathias Agopianef115302010-10-04 20:15:08 -0700515 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700516 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100517 @UnsupportedAppUsage
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700518 protected boolean setFrame(int left, int top, int right, int bottom) {
519 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800520 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700521 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700522 }
523
524 @Override
525 public boolean gatherTransparentRegion(Region region) {
Robert Carr3ca12be72017-05-22 14:57:48 -0700526 if (isAboveParent() || !mDrawFinished) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700527 return super.gatherTransparentRegion(region);
528 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700529
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700530 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700531 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700532 // this view draws, remove it from the transparent region
533 opaque = super.gatherTransparentRegion(region);
534 } else if (region != null) {
535 int w = getWidth();
536 int h = getHeight();
537 if (w>0 && h>0) {
538 getLocationInWindow(mLocation);
539 // otherwise, punch a hole in the whole hierarchy
540 int l = mLocation[0];
541 int t = mLocation[1];
542 region.op(l, t, l+w, t+h, Region.Op.UNION);
543 }
544 }
545 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
546 opaque = false;
547 }
548 return opaque;
549 }
550
551 @Override
552 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800553 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700554 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700555 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700556 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400557 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700558 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700559 }
560 super.draw(canvas);
561 }
562
563 @Override
564 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800565 if (mDrawFinished && !isAboveParent()) {
566 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700567 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700568 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400569 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700570 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700571 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700572 super.dispatchDraw(canvas);
573 }
574
Mark Renoufe574ad02019-08-12 16:22:15 -0400575 /**
576 * Control whether the surface is clipped to the same bounds as the View. If true, then
577 * the bounds set by {@link #setClipBounds(Rect)} are applied to the surface as window-crop.
578 *
579 * @param enabled whether to enable surface clipping
580 * @hide
581 */
582 public void setEnableSurfaceClipping(boolean enabled) {
583 mClipSurfaceToBounds = enabled;
584 invalidate();
585 }
586
587 @Override
588 public void setClipBounds(Rect clipBounds) {
589 super.setClipBounds(clipBounds);
590
591 if (!mClipSurfaceToBounds) {
592 return;
593 }
594
595 // When cornerRadius is non-zero, a draw() is required to update
596 // the viewport (rounding the corners of the clipBounds).
597 if (mCornerRadius > 0f && !isAboveParent()) {
598 invalidate();
599 }
600
601 if (mSurfaceControl != null) {
602 if (mClipBounds != null) {
603 mTmpRect.set(mClipBounds);
604 } else {
605 mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
606 }
607 SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this);
608 applier.scheduleApply(
609 new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl)
610 .withWindowCrop(mTmpRect)
611 .build());
612 }
613 }
614
Mark Renouf34d04f32019-05-13 15:53:18 -0400615 private void clearSurfaceViewPort(Canvas canvas) {
616 if (mCornerRadius > 0f) {
617 canvas.getClipBounds(mTmpRect);
Mark Renoufe574ad02019-08-12 16:22:15 -0400618 if (mClipSurfaceToBounds && mClipBounds != null) {
619 mTmpRect.intersect(mClipBounds);
620 }
Mark Renouf34d04f32019-05-13 15:53:18 -0400621 canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
622 mCornerRadius, mCornerRadius, mRoundedViewportPaint);
623 } else {
624 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
625 }
626 }
627
628 /**
629 * Sets the corner radius for the SurfaceView. This will round both the corners of the
630 * underlying surface, as well as the corners of the hole created to expose the surface.
631 *
632 * @param cornerRadius the new radius of the corners in pixels
633 * @hide
634 */
635 public void setCornerRadius(float cornerRadius) {
636 mCornerRadius = cornerRadius;
637 if (mCornerRadius > 0f && mRoundedViewportPaint == null) {
638 mRoundedViewportPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
639 mRoundedViewportPaint.setBlendMode(BlendMode.CLEAR);
640 mRoundedViewportPaint.setColor(0);
641 }
642 invalidate();
643 }
644
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700645 /**
Mark Renoufe574ad02019-08-12 16:22:15 -0400646 * Returns the corner radius for the SurfaceView.
647
648 * @return the radius of the corners in pixels
649 * @hide
650 */
651 public float getCornerRadius() {
652 return mCornerRadius;
653 }
654
655 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700656 * Control whether the surface view's surface is placed on top of another
657 * regular surface view in the window (but still behind the window itself).
658 * This is typically used to place overlays on top of an underlying media
659 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700660 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700661 * <p>Note that this must be set before the surface view's containing
662 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700663 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700664 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
665 */
666 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800667 mSubLayer = isMediaOverlay
668 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700669 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700670
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700671 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700672 * Control whether the surface view's surface is placed on top of its
673 * window. Normally it is placed behind the window, to allow it to
674 * (for the most part) appear to composite with the views in the
675 * hierarchy. By setting this, you cause it to be placed above the
676 * window. This means that none of the contents of the window this
677 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700678 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700679 * <p>Note that this must be set before the surface view's containing
680 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700681 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700682 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700683 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700684 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500685 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800686 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500687 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800688 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500689 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700690 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700691
692 /**
693 * Control whether the surface view's content should be treated as secure,
694 * preventing it from appearing in screenshots or from being viewed on
695 * non-secure displays.
696 *
697 * <p>Note that this must be set before the surface view's containing
698 * window is attached to the window manager.
699 *
700 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
701 *
702 * @param isSecure True if the surface view is secure.
703 */
704 public void setSecure(boolean isSecure) {
705 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800706 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700707 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800708 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700709 }
710 }
711
Robert Carr55235552017-06-02 14:21:03 -0700712 private void updateOpaqueFlag() {
Robert Carr851e7e42017-06-06 14:04:50 -0700713 if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
Robert Carr55235552017-06-02 14:21:03 -0700714 mSurfaceFlags |= SurfaceControl.OPAQUE;
715 } else {
716 mSurfaceFlags &= ~SurfaceControl.OPAQUE;
717 }
718 }
719
chaviw619da692019-06-10 15:39:40 -0700720 private void updateBackgroundVisibility(Transaction t) {
Robert Carrb923f542019-05-13 12:27:51 -0700721 if (mBackgroundControl == null) {
722 return;
723 }
724 if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
chaviw619da692019-06-10 15:39:40 -0700725 t.show(mBackgroundControl);
Robert Carrb923f542019-05-13 12:27:51 -0700726 } else {
chaviw619da692019-06-10 15:39:40 -0700727 t.hide(mBackgroundControl);
Robert Carrb923f542019-05-13 12:27:51 -0700728 }
729 }
730
chaviw619da692019-06-10 15:39:40 -0700731
Robert Carrb923f542019-05-13 12:27:51 -0700732 private void releaseSurfaces() {
Robert Carr005c63e2019-09-20 14:31:24 -0700733 mSurfaceAlpha = 1f;
734
Issei Suzuki006b71f2019-06-17 15:56:57 +0200735 synchronized (mSurfaceControlLock) {
Robert Carrde63cc62019-10-25 13:18:29 -0700736 mSurface.release();
737
Robert Carr005c63e2019-09-20 14:31:24 -0700738 if (mRtHandlingPositionUpdates) {
739 mRtReleaseSurfaces = true;
740 return;
741 }
742
Issei Suzuki006b71f2019-06-17 15:56:57 +0200743 if (mSurfaceControl != null) {
744 mTmpTransaction.remove(mSurfaceControl);
745 mSurfaceControl = null;
746 }
747 if (mBackgroundControl != null) {
748 mTmpTransaction.remove(mBackgroundControl);
749 mBackgroundControl = null;
750 }
751 mTmpTransaction.apply();
Robert Carrb923f542019-05-13 12:27:51 -0700752 }
Robert Carrb923f542019-05-13 12:27:51 -0700753 }
754
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900755 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800756 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700757 if (!mHaveFrame) {
Issei Suzuki006b71f2019-06-17 15:56:57 +0200758 if (DEBUG) {
759 Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
760 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700761 return;
762 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800763 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800764 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
Issei Suzuki006b71f2019-06-17 15:56:57 +0200765 if (DEBUG) {
766 Log.d(TAG, System.identityHashCode(this)
767 + " updateSurface: no valid surface");
768 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800769 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700770 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700771
Issei Suzukif0412592019-07-02 12:31:34 +0200772 final Translator translator = viewRoot.mTranslator;
773 if (translator != null) {
774 mSurface.setCompatibilityTranslator(translator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700775 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700776
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700777 int myWidth = mRequestedWidth;
778 if (myWidth <= 0) myWidth = getWidth();
779 int myHeight = mRequestedHeight;
780 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700781
Issei Suzuki006b71f2019-06-17 15:56:57 +0200782 final float alpha = getFixedAlpha();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700783 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700784 final boolean visibleChanged = mVisible != mRequestedVisible;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200785 final boolean alphaChanged = mSurfaceAlpha != alpha;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700786 final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
Robert Carrd5c7dd62017-03-08 10:39:30 -0800787 && mRequestedVisible;
788 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800789 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700790 boolean redrawNeeded = false;
791
Issei Suzuki006b71f2019-06-17 15:56:57 +0200792 if (creating || formatChanged || sizeChanged || visibleChanged || (mUseAlpha
793 && alphaChanged) || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800794 getLocationInWindow(mLocation);
795
John Reckaa6e84f2016-06-16 15:36:13 -0700796 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
797 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700798 + " format=" + formatChanged + " size=" + sizeChanged
Issei Suzuki006b71f2019-06-17 15:56:57 +0200799 + " visible=" + visibleChanged + " alpha=" + alphaChanged
800 + " mUseAlpha=" + mUseAlpha
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700801 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800802 + " left=" + (mWindowSpaceLeft != mLocation[0])
803 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700804
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700805 try {
806 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800807 mWindowSpaceLeft = mLocation[0];
808 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800809 mSurfaceWidth = myWidth;
810 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700811 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800812 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700813
Robert Carrd5c7dd62017-03-08 10:39:30 -0800814 mScreenRect.left = mWindowSpaceLeft;
815 mScreenRect.top = mWindowSpaceTop;
816 mScreenRect.right = mWindowSpaceLeft + getWidth();
817 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Issei Suzukif0412592019-07-02 12:31:34 +0200818 if (translator != null) {
819 translator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700820 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700821
Issei Suzuki006b71f2019-06-17 15:56:57 +0200822 final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800823 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
824
825 if (creating) {
Robert Carr3bc95b52017-03-20 21:57:23 -0700826 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carr55235552017-06-02 14:21:03 -0700827
828 updateOpaqueFlag();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700829 // SurfaceView hierarchy
830 // ViewRootImpl surface
831 // - bounds layer (crops all child surfaces to parent surface insets)
832 // - SurfaceView surface (drawn relative to ViewRootImpl surface)
833 // - Background color layer (drawn behind all SurfaceView surfaces)
834 //
835 // The bounds layer is used to crop the surface view so it does not draw into
836 // the parent surface inset region. Since there can be multiple surface views
837 // below or above the parent surface, one option is to create multiple bounds
838 // layer for each z order. The other option, the one implement is to create
839 // a single bounds layer and set z order for each child surface relative to the
840 // parent surface.
841 // When creating the surface view, we parent it to the bounds layer and then
842 // set the relative z order. When the parent surface changes, we have to
843 // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback.
Robert Carre625fcf2017-09-01 12:36:28 -0700844 final String name = "SurfaceView - " + viewRoot.getTitle().toString();
Vishnu Naireaab0e52019-06-24 08:12:28 -0700845
846 mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
847 .setName(name)
848 .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
849 .setBufferSize(mSurfaceWidth, mSurfaceHeight)
850 .setFormat(mFormat)
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700851 .setParent(viewRoot.getBoundsLayer())
Vishnu Naireaab0e52019-06-24 08:12:28 -0700852 .setFlags(mSurfaceFlags)
853 .build();
Robert Carrb923f542019-05-13 12:27:51 -0700854 mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
855 .setName("Background for -" + name)
856 .setOpaque(true)
857 .setColorLayer()
858 .setParent(mSurfaceControl)
859 .build();
860
Robert Carr44ab5752017-03-20 21:47:11 -0700861 } else if (mSurfaceControl == null) {
862 return;
Robert Carr64aadd02015-11-06 13:54:20 -0800863 }
864
Robert Carrd5c7dd62017-03-08 10:39:30 -0800865 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800866
Dianne Hackborn726426e2010-03-31 22:04:36 -0700867 mSurfaceLock.lock();
868 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700869 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700870
John Reckaa6e84f2016-06-16 15:36:13 -0700871 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
872 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800873
chaviw619da692019-06-10 15:39:40 -0700874 // If we are creating the surface control or the parent surface has not
875 // changed, then set relative z. Otherwise allow the parent
876 // SurfaceChangedCallback to update the relative z. This is needed so that
877 // we do not change the relative z before the server is ready to swap the
878 // parent surface.
879 if (creating || (mParentSurfaceGenerationId
880 == viewRoot.mSurface.getGenerationId())) {
881 updateRelativeZ(mTmpTransaction);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700882 }
chaviw619da692019-06-10 15:39:40 -0700883 mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
884
885 if (mViewVisibility) {
886 mTmpTransaction.show(mSurfaceControl);
887 } else {
888 mTmpTransaction.hide(mSurfaceControl);
889 }
Robert Carr30ad6182019-12-18 01:46:04 -0800890
891 if (mSurfacePackage != null) {
892 reparentSurfacePackage(mTmpTransaction, mSurfacePackage);
893 }
894
chaviw619da692019-06-10 15:39:40 -0700895 updateBackgroundVisibility(mTmpTransaction);
896 if (mUseAlpha) {
897 mTmpTransaction.setAlpha(mSurfaceControl, alpha);
898 mSurfaceAlpha = alpha;
899 }
900
901 // While creating the surface, we will set it's initial
902 // geometry. Outside of that though, we should generally
903 // leave it to the RenderThread.
904 //
905 // There is one more case when the buffer size changes we aren't yet
906 // prepared to sync (as even following the transaction applying
907 // we still need to latch a buffer).
908 // b/28866173
909 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
910 mTmpTransaction.setPosition(mSurfaceControl, mScreenRect.left,
911 mScreenRect.top);
912 mTmpTransaction.setMatrix(mSurfaceControl,
913 mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f,
914 mScreenRect.height() / (float) mSurfaceHeight);
915 // Set a window crop when creating the surface or changing its size to
916 // crop the buffer to the surface size since the buffer producer may
917 // use SCALING_MODE_SCALE and submit a larger size than the surface
918 // size.
919 if (mClipSurfaceToBounds && mClipBounds != null) {
920 mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
921 } else {
922 mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
923 mSurfaceHeight);
924 }
925 }
926 mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
927 if (sizeChanged && !creating) {
928 mTmpTransaction.setBufferSize(mSurfaceControl, mSurfaceWidth,
929 mSurfaceHeight);
930 }
931
932 mTmpTransaction.apply();
Jackal Guoac234d62020-02-03 15:05:43 +0800933 updateScreenMatrixForEmbeddedHierarchy();
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800934
Robert Carrd5c7dd62017-03-08 10:39:30 -0800935 if (sizeChanged || creating) {
936 redrawNeeded = true;
937 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800938
Dianne Hackborn726426e2010-03-31 22:04:36 -0700939 mSurfaceFrame.left = 0;
940 mSurfaceFrame.top = 0;
Issei Suzukif0412592019-07-02 12:31:34 +0200941 if (translator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800942 mSurfaceFrame.right = mSurfaceWidth;
943 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700944 } else {
Issei Suzukif0412592019-07-02 12:31:34 +0200945 float appInvertedScale = translator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800946 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
947 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700948 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700949
Dianne Hackborn726426e2010-03-31 22:04:36 -0700950 final int surfaceWidth = mSurfaceFrame.right;
951 final int surfaceHeight = mSurfaceFrame.bottom;
952 realSizeChanged = mLastSurfaceWidth != surfaceWidth
953 || mLastSurfaceHeight != surfaceHeight;
954 mLastSurfaceWidth = surfaceWidth;
955 mLastSurfaceHeight = surfaceHeight;
956 } finally {
957 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700958 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700959
960 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800961 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700962
Issei Suzuki60557b52019-07-03 20:04:48 +0200963 SurfaceHolder.Callback[] callbacks = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700964
Robert Carrd5c7dd62017-03-08 10:39:30 -0800965 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800966 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
967 mSurfaceCreated = false;
968 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700969 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
970 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800971 callbacks = getSurfaceCallbacks();
972 for (SurfaceHolder.Callback c : callbacks) {
973 c.surfaceDestroyed(mSurfaceHolder);
974 }
Robert Carr387838b2016-09-07 14:12:44 -0700975 // Since Android N the same surface may be reused and given to us
976 // again by the system server at a later point. However
977 // as we didn't do this in previous releases, clients weren't
978 // necessarily required to clean up properly in
979 // surfaceDestroyed. This leads to problems for example when
980 // clients don't destroy their EGL context, and try
981 // and create a new one on the same surface following reuse.
982 // Since there is no valid use of the surface in-between
983 // surfaceDestroyed and surfaceCreated, we force a disconnect,
984 // so the next connect will always work if we end up reusing
985 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700986 if (mSurface.isValid()) {
987 mSurface.forceScopedDisconnect();
988 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700989 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800990 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700991
Robert Carrd5c7dd62017-03-08 10:39:30 -0800992 if (creating) {
Robert Carrb923f542019-05-13 12:27:51 -0700993 mSurface.copyFrom(mSurfaceControl);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800994 }
995
Bryce Lee453fc362017-06-20 10:47:55 -0700996 if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
Bryce Lee02949f12017-06-16 07:20:34 -0700997 < Build.VERSION_CODES.O) {
998 // Some legacy applications use the underlying native {@link Surface} object
999 // as a key to whether anything has changed. In these cases, updates to the
1000 // existing {@link Surface} will be ignored when the size changes.
1001 // Therefore, we must explicitly recreate the {@link Surface} in these
1002 // cases.
Robert Carrb923f542019-05-13 12:27:51 -07001003 mSurface.createFrom(mSurfaceControl);
Bryce Lee02949f12017-06-16 07:20:34 -07001004 }
1005
Andreas Röhlf750b8c2012-07-02 13:06:26 +02001006 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001007 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
1008 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001009 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -07001010 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1011 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001012 if (callbacks == null) {
1013 callbacks = getSurfaceCallbacks();
1014 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001015 for (SurfaceHolder.Callback c : callbacks) {
1016 c.surfaceCreated(mSurfaceHolder);
1017 }
1018 }
1019 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -07001020 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -07001021 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1022 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001023 + " w=" + myWidth + " h=" + myHeight);
1024 if (callbacks == null) {
1025 callbacks = getSurfaceCallbacks();
1026 }
Dianne Hackborn251fd432010-07-14 16:56:31 -07001027 for (SurfaceHolder.Callback c : callbacks) {
1028 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
1029 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001030 }
1031 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -07001032 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1033 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001034 if (callbacks == null) {
1035 callbacks = getSurfaceCallbacks();
1036 }
Robert Carr8508bb22017-03-27 15:46:27 -07001037
1038 mPendingReportDraws++;
1039 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -08001040 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -08001041 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -08001042 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001043 }
1044 }
1045 } finally {
1046 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001047 if (mSurfaceControl != null && !mSurfaceCreated) {
Robert Carrb923f542019-05-13 12:27:51 -07001048 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -08001049 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001050 }
Robert Carrd5c7dd62017-03-08 10:39:30 -08001051 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -07001052 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001053 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001054 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -08001055 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
1056 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
1057 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -07001058 } else {
1059 // Calculate the window position in case RT loses the window
1060 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -08001061 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -08001062 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
1063 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -08001064 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
1065 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -08001066 if (positionChanged || layoutSizeChanged) { // Only the position has changed
1067 mWindowSpaceLeft = mLocation[0];
1068 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -08001069 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -08001070 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -08001071 mLocation[0] = getWidth();
1072 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -08001073
Robert Carrd5c7dd62017-03-08 10:39:30 -08001074 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
Robert Carrc90e5f82017-07-18 13:10:02 -07001075 mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
John Reckf057fb52016-04-15 13:46:29 -07001076
Issei Suzukif0412592019-07-02 12:31:34 +02001077 if (translator != null) {
1078 translator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -07001079 }
1080
Robert Carr3651ab82017-04-25 12:05:34 -07001081 if (mSurfaceControl == null) {
1082 return;
1083 }
1084
Bryce Lee16e50892017-04-11 01:59:37 +00001085 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
John Reckf23a1b82016-06-22 14:23:31 -07001086 try {
Issei Suzuki006b71f2019-06-17 15:56:57 +02001087 if (DEBUG_POSITION) {
1088 Log.d(TAG, String.format("%d updateSurfacePosition UI, "
1089 + "position = [%d, %d, %d, %d]",
1090 System.identityHashCode(this),
1091 mScreenRect.left, mScreenRect.top,
1092 mScreenRect.right, mScreenRect.bottom));
1093 }
Robert Carrd5c7dd62017-03-08 10:39:30 -08001094 setParentSpaceRectangle(mScreenRect, -1);
1095 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -07001096 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -07001097 }
John Reckf6481082016-02-02 15:18:23 -08001098 }
Rob Carr64e516f2015-10-29 00:20:45 +00001099 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001100 }
1101 }
1102
Robert Carrd5c7dd62017-03-08 10:39:30 -08001103 private void onDrawFinished() {
1104 if (DEBUG) {
1105 Log.i(TAG, System.identityHashCode(this) + " "
1106 + "finishedDrawing");
1107 }
Robert Carr3bc95b52017-03-20 21:57:23 -07001108
1109 if (mDeferredDestroySurfaceControl != null) {
chaviw9f6171e2019-06-07 16:33:50 -07001110 mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
Robert Carr3bc95b52017-03-20 21:57:23 -07001111 mDeferredDestroySurfaceControl = null;
1112 }
1113
Issei Suzuki60557b52019-07-03 20:04:48 +02001114 runOnUiThread(this::performDrawFinished);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001115 }
1116
Robert Carr27a800a2018-03-16 13:33:45 -07001117 /**
1118 * A place to over-ride for applying child-surface transactions.
1119 * These can be synchronized with the viewroot surface using deferTransaction.
1120 *
1121 * Called from RenderWorker while UI thread is paused.
1122 * @hide
1123 */
1124 protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
1125 Surface viewRootSurface, long nextViewRootFrameNumber) {
1126 }
1127
Robert Carr85bb9402019-12-19 01:33:24 -08001128 private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
1129 Rect position, long frameNumber) {
Valerie Haubdb905a2020-02-10 15:07:36 -08001130 if (frameNumber > 0 && !WindowManagerGlobal.useBLAST()) {
Robert Carr386fd702018-03-23 13:46:39 -07001131 final ViewRootImpl viewRoot = getViewRootImpl();
1132
Robert Carrcef9a282020-01-14 09:08:05 -08001133 t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(),
Robert Carr27a800a2018-03-16 13:33:45 -07001134 frameNumber);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001135 }
Robert Carr386fd702018-03-23 13:46:39 -07001136
Robert Carr85bb9402019-12-19 01:33:24 -08001137 t.setPosition(surface, position.left, position.top);
1138 t.setMatrix(surface,
Robert Carr27a800a2018-03-16 13:33:45 -07001139 position.width() / (float) mSurfaceWidth,
1140 0.0f, 0.0f,
1141 position.height() / (float) mSurfaceHeight);
John Reckd0abd662019-05-01 12:52:04 -07001142 if (mViewVisibility) {
Robert Carr85bb9402019-12-19 01:33:24 -08001143 t.show(surface);
John Reckd0abd662019-05-01 12:52:04 -07001144 }
Robert Carr386fd702018-03-23 13:46:39 -07001145 }
1146
1147 private void setParentSpaceRectangle(Rect position, long frameNumber) {
Valerie Haubdb905a2020-02-10 15:07:36 -08001148 final boolean useBLAST = WindowManagerGlobal.useBLAST();
Robert Carr386fd702018-03-23 13:46:39 -07001149 final ViewRootImpl viewRoot = getViewRootImpl();
Robert Carr85bb9402019-12-19 01:33:24 -08001150 final SurfaceControl.Transaction t = useBLAST ? viewRoot.getBLASTSyncTransaction() :
1151 mRtTransaction;
Robert Carr386fd702018-03-23 13:46:39 -07001152
Robert Carr85bb9402019-12-19 01:33:24 -08001153 applySurfaceTransforms(mSurfaceControl, t, position, frameNumber);
Robert Carr27a800a2018-03-16 13:33:45 -07001154
Robert Carr85bb9402019-12-19 01:33:24 -08001155 applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface,
Robert Carr27a800a2018-03-16 13:33:45 -07001156 frameNumber);
1157
Robert Carr85bb9402019-12-19 01:33:24 -08001158 if (!useBLAST) {
1159 t.apply();
1160 }
Robert Carrd5c7dd62017-03-08 10:39:30 -08001161 }
1162
John Reckf6481082016-02-02 15:18:23 -08001163 private Rect mRTLastReportedPosition = new Rect();
1164
John Reck6b164402018-09-24 15:25:42 -07001165 private RenderNode.PositionUpdateListener mPositionListener =
1166 new RenderNode.PositionUpdateListener() {
Robert Carrd5c7dd62017-03-08 10:39:30 -08001167
John Reck6b164402018-09-24 15:25:42 -07001168 @Override
1169 public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
1170 if (mSurfaceControl == null) {
1171 return;
John Reckf6481082016-02-02 15:18:23 -08001172 }
John Reckf6481082016-02-02 15:18:23 -08001173
John Reck6b164402018-09-24 15:25:42 -07001174 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
1175 // its 2nd frame if RenderThread is running slowly could potentially see
1176 // this as false, enter the branch, get pre-empted, then this comes along
1177 // and reports a new position, then the UI thread resumes and reports
1178 // its position. This could therefore be de-sync'd in that interval, but
1179 // the synchronization would violate the rule that RT must never block
1180 // on the UI thread which would open up potential deadlocks. The risk of
1181 // a single-frame desync is therefore preferable for now.
Robert Carr005c63e2019-09-20 14:31:24 -07001182 synchronized(mSurfaceControlLock) {
1183 mRtHandlingPositionUpdates = true;
1184 }
John Reck6b164402018-09-24 15:25:42 -07001185 if (mRTLastReportedPosition.left == left
1186 && mRTLastReportedPosition.top == top
1187 && mRTLastReportedPosition.right == right
1188 && mRTLastReportedPosition.bottom == bottom) {
1189 return;
1190 }
1191 try {
Issei Suzuki006b71f2019-06-17 15:56:57 +02001192 if (DEBUG_POSITION) {
John Reck6b164402018-09-24 15:25:42 -07001193 Log.d(TAG, String.format(
1194 "%d updateSurfacePosition RenderWorker, frameNr = %d, "
Issei Suzuki60557b52019-07-03 20:04:48 +02001195 + "position = [%d, %d, %d, %d]",
John Reck6b164402018-09-24 15:25:42 -07001196 System.identityHashCode(this), frameNumber,
1197 left, top, right, bottom));
1198 }
1199 mRTLastReportedPosition.set(left, top, right, bottom);
1200 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
1201 // Now overwrite mRTLastReportedPosition with our values
1202 } catch (Exception ex) {
1203 Log.e(TAG, "Exception from repositionChild", ex);
1204 }
John Reckaa6e84f2016-06-16 15:36:13 -07001205 }
Robert Carrad3a4932017-06-20 14:55:21 -07001206
John Reck6b164402018-09-24 15:25:42 -07001207 @Override
1208 public void positionLost(long frameNumber) {
Valerie Haubdb905a2020-02-10 15:07:36 -08001209 boolean useBLAST = WindowManagerGlobal.useBLAST();
John Reck6b164402018-09-24 15:25:42 -07001210 if (DEBUG) {
1211 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
1212 System.identityHashCode(this), frameNumber));
1213 }
1214 mRTLastReportedPosition.setEmpty();
1215
1216 if (mSurfaceControl == null) {
1217 return;
1218 }
John Reckd0abd662019-05-01 12:52:04 -07001219
Robert Carr94210482019-09-26 10:44:16 -07001220 final ViewRootImpl viewRoot = getViewRootImpl();
Robert Carr85bb9402019-12-19 01:33:24 -08001221
1222 final SurfaceControl.Transaction t = useBLAST ?
1223 (viewRoot != null ? viewRoot.getBLASTSyncTransaction() : mRtTransaction) :
1224 mRtTransaction;
1225
1226 if (frameNumber > 0 && viewRoot != null && !useBLAST) {
Robert Carr94210482019-09-26 10:44:16 -07001227 if (viewRoot.mSurface.isValid()) {
Robert Carrcef9a282020-01-14 09:08:05 -08001228 mRtTransaction.deferTransactionUntil(mSurfaceControl,
1229 viewRoot.getRenderSurfaceControl(), frameNumber);
Robert Carr94210482019-09-26 10:44:16 -07001230 }
John Reckf23a1b82016-06-22 14:23:31 -07001231 }
Robert Carr85bb9402019-12-19 01:33:24 -08001232 t.hide(mSurfaceControl);
Robert Carr005c63e2019-09-20 14:31:24 -07001233
1234 synchronized (mSurfaceControlLock) {
1235 if (mRtReleaseSurfaces) {
1236 mRtReleaseSurfaces = false;
1237 mRtTransaction.remove(mSurfaceControl);
1238 mRtTransaction.remove(mBackgroundControl);
1239 mSurfaceControl = null;
1240 mBackgroundControl = null;
1241 }
1242 mRtHandlingPositionUpdates = false;
1243 }
1244
Robert Carr85bb9402019-12-19 01:33:24 -08001245 // If we aren't using BLAST, we apply the transaction locally, otherise we let the ViewRoot apply it for us.
1246 // If the ViewRoot is null, we behave as if we aren't using BLAST so we need to apply the transaction.
1247 if (!useBLAST || viewRoot == null) {
1248 mRtTransaction.apply();
1249 }
John Reckf23a1b82016-06-22 14:23:31 -07001250 }
John Reck6b164402018-09-24 15:25:42 -07001251 };
John Reckaa6e84f2016-06-16 15:36:13 -07001252
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001253 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
Issei Suzuki60557b52019-07-03 20:04:48 +02001254 SurfaceHolder.Callback[] callbacks;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001255 synchronized (mCallbacks) {
1256 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
1257 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001258 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001259 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001260 }
1261
John Reck79925002017-05-26 13:57:14 -07001262 private void runOnUiThread(Runnable runnable) {
1263 Handler handler = getHandler();
1264 if (handler != null && handler.getLooper() != Looper.myLooper()) {
1265 handler.post(runnable);
1266 } else {
1267 runnable.run();
1268 }
1269 }
1270
Yohei Yukawa3b5011a2017-03-16 15:34:12 -07001271 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -04001272 * Check to see if the surface has fixed size dimensions or if the surface's
1273 * dimensions are dimensions are dependent on its current layout.
1274 *
1275 * @return true if the surface has dimensions that are fixed in size
1276 * @hide
1277 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01001278 @UnsupportedAppUsage
Derek Sollenberger7179b812010-03-22 13:41:20 -04001279 public boolean isFixedSize() {
1280 return (mRequestedWidth != -1 || mRequestedHeight != -1);
1281 }
1282
Robert Carrd5c7dd62017-03-08 10:39:30 -08001283 private boolean isAboveParent() {
1284 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001285 }
1286
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001287 /**
1288 * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
1289 * and size of the content hasn't updated yet. This color will fill the expanded area when the
1290 * view becomes larger.
1291 * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
1292 * @hide
1293 */
1294 public void setResizeBackgroundColor(int bgColor) {
Robert Carrb923f542019-05-13 12:27:51 -07001295 if (mBackgroundControl == null) {
1296 return;
1297 }
1298
1299 final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
1300 Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
1301
chaviw619da692019-06-10 15:39:40 -07001302 mTmpTransaction.setColor(mBackgroundControl, colorComponents).apply();
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001303 }
1304
Mathew Inwooda570dee2018-08-17 14:56:00 +01001305 @UnsupportedAppUsage
Igor Murashkina86ab6402013-08-30 12:58:36 -07001306 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001307 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -07001308
1309 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001310 public boolean isCreating() {
1311 return mIsCreating;
1312 }
1313
Igor Murashkina86ab6402013-08-30 12:58:36 -07001314 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001315 public void addCallback(Callback callback) {
1316 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -07001317 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001318 // have only a couple callbacks, so it doesn't matter.
Issei Suzukif0412592019-07-02 12:31:34 +02001319 if (!mCallbacks.contains(callback)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001320 mCallbacks.add(callback);
1321 }
1322 }
1323 }
1324
Igor Murashkina86ab6402013-08-30 12:58:36 -07001325 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001326 public void removeCallback(Callback callback) {
1327 synchronized (mCallbacks) {
1328 mCallbacks.remove(callback);
1329 }
1330 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001331
1332 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001333 public void setFixedSize(int width, int height) {
1334 if (mRequestedWidth != width || mRequestedHeight != height) {
1335 mRequestedWidth = width;
1336 mRequestedHeight = height;
1337 requestLayout();
1338 }
1339 }
1340
Igor Murashkina86ab6402013-08-30 12:58:36 -07001341 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001342 public void setSizeFromLayout() {
1343 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
1344 mRequestedWidth = mRequestedHeight = -1;
1345 requestLayout();
1346 }
1347 }
1348
Igor Murashkina86ab6402013-08-30 12:58:36 -07001349 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001350 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -07001351 // for backward compatibility reason, OPAQUE always
1352 // means 565 for SurfaceView
1353 if (format == PixelFormat.OPAQUE)
1354 format = PixelFormat.RGB_565;
1355
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001356 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001357 if (mSurfaceControl != null) {
1358 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001359 }
1360 }
1361
Mathias Agopiand2112302010-12-07 19:38:17 -08001362 /**
1363 * @deprecated setType is now ignored.
1364 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001365 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -08001366 @Deprecated
1367 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001368
Igor Murashkina86ab6402013-08-30 12:58:36 -07001369 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001370 public void setKeepScreenOn(boolean screenOn) {
John Reck79925002017-05-26 13:57:14 -07001371 runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001372 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001373
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001374 /**
1375 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1376 *
1377 * After drawing into the provided {@link Canvas}, the caller must
1378 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1379 *
1380 * The caller must redraw the entire surface.
1381 * @return A canvas for drawing into the surface.
1382 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001383 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001384 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -07001385 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001386 }
1387
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001388 /**
1389 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1390 *
1391 * After drawing into the provided {@link Canvas}, the caller must
1392 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1393 *
1394 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1395 * to redraw. This function may choose to expand the dirty rectangle if for example
1396 * the surface has been resized or if the previous contents of the surface were
1397 * not available. The caller must redraw the entire dirty region as represented
1398 * by the contents of the inOutDirty rectangle upon return from this function.
1399 * The caller may also pass <code>null</code> instead, in the case where the
1400 * entire surface should be redrawn.
1401 * @return A canvas for drawing into the surface.
1402 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001403 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001404 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -07001405 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001406 }
1407
John Reck6bc70142016-10-26 16:49:17 -07001408 @Override
1409 public Canvas lockHardwareCanvas() {
1410 return internalLockCanvas(null, true);
1411 }
1412
1413 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001414 mSurfaceLock.lock();
1415
John Reckaa6e84f2016-06-16 15:36:13 -07001416 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001417 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001418
1419 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001420 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001421 try {
John Reck6bc70142016-10-26 16:49:17 -07001422 if (hardware) {
1423 c = mSurface.lockHardwareCanvas();
1424 } else {
1425 c = mSurface.lockCanvas(dirty);
1426 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001427 } catch (Exception e) {
1428 Log.e(LOG_TAG, "Exception locking surface", e);
1429 }
1430 }
1431
John Reckaa6e84f2016-06-16 15:36:13 -07001432 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001433 if (c != null) {
1434 mLastLockTime = SystemClock.uptimeMillis();
1435 return c;
1436 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001437
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001438 // If the Surface is not ready to be drawn, then return null,
1439 // but throttle calls to this function so it isn't called more
1440 // than every 100ms.
1441 long now = SystemClock.uptimeMillis();
1442 long nextTime = mLastLockTime + 100;
1443 if (nextTime > now) {
1444 try {
1445 Thread.sleep(nextTime-now);
1446 } catch (InterruptedException e) {
1447 }
1448 now = SystemClock.uptimeMillis();
1449 }
1450 mLastLockTime = now;
1451 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001452
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001453 return null;
1454 }
1455
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001456 /**
1457 * Posts the new contents of the {@link Canvas} to the surface and
1458 * releases the {@link Canvas}.
1459 *
1460 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1461 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001462 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001463 public void unlockCanvasAndPost(Canvas canvas) {
1464 mSurface.unlockCanvasAndPost(canvas);
1465 mSurfaceLock.unlock();
1466 }
1467
Igor Murashkina86ab6402013-08-30 12:58:36 -07001468 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001469 public Surface getSurface() {
1470 return mSurface;
1471 }
1472
Igor Murashkina86ab6402013-08-30 12:58:36 -07001473 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001474 public Rect getSurfaceFrame() {
1475 return mSurfaceFrame;
1476 }
1477 };
Robert Carr55235552017-06-02 14:21:03 -07001478
chaviwff2e7d82018-11-02 11:11:27 -07001479 /**
Robert Carr76907ee2019-01-11 13:38:19 -08001480 * Return a SurfaceControl which can be used for parenting Surfaces to
1481 * this SurfaceView.
1482 *
1483 * @return The SurfaceControl for this SurfaceView.
chaviwff2e7d82018-11-02 11:11:27 -07001484 */
1485 public SurfaceControl getSurfaceControl() {
Robert Carrb923f542019-05-13 12:27:51 -07001486 return mSurfaceControl;
chaviwff2e7d82018-11-02 11:11:27 -07001487 }
Vishnu Nair3b037f72019-07-22 12:55:58 -07001488
1489 /**
Robert Carr87f5d2c2020-01-19 17:27:00 -08001490 * A token used for constructing {@link SurfaceControlViewHost}. This token should
1491 * be passed from the host process to the client process.
1492 *
1493 * @return The token
Vishnu Nair5cf253192019-11-07 15:33:20 -08001494 */
Robert Carr87f5d2c2020-01-19 17:27:00 -08001495 public @Nullable IBinder getHostToken() {
Vishnu Nair5cf253192019-11-07 15:33:20 -08001496 final ViewRootImpl viewRoot = getViewRootImpl();
1497 if (viewRoot == null) {
1498 return null;
1499 }
1500 return viewRoot.getInputToken();
1501 }
1502
1503 /**
Vishnu Nair3b037f72019-07-22 12:55:58 -07001504 * Set window stopped to false and update surface visibility when ViewRootImpl surface is
1505 * created.
1506 * @hide
1507 */
1508 @Override
1509 public void surfaceCreated(SurfaceControl.Transaction t) {
1510 setWindowStopped(false);
1511 }
1512
1513 /**
1514 * Set window stopped to true and update surface visibility when ViewRootImpl surface is
1515 * destroyed.
1516 * @hide
1517 */
1518 @Override
1519 public void surfaceDestroyed() {
1520 setWindowStopped(true);
Jackal Guoac234d62020-02-03 15:05:43 +08001521 setRemoteAccessibilityEmbeddedConnection(null, null);
Vishnu Nair3b037f72019-07-22 12:55:58 -07001522 }
1523
1524 /**
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001525 * Called when a valid ViewRootImpl surface is replaced by another valid surface. In this
1526 * case update relative z to the new parent surface.
Vishnu Nair3b037f72019-07-22 12:55:58 -07001527 * @hide
1528 */
1529 @Override
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001530 public void surfaceReplaced(Transaction t) {
1531 if (mSurfaceControl != null && mBackgroundControl != null) {
chaviw619da692019-06-10 15:39:40 -07001532 updateRelativeZ(t);
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001533 }
1534 }
Vishnu Nair3b037f72019-07-22 12:55:58 -07001535
chaviw619da692019-06-10 15:39:40 -07001536 private void updateRelativeZ(Transaction t) {
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001537 SurfaceControl viewRoot = getViewRootImpl().getSurfaceControl();
1538 t.setRelativeLayer(mBackgroundControl, viewRoot, Integer.MIN_VALUE);
1539 t.setRelativeLayer(mSurfaceControl, viewRoot, mSubLayer);
Vishnu Nair3b037f72019-07-22 12:55:58 -07001540 }
Robert Carr85bb9402019-12-19 01:33:24 -08001541
1542 /**
1543 * @hide
1544 * Note: Base class method is @UnsupportedAppUsage
1545 */
1546 @Override
1547 public void invalidate(boolean invalidateCache) {
1548 super.invalidate(invalidateCache);
Valerie Haubdb905a2020-02-10 15:07:36 -08001549 if (!WindowManagerGlobal.useBLAST()) {
Robert Carr85bb9402019-12-19 01:33:24 -08001550 return;
1551 }
1552 final ViewRootImpl viewRoot = getViewRootImpl();
1553 if (viewRoot == null) return;
1554 viewRoot.setUseBLASTSyncTransaction();
1555 }
Jackal Guo79b182e2019-11-18 11:44:52 +08001556
1557 /**
Robert Carr87f5d2c2020-01-19 17:27:00 -08001558 * Display the view-hierarchy embedded within a {@link SurfaceControlViewHost.SurfacePackage}
1559 * within this SurfaceView. If this SurfaceView is above it's host Surface (see
1560 * {@link #setZOrderOnTop} then the embedded Surface hierarchy will be able to receive
1561 * input.
1562 *
1563 * @param p The SurfacePackage to embed.
Robert Carr30ad6182019-12-18 01:46:04 -08001564 */
Robert Carr30ad6182019-12-18 01:46:04 -08001565 public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
1566 final SurfaceControl sc = p != null ? p.getSurfaceControl() : null;
1567 final SurfaceControl lastSc = mSurfacePackage != null ?
1568 mSurfacePackage.getSurfaceControl() : null;
1569 if (mSurfaceControl != null && lastSc != null) {
1570 mTmpTransaction.reparent(lastSc, null).apply();
1571 } else if (mSurfaceControl != null) {
1572 reparentSurfacePackage(mTmpTransaction, p);
1573 mTmpTransaction.apply();
1574 }
1575 mSurfacePackage = p;
1576 }
1577
1578 private void reparentSurfacePackage(SurfaceControl.Transaction t,
1579 SurfaceControlViewHost.SurfacePackage p) {
Jackal Guoac234d62020-02-03 15:05:43 +08001580 initEmbeddedHierarchyForAccessibility(p);
Robert Carr20c62d22020-02-05 15:25:58 -08001581 final SurfaceControl sc = p.getSurfaceControl();
1582 t.reparent(sc, mSurfaceControl).show(sc);
Robert Carr30ad6182019-12-18 01:46:04 -08001583 }
1584
Jackal Guo79b182e2019-11-18 11:44:52 +08001585 /** @hide */
1586 @Override
1587 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1588 super.onInitializeAccessibilityNodeInfoInternal(info);
Jackal Guoac234d62020-02-03 15:05:43 +08001589 final RemoteAccessibilityEmbeddedConnection wrapper =
1590 getRemoteAccessibilityEmbeddedConnection();
1591 if (wrapper == null) {
Jackal Guo79b182e2019-11-18 11:44:52 +08001592 return;
1593 }
1594 // Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
1595 // leashed child would return the root node in the embedded hierarchy
Jackal Guoac234d62020-02-03 15:05:43 +08001596 info.addChild(wrapper.getLeashToken());
1597 }
1598
1599 private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
1600 final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
1601 final RemoteAccessibilityEmbeddedConnection wrapper =
1602 getRemoteAccessibilityEmbeddedConnection();
1603
1604 // Do nothing if package is embedding the same view hierarchy.
1605 if (wrapper != null && wrapper.getConnection().equals(connection)) {
1606 return;
1607 }
1608
1609 // If this SurfaceView embeds a different view hierarchy, unlink the previous one first.
1610 setRemoteAccessibilityEmbeddedConnection(null, null);
1611
1612 try {
1613 final IBinder leashToken = connection.associateEmbeddedHierarchy(
1614 getViewRootImpl().mLeashToken, getAccessibilityViewId());
1615 setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
1616 } catch (RemoteException e) {
1617 Log.d(TAG, "Error while associateEmbeddedHierarchy " + e);
1618 }
1619 updateScreenMatrixForEmbeddedHierarchy();
1620 }
1621
1622 private void setRemoteAccessibilityEmbeddedConnection(
1623 IAccessibilityEmbeddedConnection connection, IBinder leashToken) {
1624 try {
1625 if (mRemoteAccessibilityEmbeddedConnection != null) {
1626 mRemoteAccessibilityEmbeddedConnection.getConnection()
1627 .disassociateEmbeddedHierarchy();
1628 mRemoteAccessibilityEmbeddedConnection.unlinkToDeath();
1629 mRemoteAccessibilityEmbeddedConnection = null;
1630 }
1631 if (connection != null && leashToken != null) {
1632 mRemoteAccessibilityEmbeddedConnection =
1633 new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
1634 mRemoteAccessibilityEmbeddedConnection.linkToDeath();
1635 }
1636 } catch (RemoteException e) {
1637 Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e);
1638 }
1639 }
1640
1641 private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
1642 return mRemoteAccessibilityEmbeddedConnection;
1643 }
1644
1645 private void updateScreenMatrixForEmbeddedHierarchy() {
Jackal Guoef364c52020-02-14 15:38:39 +08001646 getBoundsOnScreen(mTmpRect, true);
Jackal Guoac234d62020-02-03 15:05:43 +08001647 mTmpMatrix.reset();
Jackal Guoef364c52020-02-14 15:38:39 +08001648 mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
Jackal Guoac234d62020-02-03 15:05:43 +08001649 mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
1650 mScreenRect.height() / (float) mSurfaceHeight);
1651
1652 // If the screen matrix is identity or doesn't change, do nothing.
1653 if (mTmpMatrix.isIdentity() || mTmpMatrix.equals(mScreenMatrixForEmbeddedHierarchy)) {
1654 return;
1655 }
1656
1657 try {
1658 final RemoteAccessibilityEmbeddedConnection wrapper =
1659 getRemoteAccessibilityEmbeddedConnection();
1660 if (wrapper == null) {
1661 return;
1662 }
1663 mTmpMatrix.getValues(mMatrixValues);
1664 wrapper.getConnection().setScreenMatrix(mMatrixValues);
1665 mScreenMatrixForEmbeddedHierarchy.set(mTmpMatrix);
1666 } catch (RemoteException e) {
1667 Log.d(TAG, "Error while setScreenMatrix " + e);
1668 }
1669 }
1670
1671 /**
1672 * Wrapper of accessibility embedded connection for embedded view hierarchy.
1673 */
1674 private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
1675 private final IAccessibilityEmbeddedConnection mConnection;
1676 private final IBinder mLeashToken;
1677
1678 RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
1679 IBinder leashToken) {
1680 mConnection = connection;
1681 mLeashToken = leashToken;
1682 }
1683
1684 IAccessibilityEmbeddedConnection getConnection() {
1685 return mConnection;
1686 }
1687
1688 IBinder getLeashToken() {
1689 return mLeashToken;
1690 }
1691
1692 void linkToDeath() throws RemoteException {
1693 mConnection.asBinder().linkToDeath(this, 0);
1694 }
1695
1696 void unlinkToDeath() {
1697 mConnection.asBinder().unlinkToDeath(this, 0);
1698 }
1699
1700 @Override
1701 public void binderDied() {
1702 unlinkToDeath();
1703 runOnUiThread(() -> {
1704 if (mRemoteAccessibilityEmbeddedConnection == this) {
1705 mRemoteAccessibilityEmbeddedConnection = null;
1706 }
1707 });
1708 }
Jackal Guo79b182e2019-11-18 11:44:52 +08001709 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001710}