blob: bd811fc1f052823d0924f29b2cfa698733216ec0 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Adrian Roose99bc052017-11-20 17:55:31 +010019import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
20import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
21import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
Robert Carrd5c7dd62017-03-08 10:39:30 -080022
Robert Carr30ad6182019-12-18 01:46:04 -080023import android.annotation.NonNull;
Vishnu Nair5cf253192019-11-07 15:33:20 -080024import android.annotation.Nullable;
Artur Satayevad9254c2019-12-10 17:47:54 +000025import android.compat.annotation.UnsupportedAppUsage;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070026import android.content.Context;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070027import android.content.res.CompatibilityInfo.Translator;
Mark Renouf34d04f32019-05-13 15:53:18 -040028import android.graphics.BlendMode;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070029import android.graphics.Canvas;
Andrii Kuliancf8f6832018-01-23 19:43:30 -080030import android.graphics.Color;
Jackal Guoac234d62020-02-03 15:05:43 +080031import android.graphics.Matrix;
Mark Renouf34d04f32019-05-13 15:53:18 -040032import android.graphics.Paint;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070033import android.graphics.PixelFormat;
34import android.graphics.PorterDuff;
35import android.graphics.Rect;
36import android.graphics.Region;
John Reck32f140aa62018-10-04 15:08:24 -070037import android.graphics.RenderNode;
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070038import android.os.Build;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070039import android.os.Handler;
Vishnu Nair5cf253192019-11-07 15:33:20 -080040import android.os.IBinder;
John Reck79925002017-05-26 13:57:14 -070041import android.os.Looper;
Jackal Guoac234d62020-02-03 15:05:43 +080042import android.os.RemoteException;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070043import android.os.SystemClock;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070044import android.util.AttributeSet;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070045import android.util.Log;
Vishnu Nair8cb00ae2019-08-02 15:20:29 -070046import android.view.SurfaceControl.Transaction;
Robert Carr30ad6182019-12-18 01:46:04 -080047import android.view.SurfaceControlViewHost;
Valerie Hau779af292020-02-07 10:53:32 -080048import android.view.accessibility.AccessibilityNodeInfo;
Jackal Guoac234d62020-02-03 15:05:43 +080049import android.view.accessibility.IAccessibilityEmbeddedConnection;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070050
Robert Carr25cfa132016-11-16 13:24:09 -080051import com.android.internal.view.SurfaceCallbackHelper;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070052
Jon Larimer9bdf5762009-01-02 18:55:15 -050053import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070054import java.util.concurrent.locks.ReentrantLock;
55
56/**
57 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
58 * You can control the format of this surface and, if you like, its size; the
59 * SurfaceView takes care of placing the surface at the correct location on the
60 * screen
Igor Murashkina86ab6402013-08-30 12:58:36 -070061 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070062 * <p>The surface is Z ordered so that it is behind the window holding its
63 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070064 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070065 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070066 * normally appear on top of it. This can be used to place overlays such as
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070067 * buttons on top of the Surface, though note however that it can have an
68 * impact on performance since a full alpha-blended composite will be performed
69 * each time the Surface changes.
Igor Murashkina86ab6402013-08-30 12:58:36 -070070 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070071 * <p> The transparent region that makes the surface visible is based on the
72 * layout positions in the view hierarchy. If the post-layout transform
73 * properties are used to draw a sibling view on top of the SurfaceView, the
74 * view may not be properly composited with the surface.
75 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070076 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
77 * which can be retrieved by calling {@link #getHolder}.
Igor Murashkina86ab6402013-08-30 12:58:36 -070078 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070079 * <p>The Surface will be created for you while the SurfaceView's window is
80 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
81 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
82 * Surface is created and destroyed as the window is shown and hidden.
Igor Murashkina86ab6402013-08-30 12:58:36 -070083 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070084 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070085 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070086 * this way, you need to be aware of some threading semantics:
Igor Murashkina86ab6402013-08-30 12:58:36 -070087 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070088 * <ul>
89 * <li> All SurfaceView and
90 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
91 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070092 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070093 * state that is also touched by the drawing thread.
94 * <li> You must ensure that the drawing thread only touches the underlying
95 * Surface while it is valid -- between
96 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
97 * and
98 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
99 * </ul>
Chris Craik6ee192f2016-05-17 14:29:10 -0700100 *
101 * <p class="note"><strong>Note:</strong> Starting in platform version
102 * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
103 * updated synchronously with other View rendering. This means that translating
104 * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
105 * artifacts may occur on previous versions of the platform when its window is
106 * positioned asynchronously.</p>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700107 */
Vishnu Nair3b037f72019-07-22 12:55:58 -0700108public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800109 private static final String TAG = "SurfaceView";
110 private static final boolean DEBUG = false;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200111 private static final boolean DEBUG_POSITION = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700112
Mathew Inwooda570dee2018-08-17 14:56:00 +0100113 @UnsupportedAppUsage
Issei Suzukif0412592019-07-02 12:31:34 +0200114 final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<>();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700115
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800116 final int[] mLocation = new int[2];
Igor Murashkina86ab6402013-08-30 12:58:36 -0700117
Mathew Inwooda570dee2018-08-17 14:56:00 +0100118 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700119 final ReentrantLock mSurfaceLock = new ReentrantLock();
Mathew Inwooda570dee2018-08-17 14:56:00 +0100120 @UnsupportedAppUsage
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800121 final Surface mSurface = new Surface(); // Current surface in use
Mathew Inwood31755f92018-12-20 13:53:36 +0000122 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700123 boolean mDrawingStopped = true;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800124 // We use this to track if the application has produced a frame
125 // in to the Surface. Up until that point, we should be careful not to punch
126 // holes.
127 boolean mDrawFinished = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700128
Robert Carrd5c7dd62017-03-08 10:39:30 -0800129 final Rect mScreenRect = new Rect();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700130 private final SurfaceSession mSurfaceSession = new SurfaceSession();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800131
Robert Carrb923f542019-05-13 12:27:51 -0700132 SurfaceControl mSurfaceControl;
Robert Carr3bc95b52017-03-20 21:57:23 -0700133 // In the case of format changes we switch out the surface in-place
134 // we need to preserve the old one until the new one has drawn.
Robert Carrb923f542019-05-13 12:27:51 -0700135 SurfaceControl mDeferredDestroySurfaceControl;
136 SurfaceControl mBackgroundControl;
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) {
248 super(context, attrs, defStyleAttr, defStyleRes);
Adam Powell769b8632019-02-04 11:28:22 -0800249 mRenderNode.addPositionUpdateListener(mPositionListener);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700250
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700251 setWillNotDraw(true);
252 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700253
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700254 /**
255 * Return the SurfaceHolder providing access and control over this
256 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700257 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700258 * @return SurfaceHolder The holder of the surface.
259 */
260 public SurfaceHolder getHolder() {
261 return mSurfaceHolder;
262 }
263
Robert Carr414ebc62017-04-12 12:01:00 -0700264 private void updateRequestedVisibility() {
265 mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
266 }
267
Vishnu Nair3b037f72019-07-22 12:55:58 -0700268 private void setWindowStopped(boolean stopped) {
Robert Carr414ebc62017-04-12 12:01:00 -0700269 mWindowStopped = stopped;
270 updateRequestedVisibility();
271 updateSurface();
272 }
273
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700274 @Override
275 protected void onAttachedToWindow() {
276 super.onAttachedToWindow();
Robert Carr414ebc62017-04-12 12:01:00 -0700277
Vishnu Nair3b037f72019-07-22 12:55:58 -0700278 getViewRootImpl().addSurfaceChangedCallback(this);
Robert Carr00177cc2017-05-15 15:49:17 -0700279 mWindowStopped = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700280
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700281 mViewVisibility = getVisibility() == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700282 updateRequestedVisibility();
Romain Guy01d5edc2011-01-28 11:28:53 -0800283
Robert Carr8508bb22017-03-27 15:46:27 -0700284 mAttachedToWindow = true;
Karthik Ravi Shankara59c3a52017-09-11 17:36:25 -0700285 mParent.requestTransparentRegion(SurfaceView.this);
Romain Guy01d5edc2011-01-28 11:28:53 -0800286 if (!mGlobalListenersAdded) {
287 ViewTreeObserver observer = getViewTreeObserver();
288 observer.addOnScrollChangedListener(mScrollChangedListener);
289 observer.addOnPreDrawListener(mDrawListener);
290 mGlobalListenersAdded = true;
291 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700292 }
293
294 @Override
295 protected void onWindowVisibilityChanged(int visibility) {
296 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700297 mWindowVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700298 updateRequestedVisibility();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800299 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700300 }
301
302 @Override
303 public void setVisibility(int visibility) {
304 super.setVisibility(visibility);
305 mViewVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700306 boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700307 if (newRequestedVisible != mRequestedVisible) {
308 // our base class (View) invalidates the layout only when
309 // we go from/to the GONE state. However, SurfaceView needs
310 // to request a re-layout when the visibility changes at all.
311 // This is needed because the transparent region is computed
312 // as part of the layout phase, and it changes (obviously) when
313 // the visibility changes.
314 requestLayout();
315 }
316 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800317 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700318 }
Romain Guyafc3e112010-06-07 17:04:33 -0700319
Issei Suzuki006b71f2019-06-17 15:56:57 +0200320 /**
321 * Make alpha value of this view reflect onto the surface. This can only be called from at most
322 * one SurfaceView within a view tree.
323 *
324 * <p class="note"><strong>Note:</strong> Alpha value of the view is ignored and the underlying
325 * surface is rendered opaque by default.</p>
326 *
327 * @hide
328 */
329 public void setUseAlpha() {
330 if (!mUseAlpha) {
331 mUseAlpha = true;
332 updateSurfaceAlpha();
333 }
334 }
335
336 @Override
337 public void setAlpha(float alpha) {
338 // Sets the opacity of the view to a value, where 0 means the view is completely transparent
339 // and 1 means the view is completely opaque.
340 //
341 // Note: Alpha value of this view is ignored by default. To enable alpha blending, you need
342 // to call setUseAlpha() as well.
343 // This view doesn't support translucent opacity if the view is located z-below, since the
344 // logic to punch a hole in the view hierarchy cannot handle such case. See also
345 // #clearSurfaceViewPort(Canvas)
346 if (DEBUG) {
347 Log.d(TAG, System.identityHashCode(this)
348 + " setAlpha: mUseAlpha = " + mUseAlpha + " alpha=" + alpha);
349 }
350 super.setAlpha(alpha);
351 updateSurfaceAlpha();
352 }
353
354 private float getFixedAlpha() {
355 // Compute alpha value to be set on the underlying surface.
356 final float alpha = getAlpha();
357 return mUseAlpha && (mSubLayer > 0 || alpha == 0f) ? alpha : 1f;
358 }
359
360 private void updateSurfaceAlpha() {
361 if (!mUseAlpha) {
362 if (DEBUG) {
363 Log.d(TAG, System.identityHashCode(this)
364 + " updateSurfaceAlpha: setUseAlpha() is not called, ignored.");
365 }
366 return;
367 }
368 final float viewAlpha = getAlpha();
369 if (mSubLayer < 0 && 0f < viewAlpha && viewAlpha < 1f) {
370 Log.w(TAG, System.identityHashCode(this)
371 + " updateSurfaceAlpha:"
372 + " translucent color is not supported for a surface placed z-below.");
373 }
374 if (!mHaveFrame) {
375 if (DEBUG) {
376 Log.d(TAG, System.identityHashCode(this)
377 + " updateSurfaceAlpha: has no surface.");
378 }
379 return;
380 }
381 final ViewRootImpl viewRoot = getViewRootImpl();
382 if (viewRoot == null) {
383 if (DEBUG) {
384 Log.d(TAG, System.identityHashCode(this)
385 + " updateSurfaceAlpha: ViewRootImpl not available.");
386 }
387 return;
388 }
389 if (mSurfaceControl == null) {
390 if (DEBUG) {
391 Log.d(TAG, System.identityHashCode(this)
392 + "updateSurfaceAlpha:"
393 + " surface is not yet created, or already released.");
394 }
395 return;
396 }
397 final Surface parent = viewRoot.mSurface;
398 if (parent == null || !parent.isValid()) {
399 if (DEBUG) {
400 Log.d(TAG, System.identityHashCode(this)
401 + " updateSurfaceAlpha: ViewRootImpl has no valid surface");
402 }
403 return;
404 }
405 final float alpha = getFixedAlpha();
406 if (alpha != mSurfaceAlpha) {
407 if (isHardwareAccelerated()) {
408 /*
409 * Schedule a callback that reflects an alpha value onto the underlying surfaces.
410 * This gets called on a RenderThread worker thread, so members accessed here must
411 * be protected by a lock.
412 */
Robert Carr6d16c8c2020-02-21 12:04:31 -0800413 final boolean useBLAST = viewRoot.useBLAST();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200414 viewRoot.registerRtFrameCallback(frame -> {
415 try {
Robert Carr85bb9402019-12-19 01:33:24 -0800416 final SurfaceControl.Transaction t = useBLAST ?
417 viewRoot.getBLASTSyncTransaction() : new SurfaceControl.Transaction();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200418 synchronized (mSurfaceControlLock) {
419 if (!parent.isValid()) {
420 if (DEBUG) {
421 Log.d(TAG, System.identityHashCode(this)
422 + " updateSurfaceAlpha RT:"
423 + " ViewRootImpl has no valid surface");
424 }
425 return;
426 }
427 if (mSurfaceControl == null) {
428 if (DEBUG) {
429 Log.d(TAG, System.identityHashCode(this)
430 + "updateSurfaceAlpha RT:"
431 + " mSurfaceControl has already released");
432 }
433 return;
434 }
435 if (DEBUG) {
436 Log.d(TAG, System.identityHashCode(this)
437 + " updateSurfaceAlpha RT: set alpha=" + alpha);
438 }
439 t.setAlpha(mSurfaceControl, alpha);
Robert Carr85bb9402019-12-19 01:33:24 -0800440 if (!useBLAST) {
Robert Carrcef9a282020-01-14 09:08:05 -0800441 t.deferTransactionUntil(mSurfaceControl,
442 viewRoot.getRenderSurfaceControl(), frame);
Robert Carr85bb9402019-12-19 01:33:24 -0800443 }
Issei Suzuki006b71f2019-06-17 15:56:57 +0200444 }
445 // It's possible that mSurfaceControl is released in the UI thread before
446 // the transaction completes. If that happens, an exception is thrown, which
447 // must be caught immediately.
448 t.apply();
449 } catch (Exception e) {
450 Log.e(TAG, System.identityHashCode(this)
451 + "updateSurfaceAlpha RT: Exception during surface transaction", e);
452 }
453 });
454 damageInParent();
455 } else {
456 if (DEBUG) {
457 Log.d(TAG, System.identityHashCode(this)
458 + " updateSurfaceAlpha: set alpha=" + alpha);
459 }
chaviw619da692019-06-10 15:39:40 -0700460 mTmpTransaction.setAlpha(mSurfaceControl, alpha).apply();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200461 }
462 mSurfaceAlpha = alpha;
463 }
464 }
465
Robert Carrb53670a2017-05-25 18:20:49 -0700466 private void performDrawFinished() {
467 if (mPendingReportDraws > 0) {
468 mDrawFinished = true;
469 if (mAttachedToWindow) {
Pengfei Zhao15617202019-02-28 17:07:41 +0800470 mParent.requestTransparentRegion(SurfaceView.this);
Robert Carrb53670a2017-05-25 18:20:49 -0700471 notifyDrawFinished();
472 invalidate();
473 }
474 } else {
475 Log.e(TAG, System.identityHashCode(this) + "finished drawing"
476 + " but no pending report draw (extra call"
477 + " to draw completion runnable?)");
478 }
479 }
480
Robert Carr8508bb22017-03-27 15:46:27 -0700481 void notifyDrawFinished() {
482 ViewRootImpl viewRoot = getViewRootImpl();
483 if (viewRoot != null) {
484 viewRoot.pendingDrawFinished();
485 }
486 mPendingReportDraws--;
487 }
488
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700489 @Override
John Reck77e4a522014-10-01 10:38:07 -0700490 protected void onDetachedFromWindow() {
Lucas Dupin0c207342017-04-14 19:47:23 -0700491 ViewRootImpl viewRoot = getViewRootImpl();
492 // It's possible to create a SurfaceView using the default constructor and never
493 // attach it to a view hierarchy, this is a common use case when dealing with
494 // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
495 // the lifecycle. Instead of attaching it to a view, he/she can just pass
496 // the SurfaceHolder forward, most live wallpapers do it.
497 if (viewRoot != null) {
Vishnu Nair3b037f72019-07-22 12:55:58 -0700498 viewRoot.removeSurfaceChangedCallback(this);
Lucas Dupin0c207342017-04-14 19:47:23 -0700499 }
Robert Carr414ebc62017-04-12 12:01:00 -0700500
Robert Carr8508bb22017-03-27 15:46:27 -0700501 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800502 if (mGlobalListenersAdded) {
503 ViewTreeObserver observer = getViewTreeObserver();
504 observer.removeOnScrollChangedListener(mScrollChangedListener);
505 observer.removeOnPreDrawListener(mDrawListener);
506 mGlobalListenersAdded = false;
507 }
508
Robert Carr8508bb22017-03-27 15:46:27 -0700509 while (mPendingReportDraws > 0) {
510 notifyDrawFinished();
511 }
512
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700513 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800514
Robert Carrd5c7dd62017-03-08 10:39:30 -0800515 updateSurface();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200516 releaseSurfaces();
Robert Carr414ebc62017-04-12 12:01:00 -0700517
Robert Carr5af7d622020-03-17 12:04:20 -0700518 // We don't release this as part of releaseSurfaces as
519 // that is also called on transient visibility changes. We can't
520 // recreate this Surface, so only release it when we are fully
521 // detached.
522 if (mSurfacePackage != null) {
523 mSurfacePackage.release();
524 mSurfacePackage = null;
525 }
526
527 mHaveFrame = false;
John Reck77e4a522014-10-01 10:38:07 -0700528 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700529 }
530
531 @Override
532 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800533 int width = mRequestedWidth >= 0
534 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
535 : getDefaultSize(0, widthMeasureSpec);
536 int height = mRequestedHeight >= 0
537 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
538 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700539 setMeasuredDimension(width, height);
540 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700541
Mathias Agopianef115302010-10-04 20:15:08 -0700542 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700543 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100544 @UnsupportedAppUsage
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700545 protected boolean setFrame(int left, int top, int right, int bottom) {
546 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800547 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700548 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700549 }
550
551 @Override
552 public boolean gatherTransparentRegion(Region region) {
Robert Carr3ca12be72017-05-22 14:57:48 -0700553 if (isAboveParent() || !mDrawFinished) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700554 return super.gatherTransparentRegion(region);
555 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700556
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700557 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700558 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700559 // this view draws, remove it from the transparent region
560 opaque = super.gatherTransparentRegion(region);
561 } else if (region != null) {
562 int w = getWidth();
563 int h = getHeight();
564 if (w>0 && h>0) {
565 getLocationInWindow(mLocation);
566 // otherwise, punch a hole in the whole hierarchy
567 int l = mLocation[0];
568 int t = mLocation[1];
569 region.op(l, t, l+w, t+h, Region.Op.UNION);
570 }
571 }
572 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
573 opaque = false;
574 }
575 return opaque;
576 }
577
578 @Override
579 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800580 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700581 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700582 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700583 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400584 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700585 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700586 }
587 super.draw(canvas);
588 }
589
590 @Override
591 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800592 if (mDrawFinished && !isAboveParent()) {
593 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700594 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700595 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400596 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700597 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700598 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700599 super.dispatchDraw(canvas);
600 }
601
Mark Renoufe574ad02019-08-12 16:22:15 -0400602 /**
603 * Control whether the surface is clipped to the same bounds as the View. If true, then
604 * the bounds set by {@link #setClipBounds(Rect)} are applied to the surface as window-crop.
605 *
606 * @param enabled whether to enable surface clipping
607 * @hide
608 */
609 public void setEnableSurfaceClipping(boolean enabled) {
610 mClipSurfaceToBounds = enabled;
611 invalidate();
612 }
613
614 @Override
615 public void setClipBounds(Rect clipBounds) {
616 super.setClipBounds(clipBounds);
617
618 if (!mClipSurfaceToBounds) {
619 return;
620 }
621
622 // When cornerRadius is non-zero, a draw() is required to update
623 // the viewport (rounding the corners of the clipBounds).
624 if (mCornerRadius > 0f && !isAboveParent()) {
625 invalidate();
626 }
627
628 if (mSurfaceControl != null) {
629 if (mClipBounds != null) {
630 mTmpRect.set(mClipBounds);
631 } else {
632 mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
633 }
634 SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this);
Jorim Jaggi33a35ef2020-03-10 00:47:12 +0100635 applier.scheduleApply(false /* earlyWakeup */,
Mark Renoufe574ad02019-08-12 16:22:15 -0400636 new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl)
637 .withWindowCrop(mTmpRect)
638 .build());
639 }
640 }
641
Mark Renouf34d04f32019-05-13 15:53:18 -0400642 private void clearSurfaceViewPort(Canvas canvas) {
643 if (mCornerRadius > 0f) {
644 canvas.getClipBounds(mTmpRect);
Mark Renoufe574ad02019-08-12 16:22:15 -0400645 if (mClipSurfaceToBounds && mClipBounds != null) {
646 mTmpRect.intersect(mClipBounds);
647 }
Mark Renouf34d04f32019-05-13 15:53:18 -0400648 canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
649 mCornerRadius, mCornerRadius, mRoundedViewportPaint);
650 } else {
651 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
652 }
653 }
654
655 /**
656 * Sets the corner radius for the SurfaceView. This will round both the corners of the
657 * underlying surface, as well as the corners of the hole created to expose the surface.
658 *
659 * @param cornerRadius the new radius of the corners in pixels
660 * @hide
661 */
662 public void setCornerRadius(float cornerRadius) {
663 mCornerRadius = cornerRadius;
664 if (mCornerRadius > 0f && mRoundedViewportPaint == null) {
665 mRoundedViewportPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
666 mRoundedViewportPaint.setBlendMode(BlendMode.CLEAR);
667 mRoundedViewportPaint.setColor(0);
668 }
669 invalidate();
670 }
671
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700672 /**
Mark Renoufe574ad02019-08-12 16:22:15 -0400673 * Returns the corner radius for the SurfaceView.
674
675 * @return the radius of the corners in pixels
676 * @hide
677 */
678 public float getCornerRadius() {
679 return mCornerRadius;
680 }
681
682 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700683 * Control whether the surface view's surface is placed on top of another
684 * regular surface view in the window (but still behind the window itself).
685 * This is typically used to place overlays on top of an underlying media
686 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700687 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700688 * <p>Note that this must be set before the surface view's containing
689 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700690 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700691 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
692 */
693 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800694 mSubLayer = isMediaOverlay
695 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700696 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700697
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700698 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700699 * Control whether the surface view's surface is placed on top of its
700 * window. Normally it is placed behind the window, to allow it to
701 * (for the most part) appear to composite with the views in the
702 * hierarchy. By setting this, you cause it to be placed above the
703 * window. This means that none of the contents of the window this
704 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700705 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700706 * <p>Note that this must be set before the surface view's containing
Svet Ganova57dadd2020-03-18 23:30:16 -0700707 * window is attached to the window manager. If you target {@link Build.VERSION_CODES#R}
708 * the Z ordering can be changed dynamically if the backing surface is
709 * created, otherwise it would be applied at surface construction time.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700710 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700711 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Svet Ganova57dadd2020-03-18 23:30:16 -0700712 *
713 * @param onTop Whether to show the surface on top of this view's window.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700714 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700715 public void setZOrderOnTop(boolean onTop) {
Svet Ganova57dadd2020-03-18 23:30:16 -0700716 // In R and above we allow dynamic layer changes.
717 final boolean allowDynamicChange = getContext().getApplicationInfo().targetSdkVersion
718 > Build.VERSION_CODES.Q;
719 setZOrderedOnTop(onTop, allowDynamicChange);
720 }
721
722 /**
723 * @return Whether the surface backing this view appears on top of its parent.
724 *
725 * @hide
726 */
727 public boolean isZOrderedOnTop() {
728 return mSubLayer > 0;
729 }
730
731 /**
732 * Controls whether the surface view's surface is placed on top of its
733 * window. Normally it is placed behind the window, to allow it to
734 * (for the most part) appear to composite with the views in the
735 * hierarchy. By setting this, you cause it to be placed above the
736 * window. This means that none of the contents of the window this
737 * SurfaceView is in will be visible on top of its surface.
738 *
739 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
740 *
741 * @param onTop Whether to show the surface on top of this view's window.
742 * @param allowDynamicChange Whether this can happen after the surface is created.
743 * @return Whether the Z ordering changed.
744 *
745 * @hide
746 */
747 public boolean setZOrderedOnTop(boolean onTop, boolean allowDynamicChange) {
748 final int subLayer;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500749 if (onTop) {
Svet Ganova57dadd2020-03-18 23:30:16 -0700750 subLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500751 } else {
Svet Ganova57dadd2020-03-18 23:30:16 -0700752 subLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500753 }
Svet Ganova57dadd2020-03-18 23:30:16 -0700754 if (mSubLayer == subLayer) {
755 return false;
756 }
757 mSubLayer = subLayer;
758
759 if (!allowDynamicChange) {
760 return false;
761 }
762 if (mSurfaceControl == null) {
763 return true;
764 }
765 final ViewRootImpl viewRoot = getViewRootImpl();
766 if (viewRoot == null) {
767 return true;
768 }
769 final Surface parent = viewRoot.mSurface;
770 if (parent == null || !parent.isValid()) {
771 return true;
772 }
773
774 /*
775 * Schedule a callback that reflects an alpha value onto the underlying surfaces.
776 * This gets called on a RenderThread worker thread, so members accessed here must
777 * be protected by a lock.
778 */
779 final boolean useBLAST = viewRoot.useBLAST();
780 viewRoot.registerRtFrameCallback(frame -> {
781 try {
782 final SurfaceControl.Transaction t = useBLAST
783 ? viewRoot.getBLASTSyncTransaction()
784 : new SurfaceControl.Transaction();
785 synchronized (mSurfaceControlLock) {
786 if (!parent.isValid() || mSurfaceControl == null) {
787 return;
788 }
789 updateRelativeZ(t);
790 if (!useBLAST) {
791 t.deferTransactionUntil(mSurfaceControl,
792 viewRoot.getRenderSurfaceControl(), frame);
793 }
794 }
795 // It's possible that mSurfaceControl is released in the UI thread before
796 // the transaction completes. If that happens, an exception is thrown, which
797 // must be caught immediately.
798 t.apply();
799 } catch (Exception e) {
800 Log.e(TAG, System.identityHashCode(this)
801 + "setZOrderOnTop RT: Exception during surface transaction", e);
802 }
803 });
804
805 invalidate();
806
807 return true;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700808 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700809
810 /**
811 * Control whether the surface view's content should be treated as secure,
812 * preventing it from appearing in screenshots or from being viewed on
813 * non-secure displays.
814 *
815 * <p>Note that this must be set before the surface view's containing
816 * window is attached to the window manager.
817 *
818 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
819 *
820 * @param isSecure True if the surface view is secure.
821 */
822 public void setSecure(boolean isSecure) {
823 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800824 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700825 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800826 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700827 }
828 }
829
Robert Carr55235552017-06-02 14:21:03 -0700830 private void updateOpaqueFlag() {
Robert Carr851e7e42017-06-06 14:04:50 -0700831 if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
Robert Carr55235552017-06-02 14:21:03 -0700832 mSurfaceFlags |= SurfaceControl.OPAQUE;
833 } else {
834 mSurfaceFlags &= ~SurfaceControl.OPAQUE;
835 }
836 }
837
chaviw619da692019-06-10 15:39:40 -0700838 private void updateBackgroundVisibility(Transaction t) {
Robert Carrb923f542019-05-13 12:27:51 -0700839 if (mBackgroundControl == null) {
840 return;
841 }
842 if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
chaviw619da692019-06-10 15:39:40 -0700843 t.show(mBackgroundControl);
Robert Carrb923f542019-05-13 12:27:51 -0700844 } else {
chaviw619da692019-06-10 15:39:40 -0700845 t.hide(mBackgroundControl);
Robert Carrb923f542019-05-13 12:27:51 -0700846 }
847 }
848
Winson Chungd4a9abd2020-03-21 23:01:16 -0700849 private Transaction updateBackgroundColor(Transaction t) {
850 final float[] colorComponents = new float[] { Color.red(mBackgroundColor) / 255.f,
851 Color.green(mBackgroundColor) / 255.f, Color.blue(mBackgroundColor) / 255.f };
852 t.setColor(mBackgroundControl, colorComponents);
853 return t;
854 }
chaviw619da692019-06-10 15:39:40 -0700855
Robert Carrb923f542019-05-13 12:27:51 -0700856 private void releaseSurfaces() {
Robert Carr005c63e2019-09-20 14:31:24 -0700857 mSurfaceAlpha = 1f;
858
Issei Suzuki006b71f2019-06-17 15:56:57 +0200859 synchronized (mSurfaceControlLock) {
Robert Carrde63cc62019-10-25 13:18:29 -0700860 mSurface.release();
861
Robert Carr005c63e2019-09-20 14:31:24 -0700862 if (mRtHandlingPositionUpdates) {
863 mRtReleaseSurfaces = true;
864 return;
865 }
866
Issei Suzuki006b71f2019-06-17 15:56:57 +0200867 if (mSurfaceControl != null) {
868 mTmpTransaction.remove(mSurfaceControl);
869 mSurfaceControl = null;
870 }
871 if (mBackgroundControl != null) {
872 mTmpTransaction.remove(mBackgroundControl);
873 mBackgroundControl = null;
874 }
875 mTmpTransaction.apply();
Robert Carrb923f542019-05-13 12:27:51 -0700876 }
Robert Carrb923f542019-05-13 12:27:51 -0700877 }
878
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900879 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800880 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700881 if (!mHaveFrame) {
Issei Suzuki006b71f2019-06-17 15:56:57 +0200882 if (DEBUG) {
883 Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
884 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700885 return;
886 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800887 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800888 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
Issei Suzuki006b71f2019-06-17 15:56:57 +0200889 if (DEBUG) {
890 Log.d(TAG, System.identityHashCode(this)
891 + " updateSurface: no valid surface");
892 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800893 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700894 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700895
Issei Suzukif0412592019-07-02 12:31:34 +0200896 final Translator translator = viewRoot.mTranslator;
897 if (translator != null) {
898 mSurface.setCompatibilityTranslator(translator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700899 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700900
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700901 int myWidth = mRequestedWidth;
902 if (myWidth <= 0) myWidth = getWidth();
903 int myHeight = mRequestedHeight;
904 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700905
Issei Suzuki006b71f2019-06-17 15:56:57 +0200906 final float alpha = getFixedAlpha();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700907 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700908 final boolean visibleChanged = mVisible != mRequestedVisible;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200909 final boolean alphaChanged = mSurfaceAlpha != alpha;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700910 final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
Robert Carrd5c7dd62017-03-08 10:39:30 -0800911 && mRequestedVisible;
912 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800913 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700914 boolean redrawNeeded = false;
Robert Carrbf01a772020-02-18 08:42:53 -0800915 getLocationInSurface(mLocation);
916 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
917 || mWindowSpaceTop != mLocation[1];
918 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
919 || getHeight() != mScreenRect.height();
Robert Carr49b593e2016-07-11 12:21:18 -0700920
Robert Carrbf01a772020-02-18 08:42:53 -0800921
922 if (creating || formatChanged || sizeChanged || visibleChanged ||
923 (mUseAlpha && alphaChanged) || windowVisibleChanged ||
924 positionChanged || layoutSizeChanged) {
John Reckf6481082016-02-02 15:18:23 -0800925 getLocationInWindow(mLocation);
926
John Reckaa6e84f2016-06-16 15:36:13 -0700927 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
928 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700929 + " format=" + formatChanged + " size=" + sizeChanged
Issei Suzuki006b71f2019-06-17 15:56:57 +0200930 + " visible=" + visibleChanged + " alpha=" + alphaChanged
931 + " mUseAlpha=" + mUseAlpha
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700932 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800933 + " left=" + (mWindowSpaceLeft != mLocation[0])
934 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700935
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700936 try {
937 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800938 mWindowSpaceLeft = mLocation[0];
939 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800940 mSurfaceWidth = myWidth;
941 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700942 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800943 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700944
Robert Carrd5c7dd62017-03-08 10:39:30 -0800945 mScreenRect.left = mWindowSpaceLeft;
946 mScreenRect.top = mWindowSpaceTop;
947 mScreenRect.right = mWindowSpaceLeft + getWidth();
948 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Issei Suzukif0412592019-07-02 12:31:34 +0200949 if (translator != null) {
950 translator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700951 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700952
Issei Suzuki006b71f2019-06-17 15:56:57 +0200953 final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800954 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
955
956 if (creating) {
Robert Carr3bc95b52017-03-20 21:57:23 -0700957 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carr55235552017-06-02 14:21:03 -0700958
959 updateOpaqueFlag();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700960 // SurfaceView hierarchy
961 // ViewRootImpl surface
962 // - bounds layer (crops all child surfaces to parent surface insets)
963 // - SurfaceView surface (drawn relative to ViewRootImpl surface)
964 // - Background color layer (drawn behind all SurfaceView surfaces)
965 //
966 // The bounds layer is used to crop the surface view so it does not draw into
967 // the parent surface inset region. Since there can be multiple surface views
968 // below or above the parent surface, one option is to create multiple bounds
969 // layer for each z order. The other option, the one implement is to create
970 // a single bounds layer and set z order for each child surface relative to the
971 // parent surface.
972 // When creating the surface view, we parent it to the bounds layer and then
973 // set the relative z order. When the parent surface changes, we have to
974 // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback.
Robert Carre625fcf2017-09-01 12:36:28 -0700975 final String name = "SurfaceView - " + viewRoot.getTitle().toString();
Vishnu Naireaab0e52019-06-24 08:12:28 -0700976
977 mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
978 .setName(name)
979 .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
980 .setBufferSize(mSurfaceWidth, mSurfaceHeight)
981 .setFormat(mFormat)
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700982 .setParent(viewRoot.getBoundsLayer())
Vishnu Naireaab0e52019-06-24 08:12:28 -0700983 .setFlags(mSurfaceFlags)
984 .build();
Robert Carrb923f542019-05-13 12:27:51 -0700985 mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
986 .setName("Background for -" + name)
987 .setOpaque(true)
988 .setColorLayer()
989 .setParent(mSurfaceControl)
990 .build();
991
Robert Carr44ab5752017-03-20 21:47:11 -0700992 } else if (mSurfaceControl == null) {
993 return;
Robert Carr64aadd02015-11-06 13:54:20 -0800994 }
995
Robert Carrd5c7dd62017-03-08 10:39:30 -0800996 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800997
Dianne Hackborn726426e2010-03-31 22:04:36 -0700998 mSurfaceLock.lock();
999 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -07001000 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001001
John Reckaa6e84f2016-06-16 15:36:13 -07001002 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1003 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001004
chaviw619da692019-06-10 15:39:40 -07001005 // If we are creating the surface control or the parent surface has not
1006 // changed, then set relative z. Otherwise allow the parent
1007 // SurfaceChangedCallback to update the relative z. This is needed so that
1008 // we do not change the relative z before the server is ready to swap the
1009 // parent surface.
1010 if (creating || (mParentSurfaceGenerationId
1011 == viewRoot.mSurface.getGenerationId())) {
1012 updateRelativeZ(mTmpTransaction);
Dianne Hackborn726426e2010-03-31 22:04:36 -07001013 }
chaviw619da692019-06-10 15:39:40 -07001014 mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
1015
1016 if (mViewVisibility) {
1017 mTmpTransaction.show(mSurfaceControl);
1018 } else {
1019 mTmpTransaction.hide(mSurfaceControl);
1020 }
Robert Carr30ad6182019-12-18 01:46:04 -08001021
1022 if (mSurfacePackage != null) {
1023 reparentSurfacePackage(mTmpTransaction, mSurfacePackage);
1024 }
1025
chaviw619da692019-06-10 15:39:40 -07001026 updateBackgroundVisibility(mTmpTransaction);
Winson Chungd4a9abd2020-03-21 23:01:16 -07001027 updateBackgroundColor(mTmpTransaction);
chaviw619da692019-06-10 15:39:40 -07001028 if (mUseAlpha) {
1029 mTmpTransaction.setAlpha(mSurfaceControl, alpha);
1030 mSurfaceAlpha = alpha;
1031 }
1032
1033 // While creating the surface, we will set it's initial
1034 // geometry. Outside of that though, we should generally
1035 // leave it to the RenderThread.
1036 //
1037 // There is one more case when the buffer size changes we aren't yet
1038 // prepared to sync (as even following the transaction applying
1039 // we still need to latch a buffer).
1040 // b/28866173
1041 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
1042 mTmpTransaction.setPosition(mSurfaceControl, mScreenRect.left,
1043 mScreenRect.top);
1044 mTmpTransaction.setMatrix(mSurfaceControl,
1045 mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f,
1046 mScreenRect.height() / (float) mSurfaceHeight);
1047 // Set a window crop when creating the surface or changing its size to
1048 // crop the buffer to the surface size since the buffer producer may
1049 // use SCALING_MODE_SCALE and submit a larger size than the surface
1050 // size.
1051 if (mClipSurfaceToBounds && mClipBounds != null) {
1052 mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
1053 } else {
1054 mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
1055 mSurfaceHeight);
1056 }
Robert Carr59773cb2020-04-01 14:35:07 -07001057 } else if ((layoutSizeChanged || positionChanged || visibleChanged) &&
Robert Carr6d16c8c2020-02-21 12:04:31 -08001058 viewRoot.useBLAST()) {
Robert Carrbf01a772020-02-18 08:42:53 -08001059 viewRoot.setUseBLASTSyncTransaction();
chaviw619da692019-06-10 15:39:40 -07001060 }
1061 mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
1062 if (sizeChanged && !creating) {
1063 mTmpTransaction.setBufferSize(mSurfaceControl, mSurfaceWidth,
1064 mSurfaceHeight);
1065 }
1066
1067 mTmpTransaction.apply();
Jackal Guoac234d62020-02-03 15:05:43 +08001068 updateScreenMatrixForEmbeddedHierarchy();
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001069
Robert Carrd5c7dd62017-03-08 10:39:30 -08001070 if (sizeChanged || creating) {
1071 redrawNeeded = true;
1072 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001073
Dianne Hackborn726426e2010-03-31 22:04:36 -07001074 mSurfaceFrame.left = 0;
1075 mSurfaceFrame.top = 0;
Issei Suzukif0412592019-07-02 12:31:34 +02001076 if (translator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -08001077 mSurfaceFrame.right = mSurfaceWidth;
1078 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -07001079 } else {
Issei Suzukif0412592019-07-02 12:31:34 +02001080 float appInvertedScale = translator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001081 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
1082 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -07001083 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001084
Dianne Hackborn726426e2010-03-31 22:04:36 -07001085 final int surfaceWidth = mSurfaceFrame.right;
1086 final int surfaceHeight = mSurfaceFrame.bottom;
1087 realSizeChanged = mLastSurfaceWidth != surfaceWidth
1088 || mLastSurfaceHeight != surfaceHeight;
1089 mLastSurfaceWidth = surfaceWidth;
1090 mLastSurfaceHeight = surfaceHeight;
1091 } finally {
1092 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -07001093 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001094
1095 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -08001096 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001097
Issei Suzuki60557b52019-07-03 20:04:48 +02001098 SurfaceHolder.Callback[] callbacks = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001099
Robert Carrd5c7dd62017-03-08 10:39:30 -08001100 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001101 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
1102 mSurfaceCreated = false;
1103 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -07001104 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1105 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001106 callbacks = getSurfaceCallbacks();
1107 for (SurfaceHolder.Callback c : callbacks) {
1108 c.surfaceDestroyed(mSurfaceHolder);
1109 }
Robert Carr387838b2016-09-07 14:12:44 -07001110 // Since Android N the same surface may be reused and given to us
1111 // again by the system server at a later point. However
1112 // as we didn't do this in previous releases, clients weren't
1113 // necessarily required to clean up properly in
1114 // surfaceDestroyed. This leads to problems for example when
1115 // clients don't destroy their EGL context, and try
1116 // and create a new one on the same surface following reuse.
1117 // Since there is no valid use of the surface in-between
1118 // surfaceDestroyed and surfaceCreated, we force a disconnect,
1119 // so the next connect will always work if we end up reusing
1120 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -07001121 if (mSurface.isValid()) {
1122 mSurface.forceScopedDisconnect();
1123 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07001124 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001125 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001126
Robert Carrd5c7dd62017-03-08 10:39:30 -08001127 if (creating) {
Robert Carrb923f542019-05-13 12:27:51 -07001128 mSurface.copyFrom(mSurfaceControl);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001129 }
1130
Bryce Lee453fc362017-06-20 10:47:55 -07001131 if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
Bryce Lee02949f12017-06-16 07:20:34 -07001132 < Build.VERSION_CODES.O) {
1133 // Some legacy applications use the underlying native {@link Surface} object
1134 // as a key to whether anything has changed. In these cases, updates to the
1135 // existing {@link Surface} will be ignored when the size changes.
1136 // Therefore, we must explicitly recreate the {@link Surface} in these
1137 // cases.
Robert Carrb923f542019-05-13 12:27:51 -07001138 mSurface.createFrom(mSurfaceControl);
Bryce Lee02949f12017-06-16 07:20:34 -07001139 }
1140
Andreas Röhlf750b8c2012-07-02 13:06:26 +02001141 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001142 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
1143 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001144 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -07001145 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1146 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001147 if (callbacks == null) {
1148 callbacks = getSurfaceCallbacks();
1149 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001150 for (SurfaceHolder.Callback c : callbacks) {
1151 c.surfaceCreated(mSurfaceHolder);
1152 }
1153 }
1154 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -07001155 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -07001156 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1157 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001158 + " w=" + myWidth + " h=" + myHeight);
1159 if (callbacks == null) {
1160 callbacks = getSurfaceCallbacks();
1161 }
Dianne Hackborn251fd432010-07-14 16:56:31 -07001162 for (SurfaceHolder.Callback c : callbacks) {
1163 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
1164 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001165 }
1166 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -07001167 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1168 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001169 if (callbacks == null) {
1170 callbacks = getSurfaceCallbacks();
1171 }
Robert Carr8508bb22017-03-27 15:46:27 -07001172
1173 mPendingReportDraws++;
1174 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -08001175 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -08001176 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -08001177 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001178 }
1179 }
1180 } finally {
1181 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001182 if (mSurfaceControl != null && !mSurfaceCreated) {
Robert Carrb923f542019-05-13 12:27:51 -07001183 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -08001184 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001185 }
Robert Carrd5c7dd62017-03-08 10:39:30 -08001186 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -07001187 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001188 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001189 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -08001190 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
1191 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
1192 + ", frame=" + mSurfaceFrame);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001193 }
1194 }
1195
Robert Carrd5c7dd62017-03-08 10:39:30 -08001196 private void onDrawFinished() {
1197 if (DEBUG) {
1198 Log.i(TAG, System.identityHashCode(this) + " "
1199 + "finishedDrawing");
1200 }
Robert Carr3bc95b52017-03-20 21:57:23 -07001201
1202 if (mDeferredDestroySurfaceControl != null) {
chaviw9f6171e2019-06-07 16:33:50 -07001203 mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
Robert Carr3bc95b52017-03-20 21:57:23 -07001204 mDeferredDestroySurfaceControl = null;
1205 }
1206
Issei Suzuki60557b52019-07-03 20:04:48 +02001207 runOnUiThread(this::performDrawFinished);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001208 }
1209
Robert Carr27a800a2018-03-16 13:33:45 -07001210 /**
1211 * A place to over-ride for applying child-surface transactions.
1212 * These can be synchronized with the viewroot surface using deferTransaction.
1213 *
1214 * Called from RenderWorker while UI thread is paused.
1215 * @hide
1216 */
1217 protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
1218 Surface viewRootSurface, long nextViewRootFrameNumber) {
1219 }
1220
Robert Carr85bb9402019-12-19 01:33:24 -08001221 private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
1222 Rect position, long frameNumber) {
Robert Carr6d16c8c2020-02-21 12:04:31 -08001223 final ViewRootImpl viewRoot = getViewRootImpl();
Robert Carr92e08bf2020-04-01 14:29:13 -07001224 if (frameNumber > 0 && viewRoot != null && !viewRoot.isDrawingToBLASTTransaction()) {
Robert Carrcef9a282020-01-14 09:08:05 -08001225 t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(),
Robert Carr27a800a2018-03-16 13:33:45 -07001226 frameNumber);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001227 }
Robert Carr386fd702018-03-23 13:46:39 -07001228
Robert Carr85bb9402019-12-19 01:33:24 -08001229 t.setPosition(surface, position.left, position.top);
1230 t.setMatrix(surface,
Robert Carr27a800a2018-03-16 13:33:45 -07001231 position.width() / (float) mSurfaceWidth,
1232 0.0f, 0.0f,
1233 position.height() / (float) mSurfaceHeight);
John Reckd0abd662019-05-01 12:52:04 -07001234 if (mViewVisibility) {
Robert Carr85bb9402019-12-19 01:33:24 -08001235 t.show(surface);
John Reckd0abd662019-05-01 12:52:04 -07001236 }
Robert Carr386fd702018-03-23 13:46:39 -07001237 }
1238
1239 private void setParentSpaceRectangle(Rect position, long frameNumber) {
1240 final ViewRootImpl viewRoot = getViewRootImpl();
Robert Carr92e08bf2020-04-01 14:29:13 -07001241 final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction();
Robert Carr85bb9402019-12-19 01:33:24 -08001242 final SurfaceControl.Transaction t = useBLAST ? viewRoot.getBLASTSyncTransaction() :
1243 mRtTransaction;
Robert Carr386fd702018-03-23 13:46:39 -07001244
Robert Carr85bb9402019-12-19 01:33:24 -08001245 applySurfaceTransforms(mSurfaceControl, t, position, frameNumber);
Robert Carr27a800a2018-03-16 13:33:45 -07001246
Robert Carr85bb9402019-12-19 01:33:24 -08001247 applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface,
Robert Carr27a800a2018-03-16 13:33:45 -07001248 frameNumber);
1249
Robert Carr85bb9402019-12-19 01:33:24 -08001250 if (!useBLAST) {
1251 t.apply();
1252 }
Robert Carrd5c7dd62017-03-08 10:39:30 -08001253 }
1254
John Reckf6481082016-02-02 15:18:23 -08001255 private Rect mRTLastReportedPosition = new Rect();
1256
John Reck6b164402018-09-24 15:25:42 -07001257 private RenderNode.PositionUpdateListener mPositionListener =
1258 new RenderNode.PositionUpdateListener() {
Robert Carrd5c7dd62017-03-08 10:39:30 -08001259
John Reck6b164402018-09-24 15:25:42 -07001260 @Override
1261 public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
1262 if (mSurfaceControl == null) {
1263 return;
John Reckf6481082016-02-02 15:18:23 -08001264 }
John Reckf6481082016-02-02 15:18:23 -08001265
John Reck6b164402018-09-24 15:25:42 -07001266 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
1267 // its 2nd frame if RenderThread is running slowly could potentially see
1268 // this as false, enter the branch, get pre-empted, then this comes along
1269 // and reports a new position, then the UI thread resumes and reports
1270 // its position. This could therefore be de-sync'd in that interval, but
1271 // the synchronization would violate the rule that RT must never block
1272 // on the UI thread which would open up potential deadlocks. The risk of
1273 // a single-frame desync is therefore preferable for now.
Robert Carr005c63e2019-09-20 14:31:24 -07001274 synchronized(mSurfaceControlLock) {
1275 mRtHandlingPositionUpdates = true;
1276 }
John Reck6b164402018-09-24 15:25:42 -07001277 if (mRTLastReportedPosition.left == left
1278 && mRTLastReportedPosition.top == top
1279 && mRTLastReportedPosition.right == right
1280 && mRTLastReportedPosition.bottom == bottom) {
1281 return;
1282 }
1283 try {
Issei Suzuki006b71f2019-06-17 15:56:57 +02001284 if (DEBUG_POSITION) {
John Reck6b164402018-09-24 15:25:42 -07001285 Log.d(TAG, String.format(
1286 "%d updateSurfacePosition RenderWorker, frameNr = %d, "
Issei Suzuki60557b52019-07-03 20:04:48 +02001287 + "position = [%d, %d, %d, %d]",
John Reck6b164402018-09-24 15:25:42 -07001288 System.identityHashCode(this), frameNumber,
1289 left, top, right, bottom));
1290 }
1291 mRTLastReportedPosition.set(left, top, right, bottom);
1292 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
1293 // Now overwrite mRTLastReportedPosition with our values
1294 } catch (Exception ex) {
1295 Log.e(TAG, "Exception from repositionChild", ex);
1296 }
John Reckaa6e84f2016-06-16 15:36:13 -07001297 }
Robert Carrad3a4932017-06-20 14:55:21 -07001298
John Reck6b164402018-09-24 15:25:42 -07001299 @Override
1300 public void positionLost(long frameNumber) {
Robert Carr6d16c8c2020-02-21 12:04:31 -08001301 final ViewRootImpl viewRoot = getViewRootImpl();
Robert Carr92e08bf2020-04-01 14:29:13 -07001302 boolean useBLAST = viewRoot != null && viewRoot.isDrawingToBLASTTransaction();
John Reck6b164402018-09-24 15:25:42 -07001303 if (DEBUG) {
1304 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
1305 System.identityHashCode(this), frameNumber));
1306 }
1307 mRTLastReportedPosition.setEmpty();
1308
1309 if (mSurfaceControl == null) {
1310 return;
1311 }
John Reckd0abd662019-05-01 12:52:04 -07001312
Robert Carr85bb9402019-12-19 01:33:24 -08001313 final SurfaceControl.Transaction t = useBLAST ?
1314 (viewRoot != null ? viewRoot.getBLASTSyncTransaction() : mRtTransaction) :
1315 mRtTransaction;
1316
Robert Carrebaaca12020-05-13 11:23:43 -07001317 /**
1318 * positionLost can be called while UI thread is un-paused so we
1319 * need to hold the lock here.
1320 */
Robert Carr005c63e2019-09-20 14:31:24 -07001321 synchronized (mSurfaceControlLock) {
Robert Carrebaaca12020-05-13 11:23:43 -07001322 if (frameNumber > 0 && viewRoot != null && !useBLAST) {
1323 if (viewRoot.mSurface.isValid()) {
1324 mRtTransaction.deferTransactionUntil(mSurfaceControl,
1325 viewRoot.getRenderSurfaceControl(), frameNumber);
1326 }
1327 }
1328 t.hide(mSurfaceControl);
1329
Robert Carr005c63e2019-09-20 14:31:24 -07001330 if (mRtReleaseSurfaces) {
1331 mRtReleaseSurfaces = false;
1332 mRtTransaction.remove(mSurfaceControl);
1333 mRtTransaction.remove(mBackgroundControl);
1334 mSurfaceControl = null;
1335 mBackgroundControl = null;
1336 }
1337 mRtHandlingPositionUpdates = false;
1338 }
1339
Robert Carr85bb9402019-12-19 01:33:24 -08001340 // If we aren't using BLAST, we apply the transaction locally, otherise we let the ViewRoot apply it for us.
1341 // If the ViewRoot is null, we behave as if we aren't using BLAST so we need to apply the transaction.
1342 if (!useBLAST || viewRoot == null) {
1343 mRtTransaction.apply();
1344 }
John Reckf23a1b82016-06-22 14:23:31 -07001345 }
John Reck6b164402018-09-24 15:25:42 -07001346 };
John Reckaa6e84f2016-06-16 15:36:13 -07001347
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001348 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
Issei Suzuki60557b52019-07-03 20:04:48 +02001349 SurfaceHolder.Callback[] callbacks;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001350 synchronized (mCallbacks) {
1351 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
1352 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001353 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001354 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001355 }
1356
John Reck79925002017-05-26 13:57:14 -07001357 private void runOnUiThread(Runnable runnable) {
1358 Handler handler = getHandler();
1359 if (handler != null && handler.getLooper() != Looper.myLooper()) {
1360 handler.post(runnable);
1361 } else {
1362 runnable.run();
1363 }
1364 }
1365
Yohei Yukawa3b5011a2017-03-16 15:34:12 -07001366 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -04001367 * Check to see if the surface has fixed size dimensions or if the surface's
1368 * dimensions are dimensions are dependent on its current layout.
1369 *
1370 * @return true if the surface has dimensions that are fixed in size
1371 * @hide
1372 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01001373 @UnsupportedAppUsage
Derek Sollenberger7179b812010-03-22 13:41:20 -04001374 public boolean isFixedSize() {
1375 return (mRequestedWidth != -1 || mRequestedHeight != -1);
1376 }
1377
Robert Carrd5c7dd62017-03-08 10:39:30 -08001378 private boolean isAboveParent() {
1379 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001380 }
1381
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001382 /**
1383 * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
1384 * and size of the content hasn't updated yet. This color will fill the expanded area when the
1385 * view becomes larger.
1386 * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
1387 * @hide
1388 */
1389 public void setResizeBackgroundColor(int bgColor) {
Robert Carrb923f542019-05-13 12:27:51 -07001390 if (mBackgroundControl == null) {
1391 return;
1392 }
1393
Winson Chungd4a9abd2020-03-21 23:01:16 -07001394 mBackgroundColor = bgColor;
1395 updateBackgroundColor(mTmpTransaction).apply();
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001396 }
1397
Mathew Inwooda570dee2018-08-17 14:56:00 +01001398 @UnsupportedAppUsage
Igor Murashkina86ab6402013-08-30 12:58:36 -07001399 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001400 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -07001401
1402 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001403 public boolean isCreating() {
1404 return mIsCreating;
1405 }
1406
Igor Murashkina86ab6402013-08-30 12:58:36 -07001407 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001408 public void addCallback(Callback callback) {
1409 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -07001410 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001411 // have only a couple callbacks, so it doesn't matter.
Issei Suzukif0412592019-07-02 12:31:34 +02001412 if (!mCallbacks.contains(callback)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001413 mCallbacks.add(callback);
1414 }
1415 }
1416 }
1417
Igor Murashkina86ab6402013-08-30 12:58:36 -07001418 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001419 public void removeCallback(Callback callback) {
1420 synchronized (mCallbacks) {
1421 mCallbacks.remove(callback);
1422 }
1423 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001424
1425 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001426 public void setFixedSize(int width, int height) {
1427 if (mRequestedWidth != width || mRequestedHeight != height) {
1428 mRequestedWidth = width;
1429 mRequestedHeight = height;
1430 requestLayout();
1431 }
1432 }
1433
Igor Murashkina86ab6402013-08-30 12:58:36 -07001434 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001435 public void setSizeFromLayout() {
1436 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
1437 mRequestedWidth = mRequestedHeight = -1;
1438 requestLayout();
1439 }
1440 }
1441
Igor Murashkina86ab6402013-08-30 12:58:36 -07001442 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001443 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -07001444 // for backward compatibility reason, OPAQUE always
1445 // means 565 for SurfaceView
1446 if (format == PixelFormat.OPAQUE)
1447 format = PixelFormat.RGB_565;
1448
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001449 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001450 if (mSurfaceControl != null) {
1451 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001452 }
1453 }
1454
Mathias Agopiand2112302010-12-07 19:38:17 -08001455 /**
1456 * @deprecated setType is now ignored.
1457 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001458 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -08001459 @Deprecated
1460 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001461
Igor Murashkina86ab6402013-08-30 12:58:36 -07001462 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001463 public void setKeepScreenOn(boolean screenOn) {
John Reck79925002017-05-26 13:57:14 -07001464 runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001465 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001466
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001467 /**
1468 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1469 *
1470 * After drawing into the provided {@link Canvas}, the caller must
1471 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1472 *
1473 * The caller must redraw the entire surface.
1474 * @return A canvas for drawing into the surface.
1475 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001476 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001477 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -07001478 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001479 }
1480
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001481 /**
1482 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1483 *
1484 * After drawing into the provided {@link Canvas}, the caller must
1485 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1486 *
1487 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1488 * to redraw. This function may choose to expand the dirty rectangle if for example
1489 * the surface has been resized or if the previous contents of the surface were
1490 * not available. The caller must redraw the entire dirty region as represented
1491 * by the contents of the inOutDirty rectangle upon return from this function.
1492 * The caller may also pass <code>null</code> instead, in the case where the
1493 * entire surface should be redrawn.
1494 * @return A canvas for drawing into the surface.
1495 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001496 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001497 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -07001498 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001499 }
1500
John Reck6bc70142016-10-26 16:49:17 -07001501 @Override
1502 public Canvas lockHardwareCanvas() {
1503 return internalLockCanvas(null, true);
1504 }
1505
1506 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001507 mSurfaceLock.lock();
1508
John Reckaa6e84f2016-06-16 15:36:13 -07001509 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001510 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001511
1512 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001513 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001514 try {
John Reck6bc70142016-10-26 16:49:17 -07001515 if (hardware) {
1516 c = mSurface.lockHardwareCanvas();
1517 } else {
1518 c = mSurface.lockCanvas(dirty);
1519 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001520 } catch (Exception e) {
1521 Log.e(LOG_TAG, "Exception locking surface", e);
1522 }
1523 }
1524
John Reckaa6e84f2016-06-16 15:36:13 -07001525 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001526 if (c != null) {
1527 mLastLockTime = SystemClock.uptimeMillis();
1528 return c;
1529 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001530
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001531 // If the Surface is not ready to be drawn, then return null,
1532 // but throttle calls to this function so it isn't called more
1533 // than every 100ms.
1534 long now = SystemClock.uptimeMillis();
1535 long nextTime = mLastLockTime + 100;
1536 if (nextTime > now) {
1537 try {
1538 Thread.sleep(nextTime-now);
1539 } catch (InterruptedException e) {
1540 }
1541 now = SystemClock.uptimeMillis();
1542 }
1543 mLastLockTime = now;
1544 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001545
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001546 return null;
1547 }
1548
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001549 /**
1550 * Posts the new contents of the {@link Canvas} to the surface and
1551 * releases the {@link Canvas}.
1552 *
1553 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1554 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001555 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001556 public void unlockCanvasAndPost(Canvas canvas) {
1557 mSurface.unlockCanvasAndPost(canvas);
1558 mSurfaceLock.unlock();
1559 }
1560
Igor Murashkina86ab6402013-08-30 12:58:36 -07001561 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001562 public Surface getSurface() {
1563 return mSurface;
1564 }
1565
Igor Murashkina86ab6402013-08-30 12:58:36 -07001566 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001567 public Rect getSurfaceFrame() {
1568 return mSurfaceFrame;
1569 }
1570 };
Robert Carr55235552017-06-02 14:21:03 -07001571
chaviwff2e7d82018-11-02 11:11:27 -07001572 /**
Robert Carr76907ee2019-01-11 13:38:19 -08001573 * Return a SurfaceControl which can be used for parenting Surfaces to
1574 * this SurfaceView.
1575 *
1576 * @return The SurfaceControl for this SurfaceView.
chaviwff2e7d82018-11-02 11:11:27 -07001577 */
1578 public SurfaceControl getSurfaceControl() {
Robert Carrb923f542019-05-13 12:27:51 -07001579 return mSurfaceControl;
chaviwff2e7d82018-11-02 11:11:27 -07001580 }
Vishnu Nair3b037f72019-07-22 12:55:58 -07001581
1582 /**
Robert Carr87f5d2c2020-01-19 17:27:00 -08001583 * A token used for constructing {@link SurfaceControlViewHost}. This token should
1584 * be passed from the host process to the client process.
1585 *
1586 * @return The token
Vishnu Nair5cf253192019-11-07 15:33:20 -08001587 */
Robert Carr87f5d2c2020-01-19 17:27:00 -08001588 public @Nullable IBinder getHostToken() {
Vishnu Nair5cf253192019-11-07 15:33:20 -08001589 final ViewRootImpl viewRoot = getViewRootImpl();
1590 if (viewRoot == null) {
1591 return null;
1592 }
1593 return viewRoot.getInputToken();
1594 }
1595
1596 /**
Vishnu Nair3b037f72019-07-22 12:55:58 -07001597 * Set window stopped to false and update surface visibility when ViewRootImpl surface is
1598 * created.
1599 * @hide
1600 */
1601 @Override
1602 public void surfaceCreated(SurfaceControl.Transaction t) {
1603 setWindowStopped(false);
1604 }
1605
1606 /**
1607 * Set window stopped to true and update surface visibility when ViewRootImpl surface is
1608 * destroyed.
1609 * @hide
1610 */
1611 @Override
1612 public void surfaceDestroyed() {
1613 setWindowStopped(true);
Jackal Guoac234d62020-02-03 15:05:43 +08001614 setRemoteAccessibilityEmbeddedConnection(null, null);
Vishnu Nair3b037f72019-07-22 12:55:58 -07001615 }
1616
1617 /**
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001618 * Called when a valid ViewRootImpl surface is replaced by another valid surface. In this
1619 * case update relative z to the new parent surface.
Vishnu Nair3b037f72019-07-22 12:55:58 -07001620 * @hide
1621 */
1622 @Override
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001623 public void surfaceReplaced(Transaction t) {
1624 if (mSurfaceControl != null && mBackgroundControl != null) {
chaviw619da692019-06-10 15:39:40 -07001625 updateRelativeZ(t);
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001626 }
1627 }
Vishnu Nair3b037f72019-07-22 12:55:58 -07001628
chaviw619da692019-06-10 15:39:40 -07001629 private void updateRelativeZ(Transaction t) {
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001630 SurfaceControl viewRoot = getViewRootImpl().getSurfaceControl();
1631 t.setRelativeLayer(mBackgroundControl, viewRoot, Integer.MIN_VALUE);
1632 t.setRelativeLayer(mSurfaceControl, viewRoot, mSubLayer);
Vishnu Nair3b037f72019-07-22 12:55:58 -07001633 }
Robert Carr85bb9402019-12-19 01:33:24 -08001634
1635 /**
Robert Carr87f5d2c2020-01-19 17:27:00 -08001636 * Display the view-hierarchy embedded within a {@link SurfaceControlViewHost.SurfacePackage}
Robert Carr20c23962020-04-10 15:23:42 -07001637 * within this SurfaceView.
1638 *
1639 * This can be called independently of the SurfaceView lifetime callbacks. SurfaceView
1640 * will internally manage reparenting the package to our Surface as it is created
1641 * and destroyed.
1642 *
1643 * If this SurfaceView is above its host Surface (see
Robert Carr87f5d2c2020-01-19 17:27:00 -08001644 * {@link #setZOrderOnTop} then the embedded Surface hierarchy will be able to receive
Robert Carr20c23962020-04-10 15:23:42 -07001645 * input.
1646 *
1647 * This will take ownership of the SurfaceControl contained inside the SurfacePackage
Robert Carr5af7d622020-03-17 12:04:20 -07001648 * and free the caller of the obligation to call
Robert Carr20c23962020-04-10 15:23:42 -07001649 * {@link SurfaceControlViewHost.SurfacePackage#release}. However, note that
1650 * {@link SurfaceControlViewHost.SurfacePackage#release} and
1651 * {@link SurfaceControlViewHost#release} are not the same. While the ownership
1652 * of this particular {@link SurfaceControlViewHost.SurfacePackage} will be taken by the
1653 * SurfaceView the underlying {@link SurfaceControlViewHost} remains managed by it's original
1654 * remote-owner.
Robert Carr87f5d2c2020-01-19 17:27:00 -08001655 *
1656 * @param p The SurfacePackage to embed.
Robert Carr30ad6182019-12-18 01:46:04 -08001657 */
Robert Carr30ad6182019-12-18 01:46:04 -08001658 public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
1659 final SurfaceControl sc = p != null ? p.getSurfaceControl() : null;
1660 final SurfaceControl lastSc = mSurfacePackage != null ?
1661 mSurfacePackage.getSurfaceControl() : null;
1662 if (mSurfaceControl != null && lastSc != null) {
1663 mTmpTransaction.reparent(lastSc, null).apply();
Robert Carr5af7d622020-03-17 12:04:20 -07001664 mSurfacePackage.release();
Robert Carr30ad6182019-12-18 01:46:04 -08001665 } else if (mSurfaceControl != null) {
1666 reparentSurfacePackage(mTmpTransaction, p);
1667 mTmpTransaction.apply();
1668 }
1669 mSurfacePackage = p;
1670 }
1671
1672 private void reparentSurfacePackage(SurfaceControl.Transaction t,
1673 SurfaceControlViewHost.SurfacePackage p) {
Jackal Guoac234d62020-02-03 15:05:43 +08001674 initEmbeddedHierarchyForAccessibility(p);
Robert Carr20c62d22020-02-05 15:25:58 -08001675 final SurfaceControl sc = p.getSurfaceControl();
1676 t.reparent(sc, mSurfaceControl).show(sc);
Robert Carr30ad6182019-12-18 01:46:04 -08001677 }
1678
Jackal Guo79b182e2019-11-18 11:44:52 +08001679 /** @hide */
1680 @Override
1681 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1682 super.onInitializeAccessibilityNodeInfoInternal(info);
Jackal Guoac234d62020-02-03 15:05:43 +08001683 final RemoteAccessibilityEmbeddedConnection wrapper =
1684 getRemoteAccessibilityEmbeddedConnection();
1685 if (wrapper == null) {
Jackal Guo79b182e2019-11-18 11:44:52 +08001686 return;
1687 }
1688 // Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
1689 // leashed child would return the root node in the embedded hierarchy
Jackal Guoac234d62020-02-03 15:05:43 +08001690 info.addChild(wrapper.getLeashToken());
1691 }
1692
Jackal Guoa88ee6f2020-02-11 14:20:16 +08001693 @Override
1694 public int getImportantForAccessibility() {
1695 final int mode = super.getImportantForAccessibility();
1696 // If developers explicitly set the important mode for it, don't change the mode.
1697 // Only change the mode to important when this SurfaceView isn't explicitly set and has
1698 // an embedded hierarchy.
1699 if (mRemoteAccessibilityEmbeddedConnection == null
1700 || mode != IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
1701 return mode;
1702 }
1703 return IMPORTANT_FOR_ACCESSIBILITY_YES;
1704 }
1705
Jackal Guoac234d62020-02-03 15:05:43 +08001706 private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
1707 final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
1708 final RemoteAccessibilityEmbeddedConnection wrapper =
1709 getRemoteAccessibilityEmbeddedConnection();
1710
1711 // Do nothing if package is embedding the same view hierarchy.
1712 if (wrapper != null && wrapper.getConnection().equals(connection)) {
1713 return;
1714 }
1715
1716 // If this SurfaceView embeds a different view hierarchy, unlink the previous one first.
1717 setRemoteAccessibilityEmbeddedConnection(null, null);
1718
1719 try {
1720 final IBinder leashToken = connection.associateEmbeddedHierarchy(
1721 getViewRootImpl().mLeashToken, getAccessibilityViewId());
1722 setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
1723 } catch (RemoteException e) {
1724 Log.d(TAG, "Error while associateEmbeddedHierarchy " + e);
1725 }
1726 updateScreenMatrixForEmbeddedHierarchy();
1727 }
1728
1729 private void setRemoteAccessibilityEmbeddedConnection(
1730 IAccessibilityEmbeddedConnection connection, IBinder leashToken) {
1731 try {
1732 if (mRemoteAccessibilityEmbeddedConnection != null) {
1733 mRemoteAccessibilityEmbeddedConnection.getConnection()
1734 .disassociateEmbeddedHierarchy();
1735 mRemoteAccessibilityEmbeddedConnection.unlinkToDeath();
1736 mRemoteAccessibilityEmbeddedConnection = null;
1737 }
1738 if (connection != null && leashToken != null) {
1739 mRemoteAccessibilityEmbeddedConnection =
1740 new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
1741 mRemoteAccessibilityEmbeddedConnection.linkToDeath();
1742 }
1743 } catch (RemoteException e) {
1744 Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e);
1745 }
1746 }
1747
1748 private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
1749 return mRemoteAccessibilityEmbeddedConnection;
1750 }
1751
1752 private void updateScreenMatrixForEmbeddedHierarchy() {
Jackal Guoa67e14a2020-02-20 14:01:11 +08001753 getBoundsOnScreen(mTmpRect);
Jackal Guoac234d62020-02-03 15:05:43 +08001754 mTmpMatrix.reset();
Jackal Guoef364c52020-02-14 15:38:39 +08001755 mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
Jackal Guoac234d62020-02-03 15:05:43 +08001756 mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
1757 mScreenRect.height() / (float) mSurfaceHeight);
1758
1759 // If the screen matrix is identity or doesn't change, do nothing.
1760 if (mTmpMatrix.isIdentity() || mTmpMatrix.equals(mScreenMatrixForEmbeddedHierarchy)) {
1761 return;
1762 }
1763
1764 try {
1765 final RemoteAccessibilityEmbeddedConnection wrapper =
1766 getRemoteAccessibilityEmbeddedConnection();
1767 if (wrapper == null) {
1768 return;
1769 }
1770 mTmpMatrix.getValues(mMatrixValues);
1771 wrapper.getConnection().setScreenMatrix(mMatrixValues);
1772 mScreenMatrixForEmbeddedHierarchy.set(mTmpMatrix);
1773 } catch (RemoteException e) {
1774 Log.d(TAG, "Error while setScreenMatrix " + e);
1775 }
1776 }
1777
1778 /**
1779 * Wrapper of accessibility embedded connection for embedded view hierarchy.
1780 */
1781 private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
1782 private final IAccessibilityEmbeddedConnection mConnection;
1783 private final IBinder mLeashToken;
1784
1785 RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
1786 IBinder leashToken) {
1787 mConnection = connection;
1788 mLeashToken = leashToken;
1789 }
1790
1791 IAccessibilityEmbeddedConnection getConnection() {
1792 return mConnection;
1793 }
1794
1795 IBinder getLeashToken() {
1796 return mLeashToken;
1797 }
1798
1799 void linkToDeath() throws RemoteException {
1800 mConnection.asBinder().linkToDeath(this, 0);
1801 }
1802
1803 void unlinkToDeath() {
1804 mConnection.asBinder().unlinkToDeath(this, 0);
1805 }
1806
1807 @Override
1808 public void binderDied() {
1809 unlinkToDeath();
1810 runOnUiThread(() -> {
1811 if (mRemoteAccessibilityEmbeddedConnection == this) {
1812 mRemoteAccessibilityEmbeddedConnection = null;
1813 }
1814 });
1815 }
Jackal Guo79b182e2019-11-18 11:44:52 +08001816 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001817}