blob: 0d21eb5cf920a7357b902dce3393593be27521cd [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;
Valerie Hau779af292020-02-07 10:53:32 -080047import android.view.accessibility.AccessibilityNodeInfo;
Jackal Guoac234d62020-02-03 15:05:43 +080048import android.view.accessibility.IAccessibilityEmbeddedConnection;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070049
Robert Carr25cfa132016-11-16 13:24:09 -080050import com.android.internal.view.SurfaceCallbackHelper;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070051
Jon Larimer9bdf5762009-01-02 18:55:15 -050052import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070053import java.util.concurrent.locks.ReentrantLock;
54
55/**
56 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
57 * You can control the format of this surface and, if you like, its size; the
58 * SurfaceView takes care of placing the surface at the correct location on the
59 * screen
Igor Murashkina86ab6402013-08-30 12:58:36 -070060 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070061 * <p>The surface is Z ordered so that it is behind the window holding its
62 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070063 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070064 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070065 * 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 -070066 * buttons on top of the Surface, though note however that it can have an
67 * impact on performance since a full alpha-blended composite will be performed
68 * each time the Surface changes.
Igor Murashkina86ab6402013-08-30 12:58:36 -070069 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070070 * <p> The transparent region that makes the surface visible is based on the
71 * layout positions in the view hierarchy. If the post-layout transform
72 * properties are used to draw a sibling view on top of the SurfaceView, the
73 * view may not be properly composited with the surface.
74 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070075 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
76 * which can be retrieved by calling {@link #getHolder}.
Igor Murashkina86ab6402013-08-30 12:58:36 -070077 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070078 * <p>The Surface will be created for you while the SurfaceView's window is
79 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
80 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
81 * Surface is created and destroyed as the window is shown and hidden.
Igor Murashkina86ab6402013-08-30 12:58:36 -070082 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070083 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070084 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070085 * this way, you need to be aware of some threading semantics:
Igor Murashkina86ab6402013-08-30 12:58:36 -070086 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070087 * <ul>
88 * <li> All SurfaceView and
89 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
90 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070091 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070092 * state that is also touched by the drawing thread.
93 * <li> You must ensure that the drawing thread only touches the underlying
94 * Surface while it is valid -- between
95 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
96 * and
97 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
98 * </ul>
Chris Craik6ee192f2016-05-17 14:29:10 -070099 *
100 * <p class="note"><strong>Note:</strong> Starting in platform version
101 * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
102 * updated synchronously with other View rendering. This means that translating
103 * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
104 * artifacts may occur on previous versions of the platform when its window is
105 * positioned asynchronously.</p>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700106 */
Vishnu Nair3b037f72019-07-22 12:55:58 -0700107public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800108 private static final String TAG = "SurfaceView";
109 private static final boolean DEBUG = false;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200110 private static final boolean DEBUG_POSITION = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700111
Mathew Inwooda570dee2018-08-17 14:56:00 +0100112 @UnsupportedAppUsage
Issei Suzukif0412592019-07-02 12:31:34 +0200113 final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<>();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700114
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800115 final int[] mLocation = new int[2];
Igor Murashkina86ab6402013-08-30 12:58:36 -0700116
Mathew Inwooda570dee2018-08-17 14:56:00 +0100117 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700118 final ReentrantLock mSurfaceLock = new ReentrantLock();
Mathew Inwooda570dee2018-08-17 14:56:00 +0100119 @UnsupportedAppUsage
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800120 final Surface mSurface = new Surface(); // Current surface in use
Mathew Inwood31755f92018-12-20 13:53:36 +0000121 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700122 boolean mDrawingStopped = true;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800123 // We use this to track if the application has produced a frame
124 // in to the Surface. Up until that point, we should be careful not to punch
125 // holes.
126 boolean mDrawFinished = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700127
Robert Carrd5c7dd62017-03-08 10:39:30 -0800128 final Rect mScreenRect = new Rect();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700129 private final SurfaceSession mSurfaceSession = new SurfaceSession();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800130
Robert Carrb923f542019-05-13 12:27:51 -0700131 SurfaceControl mSurfaceControl;
Robert Carr3bc95b52017-03-20 21:57:23 -0700132 // In the case of format changes we switch out the surface in-place
133 // we need to preserve the old one until the new one has drawn.
Robert Carrb923f542019-05-13 12:27:51 -0700134 SurfaceControl mDeferredDestroySurfaceControl;
135 SurfaceControl mBackgroundControl;
shawnlinba532af2020-06-02 17:48:37 +0800136 private boolean mDisableBackgroundLayer = false;
Robert Carrebaaca12020-05-13 11:23:43 -0700137
138 /**
139 * We use this lock in SOME cases when reading or writing SurfaceControl,
140 * but use the following model so that the RenderThread can run locklessly
141 * in the position up-date case.
142 *
143 * 1. UI Thread can read from mSurfaceControl (use in Transactions) without
144 * holding the lock.
145 * 2. UI Thread will hold the lock when writing to mSurfaceControl (calling release
146 * or remove).
147 * 3. Render thread will also hold the lock when writing to mSurfaceControl (e.g.
148 * calling release from positionLost).
149 * 3. RenderNode.PositionUpdateListener::positionChanged will only be called
150 * when the UI thread is paused (blocked on the Render thread).
151 * 4. positionChanged thus will not be required to hold the lock as the
152 * UI thread is blocked, and the other writer is the RT itself.
153 */
Issei Suzuki006b71f2019-06-17 15:56:57 +0200154 final Object mSurfaceControlLock = new Object();
Robert Carr33879132016-09-06 14:41:40 -0700155 final Rect mTmpRect = new Rect();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700156
Mark Renouf34d04f32019-05-13 15:53:18 -0400157 Paint mRoundedViewportPaint;
158
Robert Carrd5c7dd62017-03-08 10:39:30 -0800159 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700160
Mathew Inwood31755f92018-12-20 13:53:36 +0000161 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700162 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700163 private volatile boolean mRtHandlingPositionUpdates = false;
Robert Carr005c63e2019-09-20 14:31:24 -0700164 private volatile boolean mRtReleaseSurfaces = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700165
Issei Suzukif0412592019-07-02 12:31:34 +0200166 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener =
167 this::updateSurface;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700168
Mathew Inwooda570dee2018-08-17 14:56:00 +0100169 @UnsupportedAppUsage
Issei Suzukif0412592019-07-02 12:31:34 +0200170 private final ViewTreeObserver.OnPreDrawListener mDrawListener = () -> {
171 // reposition ourselves where the surface is
172 mHaveFrame = getWidth() > 0 && getHeight() > 0;
173 updateSurface();
174 return true;
175 };
John Reckf6481082016-02-02 15:18:23 -0800176
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700177 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700178 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800179 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700180 boolean mViewVisibility = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700181 boolean mWindowStopped = false;
182
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 int mRequestedWidth = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000185 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700186 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700187 /* Set SurfaceView's format to 565 by default to maintain backward
188 * compatibility with applications assuming this format.
189 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100190 @UnsupportedAppUsage
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700191 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700192
Issei Suzuki006b71f2019-06-17 15:56:57 +0200193 boolean mUseAlpha = false;
194 float mSurfaceAlpha = 1f;
Mark Renoufe574ad02019-08-12 16:22:15 -0400195 boolean mClipSurfaceToBounds;
Winson Chungd4a9abd2020-03-21 23:01:16 -0700196 int mBackgroundColor = Color.BLACK;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200197
Mathew Inwooda570dee2018-08-17 14:56:00 +0100198 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700199 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800200 boolean mSurfaceCreated = false;
Mathew Inwood31755f92018-12-20 13:53:36 +0000201 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700202 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700203
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700204 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800205 int mWindowSpaceLeft = -1;
206 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800207 int mSurfaceWidth = -1;
208 int mSurfaceHeight = -1;
Mark Renouf34d04f32019-05-13 15:53:18 -0400209 float mCornerRadius;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100210 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700211 int mFormat = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000212 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700213 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700214 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Romain Guyf2499fa2011-01-26 18:31:23 -0800215
Romain Guy01d5edc2011-01-28 11:28:53 -0800216 private boolean mGlobalListenersAdded;
Robert Carr8508bb22017-03-27 15:46:27 -0700217 private boolean mAttachedToWindow;
Romain Guyf2499fa2011-01-26 18:31:23 -0800218
Robert Carrd5c7dd62017-03-08 10:39:30 -0800219 private int mSurfaceFlags = SurfaceControl.HIDDEN;
220
Robert Carr8508bb22017-03-27 15:46:27 -0700221 private int mPendingReportDraws;
222
Robert Carr27a800a2018-03-16 13:33:45 -0700223 private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
chaviw9f6171e2019-06-07 16:33:50 -0700224 private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700225 private int mParentSurfaceGenerationId;
Robert Carr27a800a2018-03-16 13:33:45 -0700226
Jackal Guoac234d62020-02-03 15:05:43 +0800227 private RemoteAccessibilityEmbeddedConnection mRemoteAccessibilityEmbeddedConnection;
228
229 private final Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
230 private final Matrix mTmpMatrix = new Matrix();
231 private final float[] mMatrixValues = new float[9];
232
Robert Carr30ad6182019-12-18 01:46:04 -0800233 SurfaceControlViewHost.SurfacePackage mSurfacePackage;
Jackal Guo79b182e2019-11-18 11:44:52 +0800234
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700235 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400236 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700237 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700238
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700239 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400240 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700241 }
242
Alan Viverette617feb92013-09-09 18:09:13 -0700243 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400244 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700245 }
246
247 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
shawnlinba532af2020-06-02 17:48:37 +0800248 this(context, attrs, defStyleAttr, defStyleRes, false);
249 }
250
251 /** @hide */
252 public SurfaceView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
253 int defStyleRes, boolean disableBackgroundLayer) {
Alan Viverette617feb92013-09-09 18:09:13 -0700254 super(context, attrs, defStyleAttr, defStyleRes);
Adam Powell769b8632019-02-04 11:28:22 -0800255 mRenderNode.addPositionUpdateListener(mPositionListener);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700256
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700257 setWillNotDraw(true);
shawnlinba532af2020-06-02 17:48:37 +0800258 mDisableBackgroundLayer = disableBackgroundLayer;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700259 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700260
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700261 /**
262 * Return the SurfaceHolder providing access and control over this
263 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700264 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700265 * @return SurfaceHolder The holder of the surface.
266 */
267 public SurfaceHolder getHolder() {
268 return mSurfaceHolder;
269 }
270
Robert Carr414ebc62017-04-12 12:01:00 -0700271 private void updateRequestedVisibility() {
272 mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
273 }
274
Vishnu Nair3b037f72019-07-22 12:55:58 -0700275 private void setWindowStopped(boolean stopped) {
Robert Carr414ebc62017-04-12 12:01:00 -0700276 mWindowStopped = stopped;
277 updateRequestedVisibility();
278 updateSurface();
279 }
280
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700281 @Override
282 protected void onAttachedToWindow() {
283 super.onAttachedToWindow();
Robert Carr414ebc62017-04-12 12:01:00 -0700284
Vishnu Nair3b037f72019-07-22 12:55:58 -0700285 getViewRootImpl().addSurfaceChangedCallback(this);
Robert Carr00177cc2017-05-15 15:49:17 -0700286 mWindowStopped = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700287
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700288 mViewVisibility = getVisibility() == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700289 updateRequestedVisibility();
Romain Guy01d5edc2011-01-28 11:28:53 -0800290
Robert Carr8508bb22017-03-27 15:46:27 -0700291 mAttachedToWindow = true;
Karthik Ravi Shankara59c3a52017-09-11 17:36:25 -0700292 mParent.requestTransparentRegion(SurfaceView.this);
Romain Guy01d5edc2011-01-28 11:28:53 -0800293 if (!mGlobalListenersAdded) {
294 ViewTreeObserver observer = getViewTreeObserver();
295 observer.addOnScrollChangedListener(mScrollChangedListener);
296 observer.addOnPreDrawListener(mDrawListener);
297 mGlobalListenersAdded = true;
298 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700299 }
300
301 @Override
302 protected void onWindowVisibilityChanged(int visibility) {
303 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700304 mWindowVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700305 updateRequestedVisibility();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800306 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700307 }
308
309 @Override
310 public void setVisibility(int visibility) {
311 super.setVisibility(visibility);
312 mViewVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700313 boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700314 if (newRequestedVisible != mRequestedVisible) {
315 // our base class (View) invalidates the layout only when
316 // we go from/to the GONE state. However, SurfaceView needs
317 // to request a re-layout when the visibility changes at all.
318 // This is needed because the transparent region is computed
319 // as part of the layout phase, and it changes (obviously) when
320 // the visibility changes.
321 requestLayout();
322 }
323 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800324 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700325 }
Romain Guyafc3e112010-06-07 17:04:33 -0700326
Issei Suzuki006b71f2019-06-17 15:56:57 +0200327 /**
328 * Make alpha value of this view reflect onto the surface. This can only be called from at most
329 * one SurfaceView within a view tree.
330 *
331 * <p class="note"><strong>Note:</strong> Alpha value of the view is ignored and the underlying
332 * surface is rendered opaque by default.</p>
333 *
334 * @hide
335 */
336 public void setUseAlpha() {
337 if (!mUseAlpha) {
338 mUseAlpha = true;
339 updateSurfaceAlpha();
340 }
341 }
342
343 @Override
344 public void setAlpha(float alpha) {
345 // Sets the opacity of the view to a value, where 0 means the view is completely transparent
346 // and 1 means the view is completely opaque.
347 //
348 // Note: Alpha value of this view is ignored by default. To enable alpha blending, you need
349 // to call setUseAlpha() as well.
350 // This view doesn't support translucent opacity if the view is located z-below, since the
351 // logic to punch a hole in the view hierarchy cannot handle such case. See also
352 // #clearSurfaceViewPort(Canvas)
353 if (DEBUG) {
354 Log.d(TAG, System.identityHashCode(this)
355 + " setAlpha: mUseAlpha = " + mUseAlpha + " alpha=" + alpha);
356 }
357 super.setAlpha(alpha);
358 updateSurfaceAlpha();
359 }
360
361 private float getFixedAlpha() {
362 // Compute alpha value to be set on the underlying surface.
363 final float alpha = getAlpha();
364 return mUseAlpha && (mSubLayer > 0 || alpha == 0f) ? alpha : 1f;
365 }
366
367 private void updateSurfaceAlpha() {
368 if (!mUseAlpha) {
369 if (DEBUG) {
370 Log.d(TAG, System.identityHashCode(this)
371 + " updateSurfaceAlpha: setUseAlpha() is not called, ignored.");
372 }
373 return;
374 }
375 final float viewAlpha = getAlpha();
376 if (mSubLayer < 0 && 0f < viewAlpha && viewAlpha < 1f) {
377 Log.w(TAG, System.identityHashCode(this)
378 + " updateSurfaceAlpha:"
379 + " translucent color is not supported for a surface placed z-below.");
380 }
381 if (!mHaveFrame) {
382 if (DEBUG) {
383 Log.d(TAG, System.identityHashCode(this)
384 + " updateSurfaceAlpha: has no surface.");
385 }
386 return;
387 }
388 final ViewRootImpl viewRoot = getViewRootImpl();
389 if (viewRoot == null) {
390 if (DEBUG) {
391 Log.d(TAG, System.identityHashCode(this)
392 + " updateSurfaceAlpha: ViewRootImpl not available.");
393 }
394 return;
395 }
396 if (mSurfaceControl == null) {
397 if (DEBUG) {
398 Log.d(TAG, System.identityHashCode(this)
399 + "updateSurfaceAlpha:"
400 + " surface is not yet created, or already released.");
401 }
402 return;
403 }
404 final Surface parent = viewRoot.mSurface;
405 if (parent == null || !parent.isValid()) {
406 if (DEBUG) {
407 Log.d(TAG, System.identityHashCode(this)
408 + " updateSurfaceAlpha: ViewRootImpl has no valid surface");
409 }
410 return;
411 }
412 final float alpha = getFixedAlpha();
413 if (alpha != mSurfaceAlpha) {
414 if (isHardwareAccelerated()) {
415 /*
416 * Schedule a callback that reflects an alpha value onto the underlying surfaces.
417 * This gets called on a RenderThread worker thread, so members accessed here must
418 * be protected by a lock.
419 */
Robert Carr6d16c8c2020-02-21 12:04:31 -0800420 final boolean useBLAST = viewRoot.useBLAST();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200421 viewRoot.registerRtFrameCallback(frame -> {
422 try {
Robert Carr85bb9402019-12-19 01:33:24 -0800423 final SurfaceControl.Transaction t = useBLAST ?
424 viewRoot.getBLASTSyncTransaction() : new SurfaceControl.Transaction();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200425 synchronized (mSurfaceControlLock) {
426 if (!parent.isValid()) {
427 if (DEBUG) {
428 Log.d(TAG, System.identityHashCode(this)
429 + " updateSurfaceAlpha RT:"
430 + " ViewRootImpl has no valid surface");
431 }
432 return;
433 }
434 if (mSurfaceControl == null) {
435 if (DEBUG) {
436 Log.d(TAG, System.identityHashCode(this)
437 + "updateSurfaceAlpha RT:"
438 + " mSurfaceControl has already released");
439 }
440 return;
441 }
442 if (DEBUG) {
443 Log.d(TAG, System.identityHashCode(this)
444 + " updateSurfaceAlpha RT: set alpha=" + alpha);
445 }
446 t.setAlpha(mSurfaceControl, alpha);
Robert Carr85bb9402019-12-19 01:33:24 -0800447 if (!useBLAST) {
Robert Carrcef9a282020-01-14 09:08:05 -0800448 t.deferTransactionUntil(mSurfaceControl,
449 viewRoot.getRenderSurfaceControl(), frame);
Robert Carr85bb9402019-12-19 01:33:24 -0800450 }
Issei Suzuki006b71f2019-06-17 15:56:57 +0200451 }
452 // It's possible that mSurfaceControl is released in the UI thread before
453 // the transaction completes. If that happens, an exception is thrown, which
454 // must be caught immediately.
455 t.apply();
456 } catch (Exception e) {
457 Log.e(TAG, System.identityHashCode(this)
458 + "updateSurfaceAlpha RT: Exception during surface transaction", e);
459 }
460 });
461 damageInParent();
462 } else {
463 if (DEBUG) {
464 Log.d(TAG, System.identityHashCode(this)
465 + " updateSurfaceAlpha: set alpha=" + alpha);
466 }
chaviw619da692019-06-10 15:39:40 -0700467 mTmpTransaction.setAlpha(mSurfaceControl, alpha).apply();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200468 }
469 mSurfaceAlpha = alpha;
470 }
471 }
472
Robert Carrb53670a2017-05-25 18:20:49 -0700473 private void performDrawFinished() {
474 if (mPendingReportDraws > 0) {
475 mDrawFinished = true;
476 if (mAttachedToWindow) {
Pengfei Zhao15617202019-02-28 17:07:41 +0800477 mParent.requestTransparentRegion(SurfaceView.this);
Robert Carrb53670a2017-05-25 18:20:49 -0700478 notifyDrawFinished();
479 invalidate();
480 }
481 } else {
482 Log.e(TAG, System.identityHashCode(this) + "finished drawing"
483 + " but no pending report draw (extra call"
484 + " to draw completion runnable?)");
485 }
486 }
487
Robert Carr8508bb22017-03-27 15:46:27 -0700488 void notifyDrawFinished() {
489 ViewRootImpl viewRoot = getViewRootImpl();
490 if (viewRoot != null) {
491 viewRoot.pendingDrawFinished();
492 }
493 mPendingReportDraws--;
494 }
495
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700496 @Override
John Reck77e4a522014-10-01 10:38:07 -0700497 protected void onDetachedFromWindow() {
Lucas Dupin0c207342017-04-14 19:47:23 -0700498 ViewRootImpl viewRoot = getViewRootImpl();
499 // It's possible to create a SurfaceView using the default constructor and never
500 // attach it to a view hierarchy, this is a common use case when dealing with
501 // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
502 // the lifecycle. Instead of attaching it to a view, he/she can just pass
503 // the SurfaceHolder forward, most live wallpapers do it.
504 if (viewRoot != null) {
Vishnu Nair3b037f72019-07-22 12:55:58 -0700505 viewRoot.removeSurfaceChangedCallback(this);
Lucas Dupin0c207342017-04-14 19:47:23 -0700506 }
Robert Carr414ebc62017-04-12 12:01:00 -0700507
Robert Carr8508bb22017-03-27 15:46:27 -0700508 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800509 if (mGlobalListenersAdded) {
510 ViewTreeObserver observer = getViewTreeObserver();
511 observer.removeOnScrollChangedListener(mScrollChangedListener);
512 observer.removeOnPreDrawListener(mDrawListener);
513 mGlobalListenersAdded = false;
514 }
515
Robert Carr8508bb22017-03-27 15:46:27 -0700516 while (mPendingReportDraws > 0) {
517 notifyDrawFinished();
518 }
519
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700520 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800521
Robert Carrd5c7dd62017-03-08 10:39:30 -0800522 updateSurface();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200523 releaseSurfaces();
Robert Carr414ebc62017-04-12 12:01:00 -0700524
Robert Carr5af7d622020-03-17 12:04:20 -0700525 // We don't release this as part of releaseSurfaces as
526 // that is also called on transient visibility changes. We can't
527 // recreate this Surface, so only release it when we are fully
528 // detached.
529 if (mSurfacePackage != null) {
530 mSurfacePackage.release();
531 mSurfacePackage = null;
532 }
533
534 mHaveFrame = false;
John Reck77e4a522014-10-01 10:38:07 -0700535 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700536 }
537
538 @Override
539 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800540 int width = mRequestedWidth >= 0
541 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
542 : getDefaultSize(0, widthMeasureSpec);
543 int height = mRequestedHeight >= 0
544 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
545 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700546 setMeasuredDimension(width, height);
547 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700548
Mathias Agopianef115302010-10-04 20:15:08 -0700549 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700550 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100551 @UnsupportedAppUsage
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700552 protected boolean setFrame(int left, int top, int right, int bottom) {
553 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800554 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700555 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700556 }
557
558 @Override
559 public boolean gatherTransparentRegion(Region region) {
Robert Carr3ca12be72017-05-22 14:57:48 -0700560 if (isAboveParent() || !mDrawFinished) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700561 return super.gatherTransparentRegion(region);
562 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700563
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700564 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700565 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700566 // this view draws, remove it from the transparent region
567 opaque = super.gatherTransparentRegion(region);
568 } else if (region != null) {
569 int w = getWidth();
570 int h = getHeight();
571 if (w>0 && h>0) {
572 getLocationInWindow(mLocation);
573 // otherwise, punch a hole in the whole hierarchy
574 int l = mLocation[0];
575 int t = mLocation[1];
576 region.op(l, t, l+w, t+h, Region.Op.UNION);
577 }
578 }
579 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
580 opaque = false;
581 }
582 return opaque;
583 }
584
585 @Override
586 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800587 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700588 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700589 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700590 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400591 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700592 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700593 }
594 super.draw(canvas);
595 }
596
597 @Override
598 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800599 if (mDrawFinished && !isAboveParent()) {
600 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700601 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700602 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400603 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700604 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700605 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700606 super.dispatchDraw(canvas);
607 }
608
Mark Renoufe574ad02019-08-12 16:22:15 -0400609 /**
610 * Control whether the surface is clipped to the same bounds as the View. If true, then
611 * the bounds set by {@link #setClipBounds(Rect)} are applied to the surface as window-crop.
612 *
613 * @param enabled whether to enable surface clipping
614 * @hide
615 */
616 public void setEnableSurfaceClipping(boolean enabled) {
617 mClipSurfaceToBounds = enabled;
618 invalidate();
619 }
620
621 @Override
622 public void setClipBounds(Rect clipBounds) {
623 super.setClipBounds(clipBounds);
624
625 if (!mClipSurfaceToBounds) {
626 return;
627 }
628
629 // When cornerRadius is non-zero, a draw() is required to update
630 // the viewport (rounding the corners of the clipBounds).
631 if (mCornerRadius > 0f && !isAboveParent()) {
632 invalidate();
633 }
634
635 if (mSurfaceControl != null) {
636 if (mClipBounds != null) {
637 mTmpRect.set(mClipBounds);
638 } else {
639 mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
640 }
641 SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this);
Vishnu Nair2ed39d82020-06-17 15:43:13 -0700642 applier.scheduleApply(
Mark Renoufe574ad02019-08-12 16:22:15 -0400643 new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl)
644 .withWindowCrop(mTmpRect)
645 .build());
646 }
647 }
648
Mark Renouf34d04f32019-05-13 15:53:18 -0400649 private void clearSurfaceViewPort(Canvas canvas) {
650 if (mCornerRadius > 0f) {
651 canvas.getClipBounds(mTmpRect);
Mark Renoufe574ad02019-08-12 16:22:15 -0400652 if (mClipSurfaceToBounds && mClipBounds != null) {
653 mTmpRect.intersect(mClipBounds);
654 }
Mark Renouf34d04f32019-05-13 15:53:18 -0400655 canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
656 mCornerRadius, mCornerRadius, mRoundedViewportPaint);
657 } else {
658 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
659 }
660 }
661
662 /**
663 * Sets the corner radius for the SurfaceView. This will round both the corners of the
664 * underlying surface, as well as the corners of the hole created to expose the surface.
665 *
666 * @param cornerRadius the new radius of the corners in pixels
667 * @hide
668 */
669 public void setCornerRadius(float cornerRadius) {
670 mCornerRadius = cornerRadius;
671 if (mCornerRadius > 0f && mRoundedViewportPaint == null) {
672 mRoundedViewportPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
673 mRoundedViewportPaint.setBlendMode(BlendMode.CLEAR);
674 mRoundedViewportPaint.setColor(0);
675 }
676 invalidate();
677 }
678
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700679 /**
Mark Renoufe574ad02019-08-12 16:22:15 -0400680 * Returns the corner radius for the SurfaceView.
681
682 * @return the radius of the corners in pixels
683 * @hide
684 */
685 public float getCornerRadius() {
686 return mCornerRadius;
687 }
688
689 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700690 * Control whether the surface view's surface is placed on top of another
691 * regular surface view in the window (but still behind the window itself).
692 * This is typically used to place overlays on top of an underlying media
693 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700694 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700695 * <p>Note that this must be set before the surface view's containing
696 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700697 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700698 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
699 */
700 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800701 mSubLayer = isMediaOverlay
702 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700703 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700704
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700705 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700706 * Control whether the surface view's surface is placed on top of its
707 * window. Normally it is placed behind the window, to allow it to
708 * (for the most part) appear to composite with the views in the
709 * hierarchy. By setting this, you cause it to be placed above the
710 * window. This means that none of the contents of the window this
711 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700712 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700713 * <p>Note that this must be set before the surface view's containing
Svet Ganova57dadd2020-03-18 23:30:16 -0700714 * window is attached to the window manager. If you target {@link Build.VERSION_CODES#R}
715 * the Z ordering can be changed dynamically if the backing surface is
716 * created, otherwise it would be applied at surface construction time.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700717 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700718 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Svet Ganova57dadd2020-03-18 23:30:16 -0700719 *
720 * @param onTop Whether to show the surface on top of this view's window.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700721 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700722 public void setZOrderOnTop(boolean onTop) {
Svet Ganova57dadd2020-03-18 23:30:16 -0700723 // In R and above we allow dynamic layer changes.
724 final boolean allowDynamicChange = getContext().getApplicationInfo().targetSdkVersion
725 > Build.VERSION_CODES.Q;
726 setZOrderedOnTop(onTop, allowDynamicChange);
727 }
728
729 /**
730 * @return Whether the surface backing this view appears on top of its parent.
731 *
732 * @hide
733 */
734 public boolean isZOrderedOnTop() {
735 return mSubLayer > 0;
736 }
737
738 /**
739 * Controls whether the surface view's surface is placed on top of its
740 * window. Normally it is placed behind the window, to allow it to
741 * (for the most part) appear to composite with the views in the
742 * hierarchy. By setting this, you cause it to be placed above the
743 * window. This means that none of the contents of the window this
744 * SurfaceView is in will be visible on top of its surface.
745 *
746 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
747 *
748 * @param onTop Whether to show the surface on top of this view's window.
749 * @param allowDynamicChange Whether this can happen after the surface is created.
750 * @return Whether the Z ordering changed.
751 *
752 * @hide
753 */
754 public boolean setZOrderedOnTop(boolean onTop, boolean allowDynamicChange) {
755 final int subLayer;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500756 if (onTop) {
Svet Ganova57dadd2020-03-18 23:30:16 -0700757 subLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500758 } else {
Svet Ganova57dadd2020-03-18 23:30:16 -0700759 subLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500760 }
Svet Ganova57dadd2020-03-18 23:30:16 -0700761 if (mSubLayer == subLayer) {
762 return false;
763 }
764 mSubLayer = subLayer;
765
766 if (!allowDynamicChange) {
767 return false;
768 }
769 if (mSurfaceControl == null) {
770 return true;
771 }
772 final ViewRootImpl viewRoot = getViewRootImpl();
773 if (viewRoot == null) {
774 return true;
775 }
776 final Surface parent = viewRoot.mSurface;
777 if (parent == null || !parent.isValid()) {
778 return true;
779 }
780
781 /*
782 * Schedule a callback that reflects an alpha value onto the underlying surfaces.
783 * This gets called on a RenderThread worker thread, so members accessed here must
784 * be protected by a lock.
785 */
786 final boolean useBLAST = viewRoot.useBLAST();
787 viewRoot.registerRtFrameCallback(frame -> {
788 try {
789 final SurfaceControl.Transaction t = useBLAST
790 ? viewRoot.getBLASTSyncTransaction()
791 : new SurfaceControl.Transaction();
792 synchronized (mSurfaceControlLock) {
793 if (!parent.isValid() || mSurfaceControl == null) {
794 return;
795 }
796 updateRelativeZ(t);
797 if (!useBLAST) {
798 t.deferTransactionUntil(mSurfaceControl,
799 viewRoot.getRenderSurfaceControl(), frame);
800 }
801 }
802 // It's possible that mSurfaceControl is released in the UI thread before
803 // the transaction completes. If that happens, an exception is thrown, which
804 // must be caught immediately.
805 t.apply();
806 } catch (Exception e) {
807 Log.e(TAG, System.identityHashCode(this)
808 + "setZOrderOnTop RT: Exception during surface transaction", e);
809 }
810 });
811
812 invalidate();
813
814 return true;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700815 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700816
817 /**
818 * Control whether the surface view's content should be treated as secure,
819 * preventing it from appearing in screenshots or from being viewed on
820 * non-secure displays.
821 *
822 * <p>Note that this must be set before the surface view's containing
823 * window is attached to the window manager.
824 *
825 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
826 *
827 * @param isSecure True if the surface view is secure.
828 */
829 public void setSecure(boolean isSecure) {
830 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800831 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700832 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800833 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700834 }
835 }
836
Robert Carr55235552017-06-02 14:21:03 -0700837 private void updateOpaqueFlag() {
Robert Carr851e7e42017-06-06 14:04:50 -0700838 if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
Robert Carr55235552017-06-02 14:21:03 -0700839 mSurfaceFlags |= SurfaceControl.OPAQUE;
840 } else {
841 mSurfaceFlags &= ~SurfaceControl.OPAQUE;
842 }
843 }
844
chaviw619da692019-06-10 15:39:40 -0700845 private void updateBackgroundVisibility(Transaction t) {
Robert Carrb923f542019-05-13 12:27:51 -0700846 if (mBackgroundControl == null) {
847 return;
848 }
shawnlinba532af2020-06-02 17:48:37 +0800849 if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
850 && !mDisableBackgroundLayer) {
chaviw619da692019-06-10 15:39:40 -0700851 t.show(mBackgroundControl);
Robert Carrb923f542019-05-13 12:27:51 -0700852 } else {
chaviw619da692019-06-10 15:39:40 -0700853 t.hide(mBackgroundControl);
Robert Carrb923f542019-05-13 12:27:51 -0700854 }
855 }
856
Winson Chungd4a9abd2020-03-21 23:01:16 -0700857 private Transaction updateBackgroundColor(Transaction t) {
858 final float[] colorComponents = new float[] { Color.red(mBackgroundColor) / 255.f,
859 Color.green(mBackgroundColor) / 255.f, Color.blue(mBackgroundColor) / 255.f };
860 t.setColor(mBackgroundControl, colorComponents);
861 return t;
862 }
chaviw619da692019-06-10 15:39:40 -0700863
Robert Carrb923f542019-05-13 12:27:51 -0700864 private void releaseSurfaces() {
Robert Carr005c63e2019-09-20 14:31:24 -0700865 mSurfaceAlpha = 1f;
866
Issei Suzuki006b71f2019-06-17 15:56:57 +0200867 synchronized (mSurfaceControlLock) {
Robert Carrde63cc62019-10-25 13:18:29 -0700868 mSurface.release();
869
Robert Carr005c63e2019-09-20 14:31:24 -0700870 if (mRtHandlingPositionUpdates) {
871 mRtReleaseSurfaces = true;
872 return;
873 }
874
Issei Suzuki006b71f2019-06-17 15:56:57 +0200875 if (mSurfaceControl != null) {
876 mTmpTransaction.remove(mSurfaceControl);
877 mSurfaceControl = null;
878 }
879 if (mBackgroundControl != null) {
880 mTmpTransaction.remove(mBackgroundControl);
881 mBackgroundControl = null;
882 }
883 mTmpTransaction.apply();
Robert Carrb923f542019-05-13 12:27:51 -0700884 }
Robert Carrb923f542019-05-13 12:27:51 -0700885 }
886
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900887 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800888 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700889 if (!mHaveFrame) {
Issei Suzuki006b71f2019-06-17 15:56:57 +0200890 if (DEBUG) {
891 Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
892 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700893 return;
894 }
Vishnu Nair34486ad2020-06-10 18:14:20 -0700895 final ViewRootImpl viewRoot = getViewRootImpl();
896
897 if (viewRoot == null) {
898 return;
899 }
900
901 if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
902 notifySurfaceDestroyed();
903 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800904 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700905 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700906
Issei Suzukif0412592019-07-02 12:31:34 +0200907 final Translator translator = viewRoot.mTranslator;
908 if (translator != null) {
909 mSurface.setCompatibilityTranslator(translator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700910 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700911
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700912 int myWidth = mRequestedWidth;
913 if (myWidth <= 0) myWidth = getWidth();
914 int myHeight = mRequestedHeight;
915 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700916
Issei Suzuki006b71f2019-06-17 15:56:57 +0200917 final float alpha = getFixedAlpha();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700918 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700919 final boolean visibleChanged = mVisible != mRequestedVisible;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200920 final boolean alphaChanged = mSurfaceAlpha != alpha;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700921 final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
Robert Carrd5c7dd62017-03-08 10:39:30 -0800922 && mRequestedVisible;
923 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800924 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700925 boolean redrawNeeded = false;
Robert Carrbf01a772020-02-18 08:42:53 -0800926 getLocationInSurface(mLocation);
927 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
928 || mWindowSpaceTop != mLocation[1];
929 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
930 || getHeight() != mScreenRect.height();
Robert Carr49b593e2016-07-11 12:21:18 -0700931
Robert Carrbf01a772020-02-18 08:42:53 -0800932
933 if (creating || formatChanged || sizeChanged || visibleChanged ||
934 (mUseAlpha && alphaChanged) || windowVisibleChanged ||
935 positionChanged || layoutSizeChanged) {
John Reckf6481082016-02-02 15:18:23 -0800936 getLocationInWindow(mLocation);
937
John Reckaa6e84f2016-06-16 15:36:13 -0700938 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
939 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700940 + " format=" + formatChanged + " size=" + sizeChanged
Issei Suzuki006b71f2019-06-17 15:56:57 +0200941 + " visible=" + visibleChanged + " alpha=" + alphaChanged
942 + " mUseAlpha=" + mUseAlpha
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700943 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800944 + " left=" + (mWindowSpaceLeft != mLocation[0])
945 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700946
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700947 try {
948 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800949 mWindowSpaceLeft = mLocation[0];
950 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800951 mSurfaceWidth = myWidth;
952 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700953 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800954 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700955
Robert Carrd5c7dd62017-03-08 10:39:30 -0800956 mScreenRect.left = mWindowSpaceLeft;
957 mScreenRect.top = mWindowSpaceTop;
958 mScreenRect.right = mWindowSpaceLeft + getWidth();
959 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Issei Suzukif0412592019-07-02 12:31:34 +0200960 if (translator != null) {
961 translator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700962 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700963
Issei Suzuki006b71f2019-06-17 15:56:57 +0200964 final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800965 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
966
967 if (creating) {
Robert Carr3bc95b52017-03-20 21:57:23 -0700968 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carr55235552017-06-02 14:21:03 -0700969
970 updateOpaqueFlag();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700971 // SurfaceView hierarchy
972 // ViewRootImpl surface
973 // - bounds layer (crops all child surfaces to parent surface insets)
974 // - SurfaceView surface (drawn relative to ViewRootImpl surface)
975 // - Background color layer (drawn behind all SurfaceView surfaces)
976 //
977 // The bounds layer is used to crop the surface view so it does not draw into
978 // the parent surface inset region. Since there can be multiple surface views
979 // below or above the parent surface, one option is to create multiple bounds
980 // layer for each z order. The other option, the one implement is to create
981 // a single bounds layer and set z order for each child surface relative to the
982 // parent surface.
983 // When creating the surface view, we parent it to the bounds layer and then
984 // set the relative z order. When the parent surface changes, we have to
985 // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback.
Robert Carre625fcf2017-09-01 12:36:28 -0700986 final String name = "SurfaceView - " + viewRoot.getTitle().toString();
Vishnu Naireaab0e52019-06-24 08:12:28 -0700987
988 mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
989 .setName(name)
Svet Ganova5b49902020-06-18 00:47:22 -0700990 .setLocalOwnerView(this)
Vishnu Naireaab0e52019-06-24 08:12:28 -0700991 .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
992 .setBufferSize(mSurfaceWidth, mSurfaceHeight)
993 .setFormat(mFormat)
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700994 .setParent(viewRoot.getBoundsLayer())
Vishnu Naireaab0e52019-06-24 08:12:28 -0700995 .setFlags(mSurfaceFlags)
996 .build();
Robert Carrb923f542019-05-13 12:27:51 -0700997 mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
998 .setName("Background for -" + name)
Svet Ganova5b49902020-06-18 00:47:22 -0700999 .setLocalOwnerView(this)
Robert Carrb923f542019-05-13 12:27:51 -07001000 .setOpaque(true)
1001 .setColorLayer()
1002 .setParent(mSurfaceControl)
1003 .build();
1004
Robert Carr44ab5752017-03-20 21:47:11 -07001005 } else if (mSurfaceControl == null) {
1006 return;
Robert Carr64aadd02015-11-06 13:54:20 -08001007 }
1008
Robert Carrd5c7dd62017-03-08 10:39:30 -08001009 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001010
Dianne Hackborn726426e2010-03-31 22:04:36 -07001011 mSurfaceLock.lock();
1012 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -07001013 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001014
John Reckaa6e84f2016-06-16 15:36:13 -07001015 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1016 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001017
chaviw619da692019-06-10 15:39:40 -07001018 // If we are creating the surface control or the parent surface has not
1019 // changed, then set relative z. Otherwise allow the parent
1020 // SurfaceChangedCallback to update the relative z. This is needed so that
1021 // we do not change the relative z before the server is ready to swap the
1022 // parent surface.
1023 if (creating || (mParentSurfaceGenerationId
1024 == viewRoot.mSurface.getGenerationId())) {
1025 updateRelativeZ(mTmpTransaction);
Dianne Hackborn726426e2010-03-31 22:04:36 -07001026 }
chaviw619da692019-06-10 15:39:40 -07001027 mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
1028
1029 if (mViewVisibility) {
1030 mTmpTransaction.show(mSurfaceControl);
1031 } else {
1032 mTmpTransaction.hide(mSurfaceControl);
1033 }
Robert Carr30ad6182019-12-18 01:46:04 -08001034
1035 if (mSurfacePackage != null) {
1036 reparentSurfacePackage(mTmpTransaction, mSurfacePackage);
1037 }
1038
chaviw619da692019-06-10 15:39:40 -07001039 updateBackgroundVisibility(mTmpTransaction);
Winson Chungd4a9abd2020-03-21 23:01:16 -07001040 updateBackgroundColor(mTmpTransaction);
chaviw619da692019-06-10 15:39:40 -07001041 if (mUseAlpha) {
1042 mTmpTransaction.setAlpha(mSurfaceControl, alpha);
1043 mSurfaceAlpha = alpha;
1044 }
1045
1046 // While creating the surface, we will set it's initial
1047 // geometry. Outside of that though, we should generally
1048 // leave it to the RenderThread.
1049 //
1050 // There is one more case when the buffer size changes we aren't yet
1051 // prepared to sync (as even following the transaction applying
1052 // we still need to latch a buffer).
1053 // b/28866173
1054 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
Svet Ganova5b49902020-06-18 00:47:22 -07001055 onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
1056 mScreenRect.left, /*positionLeft*/
1057 mScreenRect.top /*positionTop*/ ,
1058 mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
1059 mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
1060
chaviw619da692019-06-10 15:39:40 -07001061 // Set a window crop when creating the surface or changing its size to
1062 // crop the buffer to the surface size since the buffer producer may
1063 // use SCALING_MODE_SCALE and submit a larger size than the surface
1064 // size.
1065 if (mClipSurfaceToBounds && mClipBounds != null) {
1066 mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
1067 } else {
1068 mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
1069 mSurfaceHeight);
1070 }
Robert Carr59773cb2020-04-01 14:35:07 -07001071 } else if ((layoutSizeChanged || positionChanged || visibleChanged) &&
Robert Carr6d16c8c2020-02-21 12:04:31 -08001072 viewRoot.useBLAST()) {
Robert Carrbf01a772020-02-18 08:42:53 -08001073 viewRoot.setUseBLASTSyncTransaction();
chaviw619da692019-06-10 15:39:40 -07001074 }
1075 mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
1076 if (sizeChanged && !creating) {
1077 mTmpTransaction.setBufferSize(mSurfaceControl, mSurfaceWidth,
1078 mSurfaceHeight);
1079 }
1080
1081 mTmpTransaction.apply();
Jackal Guoac234d62020-02-03 15:05:43 +08001082 updateScreenMatrixForEmbeddedHierarchy();
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001083
Robert Carrd5c7dd62017-03-08 10:39:30 -08001084 if (sizeChanged || creating) {
1085 redrawNeeded = true;
1086 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001087
Dianne Hackborn726426e2010-03-31 22:04:36 -07001088 mSurfaceFrame.left = 0;
1089 mSurfaceFrame.top = 0;
Issei Suzukif0412592019-07-02 12:31:34 +02001090 if (translator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -08001091 mSurfaceFrame.right = mSurfaceWidth;
1092 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -07001093 } else {
Issei Suzukif0412592019-07-02 12:31:34 +02001094 float appInvertedScale = translator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001095 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
1096 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -07001097 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001098
Dianne Hackborn726426e2010-03-31 22:04:36 -07001099 final int surfaceWidth = mSurfaceFrame.right;
1100 final int surfaceHeight = mSurfaceFrame.bottom;
1101 realSizeChanged = mLastSurfaceWidth != surfaceWidth
1102 || mLastSurfaceHeight != surfaceHeight;
1103 mLastSurfaceWidth = surfaceWidth;
1104 mLastSurfaceHeight = surfaceHeight;
1105 } finally {
1106 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -07001107 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001108
1109 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -08001110 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001111
Issei Suzuki60557b52019-07-03 20:04:48 +02001112 SurfaceHolder.Callback[] callbacks = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001113
Robert Carrd5c7dd62017-03-08 10:39:30 -08001114 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001115 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
1116 mSurfaceCreated = false;
Vishnu Nair34486ad2020-06-10 18:14:20 -07001117 notifySurfaceDestroyed();
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001118 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001119
Robert Carrd5c7dd62017-03-08 10:39:30 -08001120 if (creating) {
Robert Carrb923f542019-05-13 12:27:51 -07001121 mSurface.copyFrom(mSurfaceControl);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001122 }
1123
Bryce Lee453fc362017-06-20 10:47:55 -07001124 if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
Bryce Lee02949f12017-06-16 07:20:34 -07001125 < Build.VERSION_CODES.O) {
1126 // Some legacy applications use the underlying native {@link Surface} object
1127 // as a key to whether anything has changed. In these cases, updates to the
1128 // existing {@link Surface} will be ignored when the size changes.
1129 // Therefore, we must explicitly recreate the {@link Surface} in these
1130 // cases.
Robert Carrb923f542019-05-13 12:27:51 -07001131 mSurface.createFrom(mSurfaceControl);
Bryce Lee02949f12017-06-16 07:20:34 -07001132 }
1133
Andreas Röhlf750b8c2012-07-02 13:06:26 +02001134 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001135 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
1136 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001137 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -07001138 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1139 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001140 if (callbacks == null) {
1141 callbacks = getSurfaceCallbacks();
1142 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001143 for (SurfaceHolder.Callback c : callbacks) {
1144 c.surfaceCreated(mSurfaceHolder);
1145 }
1146 }
1147 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -07001148 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -07001149 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1150 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001151 + " w=" + myWidth + " h=" + myHeight);
1152 if (callbacks == null) {
1153 callbacks = getSurfaceCallbacks();
1154 }
Dianne Hackborn251fd432010-07-14 16:56:31 -07001155 for (SurfaceHolder.Callback c : callbacks) {
1156 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
1157 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001158 }
1159 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -07001160 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1161 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001162 if (callbacks == null) {
1163 callbacks = getSurfaceCallbacks();
1164 }
Robert Carr8508bb22017-03-27 15:46:27 -07001165
1166 mPendingReportDraws++;
1167 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -08001168 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -08001169 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -08001170 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001171 }
1172 }
1173 } finally {
1174 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001175 if (mSurfaceControl != null && !mSurfaceCreated) {
Robert Carrb923f542019-05-13 12:27:51 -07001176 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -08001177 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001178 }
Robert Carrd5c7dd62017-03-08 10:39:30 -08001179 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -07001180 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001181 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001182 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -08001183 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
1184 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
1185 + ", frame=" + mSurfaceFrame);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001186 }
1187 }
1188
Robert Carrd5c7dd62017-03-08 10:39:30 -08001189 private void onDrawFinished() {
1190 if (DEBUG) {
1191 Log.i(TAG, System.identityHashCode(this) + " "
1192 + "finishedDrawing");
1193 }
Robert Carr3bc95b52017-03-20 21:57:23 -07001194
1195 if (mDeferredDestroySurfaceControl != null) {
Robert Carr6ce9ffb2020-06-01 11:02:19 -07001196 synchronized (mSurfaceControlLock) {
1197 mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
1198 mDeferredDestroySurfaceControl = null;
1199 }
Robert Carr3bc95b52017-03-20 21:57:23 -07001200 }
1201
Issei Suzuki60557b52019-07-03 20:04:48 +02001202 runOnUiThread(this::performDrawFinished);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001203 }
1204
Robert Carr27a800a2018-03-16 13:33:45 -07001205 /**
1206 * A place to over-ride for applying child-surface transactions.
1207 * These can be synchronized with the viewroot surface using deferTransaction.
1208 *
1209 * Called from RenderWorker while UI thread is paused.
1210 * @hide
1211 */
1212 protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
1213 Surface viewRootSurface, long nextViewRootFrameNumber) {
1214 }
1215
Svet Ganova5b49902020-06-18 00:47:22 -07001216 /**
1217 * Sets the surface position and scale. Can be called on
1218 * the UI thread as well as on the renderer thread.
1219 *
1220 * @param transaction Transaction in which to execute.
1221 * @param surface Surface whose location to set.
1222 * @param positionLeft The left position to set.
1223 * @param positionTop The top position to set.
1224 * @param postScaleX The X axis post scale
1225 * @param postScaleY The Y axis post scale
1226 *
1227 * @hide
1228 */
1229 protected void onSetSurfacePositionAndScaleRT(@NonNull Transaction transaction,
1230 @NonNull SurfaceControl surface, int positionLeft, int positionTop,
1231 float postScaleX, float postScaleY) {
1232 transaction.setPosition(surface, positionLeft, positionTop);
1233 transaction.setMatrix(surface, postScaleX /*dsdx*/, 0f /*dtdx*/,
Svet Ganov48468032020-06-23 23:38:07 -07001234 0f /*dtdy*/, postScaleY /*dsdy*/);
Svet Ganova5b49902020-06-18 00:47:22 -07001235 }
1236
1237 /** @hide */
1238 public void requestUpdateSurfacePositionAndScale() {
1239 if (mSurfaceControl == null) {
1240 return;
1241 }
1242 onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
1243 mScreenRect.left, /*positionLeft*/
1244 mScreenRect.top/*positionTop*/ ,
1245 mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
1246 mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
1247 mTmpTransaction.apply();
1248 }
1249
Robert Carr85bb9402019-12-19 01:33:24 -08001250 private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
1251 Rect position, long frameNumber) {
Robert Carr6d16c8c2020-02-21 12:04:31 -08001252 final ViewRootImpl viewRoot = getViewRootImpl();
Robert Carr92e08bf2020-04-01 14:29:13 -07001253 if (frameNumber > 0 && viewRoot != null && !viewRoot.isDrawingToBLASTTransaction()) {
Robert Carrcef9a282020-01-14 09:08:05 -08001254 t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(),
Robert Carr27a800a2018-03-16 13:33:45 -07001255 frameNumber);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001256 }
Robert Carr386fd702018-03-23 13:46:39 -07001257
Svet Ganova5b49902020-06-18 00:47:22 -07001258 onSetSurfacePositionAndScaleRT(t, surface,
1259 position.left /*positionLeft*/,
1260 position.top /*positionTop*/,
1261 position.width() / (float) mSurfaceWidth /*postScaleX*/,
1262 position.height() / (float) mSurfaceHeight /*postScaleY*/);
1263
John Reckd0abd662019-05-01 12:52:04 -07001264 if (mViewVisibility) {
Robert Carr85bb9402019-12-19 01:33:24 -08001265 t.show(surface);
John Reckd0abd662019-05-01 12:52:04 -07001266 }
Robert Carr386fd702018-03-23 13:46:39 -07001267 }
1268
Svet Ganova5b49902020-06-18 00:47:22 -07001269 /**
1270 * @return The last render position of the backing surface or an empty rect.
1271 *
1272 * @hide
1273 */
1274 public @NonNull Rect getSurfaceRenderPosition() {
1275 return mRTLastReportedPosition;
1276 }
1277
Robert Carr386fd702018-03-23 13:46:39 -07001278 private void setParentSpaceRectangle(Rect position, long frameNumber) {
1279 final ViewRootImpl viewRoot = getViewRootImpl();
Robert Carr92e08bf2020-04-01 14:29:13 -07001280 final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction();
Robert Carr85bb9402019-12-19 01:33:24 -08001281 final SurfaceControl.Transaction t = useBLAST ? viewRoot.getBLASTSyncTransaction() :
1282 mRtTransaction;
Robert Carr386fd702018-03-23 13:46:39 -07001283
Robert Carr85bb9402019-12-19 01:33:24 -08001284 applySurfaceTransforms(mSurfaceControl, t, position, frameNumber);
Robert Carr27a800a2018-03-16 13:33:45 -07001285
Robert Carr85bb9402019-12-19 01:33:24 -08001286 applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface,
Robert Carr27a800a2018-03-16 13:33:45 -07001287 frameNumber);
1288
Robert Carr85bb9402019-12-19 01:33:24 -08001289 if (!useBLAST) {
1290 t.apply();
1291 }
Robert Carrd5c7dd62017-03-08 10:39:30 -08001292 }
1293
John Reckf6481082016-02-02 15:18:23 -08001294 private Rect mRTLastReportedPosition = new Rect();
1295
John Reck6b164402018-09-24 15:25:42 -07001296 private RenderNode.PositionUpdateListener mPositionListener =
1297 new RenderNode.PositionUpdateListener() {
Robert Carrd5c7dd62017-03-08 10:39:30 -08001298
John Reck6b164402018-09-24 15:25:42 -07001299 @Override
1300 public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
1301 if (mSurfaceControl == null) {
1302 return;
John Reckf6481082016-02-02 15:18:23 -08001303 }
John Reckf6481082016-02-02 15:18:23 -08001304
John Reck6b164402018-09-24 15:25:42 -07001305 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
1306 // its 2nd frame if RenderThread is running slowly could potentially see
1307 // this as false, enter the branch, get pre-empted, then this comes along
1308 // and reports a new position, then the UI thread resumes and reports
1309 // its position. This could therefore be de-sync'd in that interval, but
1310 // the synchronization would violate the rule that RT must never block
1311 // on the UI thread which would open up potential deadlocks. The risk of
1312 // a single-frame desync is therefore preferable for now.
Robert Carr005c63e2019-09-20 14:31:24 -07001313 synchronized(mSurfaceControlLock) {
1314 mRtHandlingPositionUpdates = true;
1315 }
John Reck6b164402018-09-24 15:25:42 -07001316 if (mRTLastReportedPosition.left == left
1317 && mRTLastReportedPosition.top == top
1318 && mRTLastReportedPosition.right == right
1319 && mRTLastReportedPosition.bottom == bottom) {
1320 return;
1321 }
1322 try {
Issei Suzuki006b71f2019-06-17 15:56:57 +02001323 if (DEBUG_POSITION) {
John Reck6b164402018-09-24 15:25:42 -07001324 Log.d(TAG, String.format(
1325 "%d updateSurfacePosition RenderWorker, frameNr = %d, "
Issei Suzuki60557b52019-07-03 20:04:48 +02001326 + "position = [%d, %d, %d, %d]",
John Reck6b164402018-09-24 15:25:42 -07001327 System.identityHashCode(this), frameNumber,
1328 left, top, right, bottom));
1329 }
1330 mRTLastReportedPosition.set(left, top, right, bottom);
1331 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
1332 // Now overwrite mRTLastReportedPosition with our values
1333 } catch (Exception ex) {
1334 Log.e(TAG, "Exception from repositionChild", ex);
1335 }
John Reckaa6e84f2016-06-16 15:36:13 -07001336 }
Robert Carrad3a4932017-06-20 14:55:21 -07001337
John Reck6b164402018-09-24 15:25:42 -07001338 @Override
1339 public void positionLost(long frameNumber) {
Robert Carr6d16c8c2020-02-21 12:04:31 -08001340 final ViewRootImpl viewRoot = getViewRootImpl();
Robert Carr92e08bf2020-04-01 14:29:13 -07001341 boolean useBLAST = viewRoot != null && viewRoot.isDrawingToBLASTTransaction();
John Reck6b164402018-09-24 15:25:42 -07001342 if (DEBUG) {
1343 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
1344 System.identityHashCode(this), frameNumber));
1345 }
1346 mRTLastReportedPosition.setEmpty();
1347
1348 if (mSurfaceControl == null) {
1349 return;
1350 }
John Reckd0abd662019-05-01 12:52:04 -07001351
Robert Carr85bb9402019-12-19 01:33:24 -08001352 final SurfaceControl.Transaction t = useBLAST ?
1353 (viewRoot != null ? viewRoot.getBLASTSyncTransaction() : mRtTransaction) :
1354 mRtTransaction;
1355
Robert Carrebaaca12020-05-13 11:23:43 -07001356 /**
1357 * positionLost can be called while UI thread is un-paused so we
1358 * need to hold the lock here.
1359 */
Robert Carr005c63e2019-09-20 14:31:24 -07001360 synchronized (mSurfaceControlLock) {
Robert Carrebaaca12020-05-13 11:23:43 -07001361 if (frameNumber > 0 && viewRoot != null && !useBLAST) {
1362 if (viewRoot.mSurface.isValid()) {
1363 mRtTransaction.deferTransactionUntil(mSurfaceControl,
1364 viewRoot.getRenderSurfaceControl(), frameNumber);
1365 }
1366 }
1367 t.hide(mSurfaceControl);
1368
Robert Carr005c63e2019-09-20 14:31:24 -07001369 if (mRtReleaseSurfaces) {
1370 mRtReleaseSurfaces = false;
1371 mRtTransaction.remove(mSurfaceControl);
1372 mRtTransaction.remove(mBackgroundControl);
1373 mSurfaceControl = null;
1374 mBackgroundControl = null;
1375 }
1376 mRtHandlingPositionUpdates = false;
1377 }
1378
Robert Carr85bb9402019-12-19 01:33:24 -08001379 // If we aren't using BLAST, we apply the transaction locally, otherise we let the ViewRoot apply it for us.
1380 // If the ViewRoot is null, we behave as if we aren't using BLAST so we need to apply the transaction.
1381 if (!useBLAST || viewRoot == null) {
1382 mRtTransaction.apply();
1383 }
John Reckf23a1b82016-06-22 14:23:31 -07001384 }
John Reck6b164402018-09-24 15:25:42 -07001385 };
John Reckaa6e84f2016-06-16 15:36:13 -07001386
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001387 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
Issei Suzuki60557b52019-07-03 20:04:48 +02001388 SurfaceHolder.Callback[] callbacks;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001389 synchronized (mCallbacks) {
1390 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
1391 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001392 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001393 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001394 }
1395
John Reck79925002017-05-26 13:57:14 -07001396 private void runOnUiThread(Runnable runnable) {
1397 Handler handler = getHandler();
1398 if (handler != null && handler.getLooper() != Looper.myLooper()) {
1399 handler.post(runnable);
1400 } else {
1401 runnable.run();
1402 }
1403 }
1404
Yohei Yukawa3b5011a2017-03-16 15:34:12 -07001405 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -04001406 * Check to see if the surface has fixed size dimensions or if the surface's
1407 * dimensions are dimensions are dependent on its current layout.
1408 *
1409 * @return true if the surface has dimensions that are fixed in size
1410 * @hide
1411 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01001412 @UnsupportedAppUsage
Derek Sollenberger7179b812010-03-22 13:41:20 -04001413 public boolean isFixedSize() {
1414 return (mRequestedWidth != -1 || mRequestedHeight != -1);
1415 }
1416
Robert Carrd5c7dd62017-03-08 10:39:30 -08001417 private boolean isAboveParent() {
1418 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001419 }
1420
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001421 /**
1422 * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
1423 * and size of the content hasn't updated yet. This color will fill the expanded area when the
1424 * view becomes larger.
1425 * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
1426 * @hide
1427 */
1428 public void setResizeBackgroundColor(int bgColor) {
Robert Carrb923f542019-05-13 12:27:51 -07001429 if (mBackgroundControl == null) {
1430 return;
1431 }
1432
Winson Chungd4a9abd2020-03-21 23:01:16 -07001433 mBackgroundColor = bgColor;
1434 updateBackgroundColor(mTmpTransaction).apply();
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001435 }
1436
Mathew Inwooda570dee2018-08-17 14:56:00 +01001437 @UnsupportedAppUsage
Igor Murashkina86ab6402013-08-30 12:58:36 -07001438 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001439 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -07001440
1441 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001442 public boolean isCreating() {
1443 return mIsCreating;
1444 }
1445
Igor Murashkina86ab6402013-08-30 12:58:36 -07001446 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001447 public void addCallback(Callback callback) {
1448 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -07001449 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001450 // have only a couple callbacks, so it doesn't matter.
Issei Suzukif0412592019-07-02 12:31:34 +02001451 if (!mCallbacks.contains(callback)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001452 mCallbacks.add(callback);
1453 }
1454 }
1455 }
1456
Igor Murashkina86ab6402013-08-30 12:58:36 -07001457 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001458 public void removeCallback(Callback callback) {
1459 synchronized (mCallbacks) {
1460 mCallbacks.remove(callback);
1461 }
1462 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001463
1464 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001465 public void setFixedSize(int width, int height) {
1466 if (mRequestedWidth != width || mRequestedHeight != height) {
1467 mRequestedWidth = width;
1468 mRequestedHeight = height;
1469 requestLayout();
1470 }
1471 }
1472
Igor Murashkina86ab6402013-08-30 12:58:36 -07001473 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001474 public void setSizeFromLayout() {
1475 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
1476 mRequestedWidth = mRequestedHeight = -1;
1477 requestLayout();
1478 }
1479 }
1480
Igor Murashkina86ab6402013-08-30 12:58:36 -07001481 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001482 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -07001483 // for backward compatibility reason, OPAQUE always
1484 // means 565 for SurfaceView
1485 if (format == PixelFormat.OPAQUE)
1486 format = PixelFormat.RGB_565;
1487
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001488 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001489 if (mSurfaceControl != null) {
1490 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001491 }
1492 }
1493
Mathias Agopiand2112302010-12-07 19:38:17 -08001494 /**
1495 * @deprecated setType is now ignored.
1496 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001497 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -08001498 @Deprecated
1499 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001500
Igor Murashkina86ab6402013-08-30 12:58:36 -07001501 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001502 public void setKeepScreenOn(boolean screenOn) {
John Reck79925002017-05-26 13:57:14 -07001503 runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001504 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001505
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001506 /**
1507 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1508 *
1509 * After drawing into the provided {@link Canvas}, the caller must
1510 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1511 *
1512 * The caller must redraw the entire surface.
1513 * @return A canvas for drawing into the surface.
1514 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001515 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001516 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -07001517 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001518 }
1519
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001520 /**
1521 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1522 *
1523 * After drawing into the provided {@link Canvas}, the caller must
1524 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1525 *
1526 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1527 * to redraw. This function may choose to expand the dirty rectangle if for example
1528 * the surface has been resized or if the previous contents of the surface were
1529 * not available. The caller must redraw the entire dirty region as represented
1530 * by the contents of the inOutDirty rectangle upon return from this function.
1531 * The caller may also pass <code>null</code> instead, in the case where the
1532 * entire surface should be redrawn.
1533 * @return A canvas for drawing into the surface.
1534 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001535 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001536 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -07001537 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001538 }
1539
John Reck6bc70142016-10-26 16:49:17 -07001540 @Override
1541 public Canvas lockHardwareCanvas() {
1542 return internalLockCanvas(null, true);
1543 }
1544
1545 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001546 mSurfaceLock.lock();
1547
John Reckaa6e84f2016-06-16 15:36:13 -07001548 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001549 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001550
1551 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001552 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001553 try {
John Reck6bc70142016-10-26 16:49:17 -07001554 if (hardware) {
1555 c = mSurface.lockHardwareCanvas();
1556 } else {
1557 c = mSurface.lockCanvas(dirty);
1558 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001559 } catch (Exception e) {
1560 Log.e(LOG_TAG, "Exception locking surface", e);
1561 }
1562 }
1563
John Reckaa6e84f2016-06-16 15:36:13 -07001564 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001565 if (c != null) {
1566 mLastLockTime = SystemClock.uptimeMillis();
1567 return c;
1568 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001569
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001570 // If the Surface is not ready to be drawn, then return null,
1571 // but throttle calls to this function so it isn't called more
1572 // than every 100ms.
1573 long now = SystemClock.uptimeMillis();
1574 long nextTime = mLastLockTime + 100;
1575 if (nextTime > now) {
1576 try {
1577 Thread.sleep(nextTime-now);
1578 } catch (InterruptedException e) {
1579 }
1580 now = SystemClock.uptimeMillis();
1581 }
1582 mLastLockTime = now;
1583 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001584
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001585 return null;
1586 }
1587
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001588 /**
1589 * Posts the new contents of the {@link Canvas} to the surface and
1590 * releases the {@link Canvas}.
1591 *
1592 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1593 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001594 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001595 public void unlockCanvasAndPost(Canvas canvas) {
1596 mSurface.unlockCanvasAndPost(canvas);
1597 mSurfaceLock.unlock();
1598 }
1599
Igor Murashkina86ab6402013-08-30 12:58:36 -07001600 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001601 public Surface getSurface() {
1602 return mSurface;
1603 }
1604
Igor Murashkina86ab6402013-08-30 12:58:36 -07001605 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001606 public Rect getSurfaceFrame() {
1607 return mSurfaceFrame;
1608 }
1609 };
Robert Carr55235552017-06-02 14:21:03 -07001610
chaviwff2e7d82018-11-02 11:11:27 -07001611 /**
Robert Carr76907ee2019-01-11 13:38:19 -08001612 * Return a SurfaceControl which can be used for parenting Surfaces to
1613 * this SurfaceView.
1614 *
1615 * @return The SurfaceControl for this SurfaceView.
chaviwff2e7d82018-11-02 11:11:27 -07001616 */
1617 public SurfaceControl getSurfaceControl() {
Robert Carrb923f542019-05-13 12:27:51 -07001618 return mSurfaceControl;
chaviwff2e7d82018-11-02 11:11:27 -07001619 }
Vishnu Nair3b037f72019-07-22 12:55:58 -07001620
1621 /**
Robert Carr87f5d2c2020-01-19 17:27:00 -08001622 * A token used for constructing {@link SurfaceControlViewHost}. This token should
1623 * be passed from the host process to the client process.
1624 *
1625 * @return The token
Vishnu Nair5cf253192019-11-07 15:33:20 -08001626 */
Robert Carr87f5d2c2020-01-19 17:27:00 -08001627 public @Nullable IBinder getHostToken() {
Vishnu Nair5cf253192019-11-07 15:33:20 -08001628 final ViewRootImpl viewRoot = getViewRootImpl();
1629 if (viewRoot == null) {
1630 return null;
1631 }
1632 return viewRoot.getInputToken();
1633 }
1634
1635 /**
Vishnu Nair3b037f72019-07-22 12:55:58 -07001636 * Set window stopped to false and update surface visibility when ViewRootImpl surface is
1637 * created.
1638 * @hide
1639 */
1640 @Override
1641 public void surfaceCreated(SurfaceControl.Transaction t) {
1642 setWindowStopped(false);
1643 }
1644
1645 /**
1646 * Set window stopped to true and update surface visibility when ViewRootImpl surface is
1647 * destroyed.
1648 * @hide
1649 */
1650 @Override
1651 public void surfaceDestroyed() {
1652 setWindowStopped(true);
Jackal Guoac234d62020-02-03 15:05:43 +08001653 setRemoteAccessibilityEmbeddedConnection(null, null);
Vishnu Nair3b037f72019-07-22 12:55:58 -07001654 }
1655
1656 /**
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001657 * Called when a valid ViewRootImpl surface is replaced by another valid surface. In this
1658 * case update relative z to the new parent surface.
Vishnu Nair3b037f72019-07-22 12:55:58 -07001659 * @hide
1660 */
1661 @Override
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001662 public void surfaceReplaced(Transaction t) {
1663 if (mSurfaceControl != null && mBackgroundControl != null) {
chaviw619da692019-06-10 15:39:40 -07001664 updateRelativeZ(t);
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001665 }
1666 }
Vishnu Nair3b037f72019-07-22 12:55:58 -07001667
chaviw619da692019-06-10 15:39:40 -07001668 private void updateRelativeZ(Transaction t) {
Robert Carrc34aea82020-06-16 11:47:07 -07001669 final ViewRootImpl viewRoot = getViewRootImpl();
1670 if (viewRoot == null) {
1671 // We were just detached.
1672 return;
1673 }
1674 final SurfaceControl viewRootControl = viewRoot.getSurfaceControl();
1675 t.setRelativeLayer(mBackgroundControl, viewRootControl, Integer.MIN_VALUE);
1676 t.setRelativeLayer(mSurfaceControl, viewRootControl, mSubLayer);
Vishnu Nair3b037f72019-07-22 12:55:58 -07001677 }
Robert Carr85bb9402019-12-19 01:33:24 -08001678
1679 /**
Robert Carr87f5d2c2020-01-19 17:27:00 -08001680 * Display the view-hierarchy embedded within a {@link SurfaceControlViewHost.SurfacePackage}
Robert Carr20c23962020-04-10 15:23:42 -07001681 * within this SurfaceView.
1682 *
1683 * This can be called independently of the SurfaceView lifetime callbacks. SurfaceView
1684 * will internally manage reparenting the package to our Surface as it is created
1685 * and destroyed.
1686 *
1687 * If this SurfaceView is above its host Surface (see
Robert Carr87f5d2c2020-01-19 17:27:00 -08001688 * {@link #setZOrderOnTop} then the embedded Surface hierarchy will be able to receive
Robert Carr20c23962020-04-10 15:23:42 -07001689 * input.
1690 *
1691 * This will take ownership of the SurfaceControl contained inside the SurfacePackage
Robert Carr5af7d622020-03-17 12:04:20 -07001692 * and free the caller of the obligation to call
Robert Carr20c23962020-04-10 15:23:42 -07001693 * {@link SurfaceControlViewHost.SurfacePackage#release}. However, note that
1694 * {@link SurfaceControlViewHost.SurfacePackage#release} and
1695 * {@link SurfaceControlViewHost#release} are not the same. While the ownership
1696 * of this particular {@link SurfaceControlViewHost.SurfacePackage} will be taken by the
1697 * SurfaceView the underlying {@link SurfaceControlViewHost} remains managed by it's original
1698 * remote-owner.
Robert Carr87f5d2c2020-01-19 17:27:00 -08001699 *
1700 * @param p The SurfacePackage to embed.
Robert Carr30ad6182019-12-18 01:46:04 -08001701 */
Robert Carr30ad6182019-12-18 01:46:04 -08001702 public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
1703 final SurfaceControl sc = p != null ? p.getSurfaceControl() : null;
1704 final SurfaceControl lastSc = mSurfacePackage != null ?
1705 mSurfacePackage.getSurfaceControl() : null;
1706 if (mSurfaceControl != null && lastSc != null) {
1707 mTmpTransaction.reparent(lastSc, null).apply();
Robert Carr5af7d622020-03-17 12:04:20 -07001708 mSurfacePackage.release();
Robert Carr30ad6182019-12-18 01:46:04 -08001709 } else if (mSurfaceControl != null) {
1710 reparentSurfacePackage(mTmpTransaction, p);
1711 mTmpTransaction.apply();
1712 }
1713 mSurfacePackage = p;
1714 }
1715
1716 private void reparentSurfacePackage(SurfaceControl.Transaction t,
1717 SurfaceControlViewHost.SurfacePackage p) {
Jackal Guoac234d62020-02-03 15:05:43 +08001718 initEmbeddedHierarchyForAccessibility(p);
Robert Carr20c62d22020-02-05 15:25:58 -08001719 final SurfaceControl sc = p.getSurfaceControl();
1720 t.reparent(sc, mSurfaceControl).show(sc);
Robert Carr30ad6182019-12-18 01:46:04 -08001721 }
1722
Jackal Guo79b182e2019-11-18 11:44:52 +08001723 /** @hide */
1724 @Override
1725 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1726 super.onInitializeAccessibilityNodeInfoInternal(info);
Jackal Guoac234d62020-02-03 15:05:43 +08001727 final RemoteAccessibilityEmbeddedConnection wrapper =
1728 getRemoteAccessibilityEmbeddedConnection();
1729 if (wrapper == null) {
Jackal Guo79b182e2019-11-18 11:44:52 +08001730 return;
1731 }
1732 // Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
1733 // leashed child would return the root node in the embedded hierarchy
Jackal Guoac234d62020-02-03 15:05:43 +08001734 info.addChild(wrapper.getLeashToken());
1735 }
1736
Jackal Guoa88ee6f2020-02-11 14:20:16 +08001737 @Override
1738 public int getImportantForAccessibility() {
1739 final int mode = super.getImportantForAccessibility();
1740 // If developers explicitly set the important mode for it, don't change the mode.
1741 // Only change the mode to important when this SurfaceView isn't explicitly set and has
1742 // an embedded hierarchy.
1743 if (mRemoteAccessibilityEmbeddedConnection == null
1744 || mode != IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
1745 return mode;
1746 }
1747 return IMPORTANT_FOR_ACCESSIBILITY_YES;
1748 }
1749
Jackal Guoac234d62020-02-03 15:05:43 +08001750 private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
1751 final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
1752 final RemoteAccessibilityEmbeddedConnection wrapper =
1753 getRemoteAccessibilityEmbeddedConnection();
1754
1755 // Do nothing if package is embedding the same view hierarchy.
1756 if (wrapper != null && wrapper.getConnection().equals(connection)) {
1757 return;
1758 }
1759
1760 // If this SurfaceView embeds a different view hierarchy, unlink the previous one first.
1761 setRemoteAccessibilityEmbeddedConnection(null, null);
1762
1763 try {
1764 final IBinder leashToken = connection.associateEmbeddedHierarchy(
1765 getViewRootImpl().mLeashToken, getAccessibilityViewId());
1766 setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
1767 } catch (RemoteException e) {
1768 Log.d(TAG, "Error while associateEmbeddedHierarchy " + e);
1769 }
1770 updateScreenMatrixForEmbeddedHierarchy();
1771 }
1772
1773 private void setRemoteAccessibilityEmbeddedConnection(
1774 IAccessibilityEmbeddedConnection connection, IBinder leashToken) {
1775 try {
1776 if (mRemoteAccessibilityEmbeddedConnection != null) {
1777 mRemoteAccessibilityEmbeddedConnection.getConnection()
1778 .disassociateEmbeddedHierarchy();
1779 mRemoteAccessibilityEmbeddedConnection.unlinkToDeath();
1780 mRemoteAccessibilityEmbeddedConnection = null;
1781 }
1782 if (connection != null && leashToken != null) {
1783 mRemoteAccessibilityEmbeddedConnection =
1784 new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
1785 mRemoteAccessibilityEmbeddedConnection.linkToDeath();
1786 }
1787 } catch (RemoteException e) {
1788 Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e);
1789 }
1790 }
1791
1792 private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
1793 return mRemoteAccessibilityEmbeddedConnection;
1794 }
1795
1796 private void updateScreenMatrixForEmbeddedHierarchy() {
Jackal Guoa67e14a2020-02-20 14:01:11 +08001797 getBoundsOnScreen(mTmpRect);
Jackal Guoac234d62020-02-03 15:05:43 +08001798 mTmpMatrix.reset();
Jackal Guoef364c52020-02-14 15:38:39 +08001799 mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
Jackal Guoac234d62020-02-03 15:05:43 +08001800 mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
1801 mScreenRect.height() / (float) mSurfaceHeight);
1802
1803 // If the screen matrix is identity or doesn't change, do nothing.
1804 if (mTmpMatrix.isIdentity() || mTmpMatrix.equals(mScreenMatrixForEmbeddedHierarchy)) {
1805 return;
1806 }
1807
1808 try {
1809 final RemoteAccessibilityEmbeddedConnection wrapper =
1810 getRemoteAccessibilityEmbeddedConnection();
1811 if (wrapper == null) {
1812 return;
1813 }
1814 mTmpMatrix.getValues(mMatrixValues);
1815 wrapper.getConnection().setScreenMatrix(mMatrixValues);
1816 mScreenMatrixForEmbeddedHierarchy.set(mTmpMatrix);
1817 } catch (RemoteException e) {
1818 Log.d(TAG, "Error while setScreenMatrix " + e);
1819 }
1820 }
1821
Vishnu Nair34486ad2020-06-10 18:14:20 -07001822 private void notifySurfaceDestroyed() {
1823 if (mSurface.isValid()) {
1824 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1825 + "surfaceDestroyed");
1826 SurfaceHolder.Callback[] callbacks = getSurfaceCallbacks();
1827 for (SurfaceHolder.Callback c : callbacks) {
1828 c.surfaceDestroyed(mSurfaceHolder);
1829 }
1830 // Since Android N the same surface may be reused and given to us
1831 // again by the system server at a later point. However
1832 // as we didn't do this in previous releases, clients weren't
1833 // necessarily required to clean up properly in
1834 // surfaceDestroyed. This leads to problems for example when
1835 // clients don't destroy their EGL context, and try
1836 // and create a new one on the same surface following reuse.
1837 // Since there is no valid use of the surface in-between
1838 // surfaceDestroyed and surfaceCreated, we force a disconnect,
1839 // so the next connect will always work if we end up reusing
1840 // the surface.
1841 if (mSurface.isValid()) {
1842 mSurface.forceScopedDisconnect();
1843 }
1844 }
1845 }
1846
Jackal Guoac234d62020-02-03 15:05:43 +08001847 /**
1848 * Wrapper of accessibility embedded connection for embedded view hierarchy.
1849 */
1850 private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
1851 private final IAccessibilityEmbeddedConnection mConnection;
1852 private final IBinder mLeashToken;
1853
1854 RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
1855 IBinder leashToken) {
1856 mConnection = connection;
1857 mLeashToken = leashToken;
1858 }
1859
1860 IAccessibilityEmbeddedConnection getConnection() {
1861 return mConnection;
1862 }
1863
1864 IBinder getLeashToken() {
1865 return mLeashToken;
1866 }
1867
1868 void linkToDeath() throws RemoteException {
1869 mConnection.asBinder().linkToDeath(this, 0);
1870 }
1871
1872 void unlinkToDeath() {
1873 mConnection.asBinder().unlinkToDeath(this, 0);
1874 }
1875
1876 @Override
1877 public void binderDied() {
1878 unlinkToDeath();
1879 runOnUiThread(() -> {
1880 if (mRemoteAccessibilityEmbeddedConnection == this) {
1881 mRemoteAccessibilityEmbeddedConnection = null;
1882 }
1883 });
1884 }
Jackal Guo79b182e2019-11-18 11:44:52 +08001885 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001886}