blob: 0b5af2d013494c288d6b66c7d567b0a8ed5b55a1 [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
Vishnu Nair5cf253192019-11-07 15:33:20 -080023import android.annotation.Nullable;
24import android.annotation.TestApi;
Mathew Inwooda570dee2018-08-17 14:56:00 +010025import android.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;
Mark Renouf34d04f32019-05-13 15:53:18 -040031import android.graphics.Paint;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070032import android.graphics.PixelFormat;
33import android.graphics.PorterDuff;
34import android.graphics.Rect;
35import android.graphics.Region;
John Reck32f140aa62018-10-04 15:08:24 -070036import android.graphics.RenderNode;
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070037import android.os.Build;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070038import android.os.Handler;
Vishnu Nair5cf253192019-11-07 15:33:20 -080039import android.os.IBinder;
John Reck79925002017-05-26 13:57:14 -070040import android.os.Looper;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070041import android.os.SystemClock;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070042import android.util.AttributeSet;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070043import android.util.Log;
Vishnu Nair8cb00ae2019-08-02 15:20:29 -070044import android.view.SurfaceControl.Transaction;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070045
Robert Carr25cfa132016-11-16 13:24:09 -080046import com.android.internal.view.SurfaceCallbackHelper;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070047
Jon Larimer9bdf5762009-01-02 18:55:15 -050048import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070049import java.util.concurrent.locks.ReentrantLock;
50
51/**
52 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
53 * You can control the format of this surface and, if you like, its size; the
54 * SurfaceView takes care of placing the surface at the correct location on the
55 * screen
Igor Murashkina86ab6402013-08-30 12:58:36 -070056 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070057 * <p>The surface is Z ordered so that it is behind the window holding its
58 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070059 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070060 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070061 * 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 -070062 * buttons on top of the Surface, though note however that it can have an
63 * impact on performance since a full alpha-blended composite will be performed
64 * each time the Surface changes.
Igor Murashkina86ab6402013-08-30 12:58:36 -070065 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070066 * <p> The transparent region that makes the surface visible is based on the
67 * layout positions in the view hierarchy. If the post-layout transform
68 * properties are used to draw a sibling view on top of the SurfaceView, the
69 * view may not be properly composited with the surface.
70 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070071 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
72 * which can be retrieved by calling {@link #getHolder}.
Igor Murashkina86ab6402013-08-30 12:58:36 -070073 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070074 * <p>The Surface will be created for you while the SurfaceView's window is
75 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
76 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
77 * Surface is created and destroyed as the window is shown and hidden.
Igor Murashkina86ab6402013-08-30 12:58:36 -070078 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070079 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070080 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070081 * this way, you need to be aware of some threading semantics:
Igor Murashkina86ab6402013-08-30 12:58:36 -070082 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070083 * <ul>
84 * <li> All SurfaceView and
85 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
86 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070087 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070088 * state that is also touched by the drawing thread.
89 * <li> You must ensure that the drawing thread only touches the underlying
90 * Surface while it is valid -- between
91 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
92 * and
93 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
94 * </ul>
Chris Craik6ee192f2016-05-17 14:29:10 -070095 *
96 * <p class="note"><strong>Note:</strong> Starting in platform version
97 * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
98 * updated synchronously with other View rendering. This means that translating
99 * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
100 * artifacts may occur on previous versions of the platform when its window is
101 * positioned asynchronously.</p>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700102 */
Vishnu Nair3b037f72019-07-22 12:55:58 -0700103public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800104 private static final String TAG = "SurfaceView";
105 private static final boolean DEBUG = false;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200106 private static final boolean DEBUG_POSITION = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700107
Mathew Inwooda570dee2018-08-17 14:56:00 +0100108 @UnsupportedAppUsage
Issei Suzukif0412592019-07-02 12:31:34 +0200109 final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<>();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700110
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800111 final int[] mLocation = new int[2];
Igor Murashkina86ab6402013-08-30 12:58:36 -0700112
Mathew Inwooda570dee2018-08-17 14:56:00 +0100113 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700114 final ReentrantLock mSurfaceLock = new ReentrantLock();
Mathew Inwooda570dee2018-08-17 14:56:00 +0100115 @UnsupportedAppUsage
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800116 final Surface mSurface = new Surface(); // Current surface in use
Mathew Inwood31755f92018-12-20 13:53:36 +0000117 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700118 boolean mDrawingStopped = true;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800119 // We use this to track if the application has produced a frame
120 // in to the Surface. Up until that point, we should be careful not to punch
121 // holes.
122 boolean mDrawFinished = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700123
Robert Carrd5c7dd62017-03-08 10:39:30 -0800124 final Rect mScreenRect = new Rect();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700125 private final SurfaceSession mSurfaceSession = new SurfaceSession();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800126
Robert Carrb923f542019-05-13 12:27:51 -0700127 SurfaceControl mSurfaceControl;
Robert Carr3bc95b52017-03-20 21:57:23 -0700128 // In the case of format changes we switch out the surface in-place
129 // we need to preserve the old one until the new one has drawn.
Robert Carrb923f542019-05-13 12:27:51 -0700130 SurfaceControl mDeferredDestroySurfaceControl;
131 SurfaceControl mBackgroundControl;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200132 final Object mSurfaceControlLock = new Object();
Robert Carr33879132016-09-06 14:41:40 -0700133 final Rect mTmpRect = new Rect();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700134
Mark Renouf34d04f32019-05-13 15:53:18 -0400135 Paint mRoundedViewportPaint;
136
Robert Carrd5c7dd62017-03-08 10:39:30 -0800137 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700138
Mathew Inwood31755f92018-12-20 13:53:36 +0000139 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700140 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700141 private volatile boolean mRtHandlingPositionUpdates = false;
Robert Carr005c63e2019-09-20 14:31:24 -0700142 private volatile boolean mRtReleaseSurfaces = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700143
Issei Suzukif0412592019-07-02 12:31:34 +0200144 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener =
145 this::updateSurface;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700146
Mathew Inwooda570dee2018-08-17 14:56:00 +0100147 @UnsupportedAppUsage
Issei Suzukif0412592019-07-02 12:31:34 +0200148 private final ViewTreeObserver.OnPreDrawListener mDrawListener = () -> {
149 // reposition ourselves where the surface is
150 mHaveFrame = getWidth() > 0 && getHeight() > 0;
151 updateSurface();
152 return true;
153 };
John Reckf6481082016-02-02 15:18:23 -0800154
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700155 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700156 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800157 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700158 boolean mViewVisibility = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700159 boolean mWindowStopped = false;
160
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 int mRequestedWidth = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000163 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700164 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700165 /* Set SurfaceView's format to 565 by default to maintain backward
166 * compatibility with applications assuming this format.
167 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100168 @UnsupportedAppUsage
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700169 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700170
Issei Suzuki006b71f2019-06-17 15:56:57 +0200171 boolean mUseAlpha = false;
172 float mSurfaceAlpha = 1f;
Mark Renoufe574ad02019-08-12 16:22:15 -0400173 boolean mClipSurfaceToBounds;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200174
Mathew Inwooda570dee2018-08-17 14:56:00 +0100175 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700176 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800177 boolean mSurfaceCreated = false;
Mathew Inwood31755f92018-12-20 13:53:36 +0000178 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700179 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700180
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700181 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800182 int mWindowSpaceLeft = -1;
183 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800184 int mSurfaceWidth = -1;
185 int mSurfaceHeight = -1;
Mark Renouf34d04f32019-05-13 15:53:18 -0400186 float mCornerRadius;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100187 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700188 int mFormat = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000189 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700190 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700191 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Romain Guyf2499fa2011-01-26 18:31:23 -0800192
Romain Guy01d5edc2011-01-28 11:28:53 -0800193 private boolean mGlobalListenersAdded;
Robert Carr8508bb22017-03-27 15:46:27 -0700194 private boolean mAttachedToWindow;
Romain Guyf2499fa2011-01-26 18:31:23 -0800195
Robert Carrd5c7dd62017-03-08 10:39:30 -0800196 private int mSurfaceFlags = SurfaceControl.HIDDEN;
197
Robert Carr8508bb22017-03-27 15:46:27 -0700198 private int mPendingReportDraws;
199
Robert Carr27a800a2018-03-16 13:33:45 -0700200 private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
chaviw9f6171e2019-06-07 16:33:50 -0700201 private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700202 private int mParentSurfaceGenerationId;
Robert Carr27a800a2018-03-16 13:33:45 -0700203
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700204 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400205 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700206 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700207
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700208 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400209 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700210 }
211
Alan Viverette617feb92013-09-09 18:09:13 -0700212 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400213 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700214 }
215
216 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
217 super(context, attrs, defStyleAttr, defStyleRes);
Adam Powell769b8632019-02-04 11:28:22 -0800218 mRenderNode.addPositionUpdateListener(mPositionListener);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700219
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700220 setWillNotDraw(true);
221 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700222
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700223 /**
224 * Return the SurfaceHolder providing access and control over this
225 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700226 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700227 * @return SurfaceHolder The holder of the surface.
228 */
229 public SurfaceHolder getHolder() {
230 return mSurfaceHolder;
231 }
232
Robert Carr414ebc62017-04-12 12:01:00 -0700233 private void updateRequestedVisibility() {
234 mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
235 }
236
Vishnu Nair3b037f72019-07-22 12:55:58 -0700237 private void setWindowStopped(boolean stopped) {
Robert Carr414ebc62017-04-12 12:01:00 -0700238 mWindowStopped = stopped;
239 updateRequestedVisibility();
240 updateSurface();
241 }
242
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700243 @Override
244 protected void onAttachedToWindow() {
245 super.onAttachedToWindow();
Robert Carr414ebc62017-04-12 12:01:00 -0700246
Vishnu Nair3b037f72019-07-22 12:55:58 -0700247 getViewRootImpl().addSurfaceChangedCallback(this);
Robert Carr00177cc2017-05-15 15:49:17 -0700248 mWindowStopped = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700249
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700250 mViewVisibility = getVisibility() == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700251 updateRequestedVisibility();
Romain Guy01d5edc2011-01-28 11:28:53 -0800252
Robert Carr8508bb22017-03-27 15:46:27 -0700253 mAttachedToWindow = true;
Karthik Ravi Shankara59c3a52017-09-11 17:36:25 -0700254 mParent.requestTransparentRegion(SurfaceView.this);
Romain Guy01d5edc2011-01-28 11:28:53 -0800255 if (!mGlobalListenersAdded) {
256 ViewTreeObserver observer = getViewTreeObserver();
257 observer.addOnScrollChangedListener(mScrollChangedListener);
258 observer.addOnPreDrawListener(mDrawListener);
259 mGlobalListenersAdded = true;
260 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700261 }
262
263 @Override
264 protected void onWindowVisibilityChanged(int visibility) {
265 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700266 mWindowVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700267 updateRequestedVisibility();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800268 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700269 }
270
271 @Override
272 public void setVisibility(int visibility) {
273 super.setVisibility(visibility);
274 mViewVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700275 boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700276 if (newRequestedVisible != mRequestedVisible) {
277 // our base class (View) invalidates the layout only when
278 // we go from/to the GONE state. However, SurfaceView needs
279 // to request a re-layout when the visibility changes at all.
280 // This is needed because the transparent region is computed
281 // as part of the layout phase, and it changes (obviously) when
282 // the visibility changes.
283 requestLayout();
284 }
285 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800286 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700287 }
Romain Guyafc3e112010-06-07 17:04:33 -0700288
Issei Suzuki006b71f2019-06-17 15:56:57 +0200289 /**
290 * Make alpha value of this view reflect onto the surface. This can only be called from at most
291 * one SurfaceView within a view tree.
292 *
293 * <p class="note"><strong>Note:</strong> Alpha value of the view is ignored and the underlying
294 * surface is rendered opaque by default.</p>
295 *
296 * @hide
297 */
298 public void setUseAlpha() {
299 if (!mUseAlpha) {
300 mUseAlpha = true;
301 updateSurfaceAlpha();
302 }
303 }
304
305 @Override
306 public void setAlpha(float alpha) {
307 // Sets the opacity of the view to a value, where 0 means the view is completely transparent
308 // and 1 means the view is completely opaque.
309 //
310 // Note: Alpha value of this view is ignored by default. To enable alpha blending, you need
311 // to call setUseAlpha() as well.
312 // This view doesn't support translucent opacity if the view is located z-below, since the
313 // logic to punch a hole in the view hierarchy cannot handle such case. See also
314 // #clearSurfaceViewPort(Canvas)
315 if (DEBUG) {
316 Log.d(TAG, System.identityHashCode(this)
317 + " setAlpha: mUseAlpha = " + mUseAlpha + " alpha=" + alpha);
318 }
319 super.setAlpha(alpha);
320 updateSurfaceAlpha();
321 }
322
323 private float getFixedAlpha() {
324 // Compute alpha value to be set on the underlying surface.
325 final float alpha = getAlpha();
326 return mUseAlpha && (mSubLayer > 0 || alpha == 0f) ? alpha : 1f;
327 }
328
329 private void updateSurfaceAlpha() {
330 if (!mUseAlpha) {
331 if (DEBUG) {
332 Log.d(TAG, System.identityHashCode(this)
333 + " updateSurfaceAlpha: setUseAlpha() is not called, ignored.");
334 }
335 return;
336 }
337 final float viewAlpha = getAlpha();
338 if (mSubLayer < 0 && 0f < viewAlpha && viewAlpha < 1f) {
339 Log.w(TAG, System.identityHashCode(this)
340 + " updateSurfaceAlpha:"
341 + " translucent color is not supported for a surface placed z-below.");
342 }
343 if (!mHaveFrame) {
344 if (DEBUG) {
345 Log.d(TAG, System.identityHashCode(this)
346 + " updateSurfaceAlpha: has no surface.");
347 }
348 return;
349 }
350 final ViewRootImpl viewRoot = getViewRootImpl();
351 if (viewRoot == null) {
352 if (DEBUG) {
353 Log.d(TAG, System.identityHashCode(this)
354 + " updateSurfaceAlpha: ViewRootImpl not available.");
355 }
356 return;
357 }
358 if (mSurfaceControl == null) {
359 if (DEBUG) {
360 Log.d(TAG, System.identityHashCode(this)
361 + "updateSurfaceAlpha:"
362 + " surface is not yet created, or already released.");
363 }
364 return;
365 }
366 final Surface parent = viewRoot.mSurface;
367 if (parent == null || !parent.isValid()) {
368 if (DEBUG) {
369 Log.d(TAG, System.identityHashCode(this)
370 + " updateSurfaceAlpha: ViewRootImpl has no valid surface");
371 }
372 return;
373 }
374 final float alpha = getFixedAlpha();
375 if (alpha != mSurfaceAlpha) {
376 if (isHardwareAccelerated()) {
377 /*
378 * Schedule a callback that reflects an alpha value onto the underlying surfaces.
379 * This gets called on a RenderThread worker thread, so members accessed here must
380 * be protected by a lock.
381 */
382 viewRoot.registerRtFrameCallback(frame -> {
383 try {
384 final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
385 synchronized (mSurfaceControlLock) {
386 if (!parent.isValid()) {
387 if (DEBUG) {
388 Log.d(TAG, System.identityHashCode(this)
389 + " updateSurfaceAlpha RT:"
390 + " ViewRootImpl has no valid surface");
391 }
392 return;
393 }
394 if (mSurfaceControl == null) {
395 if (DEBUG) {
396 Log.d(TAG, System.identityHashCode(this)
397 + "updateSurfaceAlpha RT:"
398 + " mSurfaceControl has already released");
399 }
400 return;
401 }
402 if (DEBUG) {
403 Log.d(TAG, System.identityHashCode(this)
404 + " updateSurfaceAlpha RT: set alpha=" + alpha);
405 }
406 t.setAlpha(mSurfaceControl, alpha);
407 t.deferTransactionUntilSurface(mSurfaceControl, parent, frame);
408 }
409 // It's possible that mSurfaceControl is released in the UI thread before
410 // the transaction completes. If that happens, an exception is thrown, which
411 // must be caught immediately.
412 t.apply();
413 } catch (Exception e) {
414 Log.e(TAG, System.identityHashCode(this)
415 + "updateSurfaceAlpha RT: Exception during surface transaction", e);
416 }
417 });
418 damageInParent();
419 } else {
420 if (DEBUG) {
421 Log.d(TAG, System.identityHashCode(this)
422 + " updateSurfaceAlpha: set alpha=" + alpha);
423 }
chaviw619da692019-06-10 15:39:40 -0700424 mTmpTransaction.setAlpha(mSurfaceControl, alpha).apply();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200425 }
426 mSurfaceAlpha = alpha;
427 }
428 }
429
Robert Carrb53670a2017-05-25 18:20:49 -0700430 private void performDrawFinished() {
431 if (mPendingReportDraws > 0) {
432 mDrawFinished = true;
433 if (mAttachedToWindow) {
Pengfei Zhao15617202019-02-28 17:07:41 +0800434 mParent.requestTransparentRegion(SurfaceView.this);
Robert Carrb53670a2017-05-25 18:20:49 -0700435 notifyDrawFinished();
436 invalidate();
437 }
438 } else {
439 Log.e(TAG, System.identityHashCode(this) + "finished drawing"
440 + " but no pending report draw (extra call"
441 + " to draw completion runnable?)");
442 }
443 }
444
Robert Carr8508bb22017-03-27 15:46:27 -0700445 void notifyDrawFinished() {
446 ViewRootImpl viewRoot = getViewRootImpl();
447 if (viewRoot != null) {
448 viewRoot.pendingDrawFinished();
449 }
450 mPendingReportDraws--;
451 }
452
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700453 @Override
John Reck77e4a522014-10-01 10:38:07 -0700454 protected void onDetachedFromWindow() {
Lucas Dupin0c207342017-04-14 19:47:23 -0700455 ViewRootImpl viewRoot = getViewRootImpl();
456 // It's possible to create a SurfaceView using the default constructor and never
457 // attach it to a view hierarchy, this is a common use case when dealing with
458 // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
459 // the lifecycle. Instead of attaching it to a view, he/she can just pass
460 // the SurfaceHolder forward, most live wallpapers do it.
461 if (viewRoot != null) {
Vishnu Nair3b037f72019-07-22 12:55:58 -0700462 viewRoot.removeSurfaceChangedCallback(this);
Lucas Dupin0c207342017-04-14 19:47:23 -0700463 }
Robert Carr414ebc62017-04-12 12:01:00 -0700464
Robert Carr8508bb22017-03-27 15:46:27 -0700465 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800466 if (mGlobalListenersAdded) {
467 ViewTreeObserver observer = getViewTreeObserver();
468 observer.removeOnScrollChangedListener(mScrollChangedListener);
469 observer.removeOnPreDrawListener(mDrawListener);
470 mGlobalListenersAdded = false;
471 }
472
Robert Carr8508bb22017-03-27 15:46:27 -0700473 while (mPendingReportDraws > 0) {
474 notifyDrawFinished();
475 }
476
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700477 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800478
Robert Carrd5c7dd62017-03-08 10:39:30 -0800479 updateSurface();
Issei Suzuki006b71f2019-06-17 15:56:57 +0200480 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800481 mHaveFrame = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700482
John Reck77e4a522014-10-01 10:38:07 -0700483 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700484 }
485
486 @Override
487 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800488 int width = mRequestedWidth >= 0
489 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
490 : getDefaultSize(0, widthMeasureSpec);
491 int height = mRequestedHeight >= 0
492 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
493 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700494 setMeasuredDimension(width, height);
495 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700496
Mathias Agopianef115302010-10-04 20:15:08 -0700497 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700498 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100499 @UnsupportedAppUsage
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700500 protected boolean setFrame(int left, int top, int right, int bottom) {
501 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800502 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700503 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700504 }
505
506 @Override
507 public boolean gatherTransparentRegion(Region region) {
Robert Carr3ca12be72017-05-22 14:57:48 -0700508 if (isAboveParent() || !mDrawFinished) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700509 return super.gatherTransparentRegion(region);
510 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700511
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700512 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700513 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700514 // this view draws, remove it from the transparent region
515 opaque = super.gatherTransparentRegion(region);
516 } else if (region != null) {
517 int w = getWidth();
518 int h = getHeight();
519 if (w>0 && h>0) {
520 getLocationInWindow(mLocation);
521 // otherwise, punch a hole in the whole hierarchy
522 int l = mLocation[0];
523 int t = mLocation[1];
524 region.op(l, t, l+w, t+h, Region.Op.UNION);
525 }
526 }
527 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
528 opaque = false;
529 }
530 return opaque;
531 }
532
533 @Override
534 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800535 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700536 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700537 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700538 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400539 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700540 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700541 }
542 super.draw(canvas);
543 }
544
545 @Override
546 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800547 if (mDrawFinished && !isAboveParent()) {
548 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700549 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700550 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400551 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700552 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700553 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700554 super.dispatchDraw(canvas);
555 }
556
Mark Renoufe574ad02019-08-12 16:22:15 -0400557 /**
558 * Control whether the surface is clipped to the same bounds as the View. If true, then
559 * the bounds set by {@link #setClipBounds(Rect)} are applied to the surface as window-crop.
560 *
561 * @param enabled whether to enable surface clipping
562 * @hide
563 */
564 public void setEnableSurfaceClipping(boolean enabled) {
565 mClipSurfaceToBounds = enabled;
566 invalidate();
567 }
568
569 @Override
570 public void setClipBounds(Rect clipBounds) {
571 super.setClipBounds(clipBounds);
572
573 if (!mClipSurfaceToBounds) {
574 return;
575 }
576
577 // When cornerRadius is non-zero, a draw() is required to update
578 // the viewport (rounding the corners of the clipBounds).
579 if (mCornerRadius > 0f && !isAboveParent()) {
580 invalidate();
581 }
582
583 if (mSurfaceControl != null) {
584 if (mClipBounds != null) {
585 mTmpRect.set(mClipBounds);
586 } else {
587 mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
588 }
589 SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this);
590 applier.scheduleApply(
591 new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl)
592 .withWindowCrop(mTmpRect)
593 .build());
594 }
595 }
596
Mark Renouf34d04f32019-05-13 15:53:18 -0400597 private void clearSurfaceViewPort(Canvas canvas) {
598 if (mCornerRadius > 0f) {
599 canvas.getClipBounds(mTmpRect);
Mark Renoufe574ad02019-08-12 16:22:15 -0400600 if (mClipSurfaceToBounds && mClipBounds != null) {
601 mTmpRect.intersect(mClipBounds);
602 }
Mark Renouf34d04f32019-05-13 15:53:18 -0400603 canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
604 mCornerRadius, mCornerRadius, mRoundedViewportPaint);
605 } else {
606 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
607 }
608 }
609
610 /**
611 * Sets the corner radius for the SurfaceView. This will round both the corners of the
612 * underlying surface, as well as the corners of the hole created to expose the surface.
613 *
614 * @param cornerRadius the new radius of the corners in pixels
615 * @hide
616 */
617 public void setCornerRadius(float cornerRadius) {
618 mCornerRadius = cornerRadius;
619 if (mCornerRadius > 0f && mRoundedViewportPaint == null) {
620 mRoundedViewportPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
621 mRoundedViewportPaint.setBlendMode(BlendMode.CLEAR);
622 mRoundedViewportPaint.setColor(0);
623 }
624 invalidate();
625 }
626
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700627 /**
Mark Renoufe574ad02019-08-12 16:22:15 -0400628 * Returns the corner radius for the SurfaceView.
629
630 * @return the radius of the corners in pixels
631 * @hide
632 */
633 public float getCornerRadius() {
634 return mCornerRadius;
635 }
636
637 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700638 * Control whether the surface view's surface is placed on top of another
639 * regular surface view in the window (but still behind the window itself).
640 * This is typically used to place overlays on top of an underlying media
641 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700642 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700643 * <p>Note that this must be set before the surface view's containing
644 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700645 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700646 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
647 */
648 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800649 mSubLayer = isMediaOverlay
650 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700651 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700652
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700653 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700654 * Control whether the surface view's surface is placed on top of its
655 * window. Normally it is placed behind the window, to allow it to
656 * (for the most part) appear to composite with the views in the
657 * hierarchy. By setting this, you cause it to be placed above the
658 * window. This means that none of the contents of the window this
659 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700660 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700661 * <p>Note that this must be set before the surface view's containing
662 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700663 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700664 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700665 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700666 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500667 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800668 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500669 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800670 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500671 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700672 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700673
674 /**
675 * Control whether the surface view's content should be treated as secure,
676 * preventing it from appearing in screenshots or from being viewed on
677 * non-secure displays.
678 *
679 * <p>Note that this must be set before the surface view's containing
680 * window is attached to the window manager.
681 *
682 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
683 *
684 * @param isSecure True if the surface view is secure.
685 */
686 public void setSecure(boolean isSecure) {
687 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800688 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700689 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800690 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700691 }
692 }
693
Robert Carr55235552017-06-02 14:21:03 -0700694 private void updateOpaqueFlag() {
Robert Carr851e7e42017-06-06 14:04:50 -0700695 if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
Robert Carr55235552017-06-02 14:21:03 -0700696 mSurfaceFlags |= SurfaceControl.OPAQUE;
697 } else {
698 mSurfaceFlags &= ~SurfaceControl.OPAQUE;
699 }
700 }
701
chaviw619da692019-06-10 15:39:40 -0700702 private void updateBackgroundVisibility(Transaction t) {
Robert Carrb923f542019-05-13 12:27:51 -0700703 if (mBackgroundControl == null) {
704 return;
705 }
706 if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
chaviw619da692019-06-10 15:39:40 -0700707 t.show(mBackgroundControl);
Robert Carrb923f542019-05-13 12:27:51 -0700708 } else {
chaviw619da692019-06-10 15:39:40 -0700709 t.hide(mBackgroundControl);
Robert Carrb923f542019-05-13 12:27:51 -0700710 }
711 }
712
chaviw619da692019-06-10 15:39:40 -0700713
Robert Carrb923f542019-05-13 12:27:51 -0700714 private void releaseSurfaces() {
Robert Carr005c63e2019-09-20 14:31:24 -0700715 mSurfaceAlpha = 1f;
716
Issei Suzuki006b71f2019-06-17 15:56:57 +0200717 synchronized (mSurfaceControlLock) {
Robert Carrde63cc62019-10-25 13:18:29 -0700718 mSurface.release();
719
Robert Carr005c63e2019-09-20 14:31:24 -0700720 if (mRtHandlingPositionUpdates) {
721 mRtReleaseSurfaces = true;
722 return;
723 }
724
Issei Suzuki006b71f2019-06-17 15:56:57 +0200725 if (mSurfaceControl != null) {
726 mTmpTransaction.remove(mSurfaceControl);
727 mSurfaceControl = null;
728 }
729 if (mBackgroundControl != null) {
730 mTmpTransaction.remove(mBackgroundControl);
731 mBackgroundControl = null;
732 }
733 mTmpTransaction.apply();
Robert Carrb923f542019-05-13 12:27:51 -0700734 }
Robert Carrb923f542019-05-13 12:27:51 -0700735 }
736
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900737 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800738 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700739 if (!mHaveFrame) {
Issei Suzuki006b71f2019-06-17 15:56:57 +0200740 if (DEBUG) {
741 Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
742 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700743 return;
744 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800745 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800746 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
Issei Suzuki006b71f2019-06-17 15:56:57 +0200747 if (DEBUG) {
748 Log.d(TAG, System.identityHashCode(this)
749 + " updateSurface: no valid surface");
750 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800751 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700752 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700753
Issei Suzukif0412592019-07-02 12:31:34 +0200754 final Translator translator = viewRoot.mTranslator;
755 if (translator != null) {
756 mSurface.setCompatibilityTranslator(translator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700757 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700758
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700759 int myWidth = mRequestedWidth;
760 if (myWidth <= 0) myWidth = getWidth();
761 int myHeight = mRequestedHeight;
762 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700763
Issei Suzuki006b71f2019-06-17 15:56:57 +0200764 final float alpha = getFixedAlpha();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700765 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700766 final boolean visibleChanged = mVisible != mRequestedVisible;
Issei Suzuki006b71f2019-06-17 15:56:57 +0200767 final boolean alphaChanged = mSurfaceAlpha != alpha;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700768 final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
Robert Carrd5c7dd62017-03-08 10:39:30 -0800769 && mRequestedVisible;
770 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800771 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700772 boolean redrawNeeded = false;
773
Issei Suzuki006b71f2019-06-17 15:56:57 +0200774 if (creating || formatChanged || sizeChanged || visibleChanged || (mUseAlpha
775 && alphaChanged) || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800776 getLocationInWindow(mLocation);
777
John Reckaa6e84f2016-06-16 15:36:13 -0700778 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
779 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700780 + " format=" + formatChanged + " size=" + sizeChanged
Issei Suzuki006b71f2019-06-17 15:56:57 +0200781 + " visible=" + visibleChanged + " alpha=" + alphaChanged
782 + " mUseAlpha=" + mUseAlpha
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700783 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800784 + " left=" + (mWindowSpaceLeft != mLocation[0])
785 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700786
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700787 try {
788 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800789 mWindowSpaceLeft = mLocation[0];
790 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800791 mSurfaceWidth = myWidth;
792 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700793 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800794 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700795
Robert Carrd5c7dd62017-03-08 10:39:30 -0800796 mScreenRect.left = mWindowSpaceLeft;
797 mScreenRect.top = mWindowSpaceTop;
798 mScreenRect.right = mWindowSpaceLeft + getWidth();
799 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Issei Suzukif0412592019-07-02 12:31:34 +0200800 if (translator != null) {
801 translator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700802 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700803
Issei Suzuki006b71f2019-06-17 15:56:57 +0200804 final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800805 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
806
807 if (creating) {
Robert Carr3bc95b52017-03-20 21:57:23 -0700808 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carr55235552017-06-02 14:21:03 -0700809
810 updateOpaqueFlag();
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700811 // SurfaceView hierarchy
812 // ViewRootImpl surface
813 // - bounds layer (crops all child surfaces to parent surface insets)
814 // - SurfaceView surface (drawn relative to ViewRootImpl surface)
815 // - Background color layer (drawn behind all SurfaceView surfaces)
816 //
817 // The bounds layer is used to crop the surface view so it does not draw into
818 // the parent surface inset region. Since there can be multiple surface views
819 // below or above the parent surface, one option is to create multiple bounds
820 // layer for each z order. The other option, the one implement is to create
821 // a single bounds layer and set z order for each child surface relative to the
822 // parent surface.
823 // When creating the surface view, we parent it to the bounds layer and then
824 // set the relative z order. When the parent surface changes, we have to
825 // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback.
Robert Carre625fcf2017-09-01 12:36:28 -0700826 final String name = "SurfaceView - " + viewRoot.getTitle().toString();
Vishnu Naireaab0e52019-06-24 08:12:28 -0700827
828 mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
829 .setName(name)
830 .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
831 .setBufferSize(mSurfaceWidth, mSurfaceHeight)
832 .setFormat(mFormat)
Vishnu Nair8cb00ae2019-08-02 15:20:29 -0700833 .setParent(viewRoot.getBoundsLayer())
Vishnu Naireaab0e52019-06-24 08:12:28 -0700834 .setFlags(mSurfaceFlags)
835 .build();
Robert Carrb923f542019-05-13 12:27:51 -0700836 mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
837 .setName("Background for -" + name)
838 .setOpaque(true)
839 .setColorLayer()
840 .setParent(mSurfaceControl)
841 .build();
842
Robert Carr44ab5752017-03-20 21:47:11 -0700843 } else if (mSurfaceControl == null) {
844 return;
Robert Carr64aadd02015-11-06 13:54:20 -0800845 }
846
Robert Carrd5c7dd62017-03-08 10:39:30 -0800847 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800848
Dianne Hackborn726426e2010-03-31 22:04:36 -0700849 mSurfaceLock.lock();
850 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700851 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700852
John Reckaa6e84f2016-06-16 15:36:13 -0700853 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
854 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800855
chaviw619da692019-06-10 15:39:40 -0700856 // If we are creating the surface control or the parent surface has not
857 // changed, then set relative z. Otherwise allow the parent
858 // SurfaceChangedCallback to update the relative z. This is needed so that
859 // we do not change the relative z before the server is ready to swap the
860 // parent surface.
861 if (creating || (mParentSurfaceGenerationId
862 == viewRoot.mSurface.getGenerationId())) {
863 updateRelativeZ(mTmpTransaction);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700864 }
chaviw619da692019-06-10 15:39:40 -0700865 mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
866
867 if (mViewVisibility) {
868 mTmpTransaction.show(mSurfaceControl);
869 } else {
870 mTmpTransaction.hide(mSurfaceControl);
871 }
872 updateBackgroundVisibility(mTmpTransaction);
873 if (mUseAlpha) {
874 mTmpTransaction.setAlpha(mSurfaceControl, alpha);
875 mSurfaceAlpha = alpha;
876 }
877
878 // While creating the surface, we will set it's initial
879 // geometry. Outside of that though, we should generally
880 // leave it to the RenderThread.
881 //
882 // There is one more case when the buffer size changes we aren't yet
883 // prepared to sync (as even following the transaction applying
884 // we still need to latch a buffer).
885 // b/28866173
886 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
887 mTmpTransaction.setPosition(mSurfaceControl, mScreenRect.left,
888 mScreenRect.top);
889 mTmpTransaction.setMatrix(mSurfaceControl,
890 mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f,
891 mScreenRect.height() / (float) mSurfaceHeight);
892 // Set a window crop when creating the surface or changing its size to
893 // crop the buffer to the surface size since the buffer producer may
894 // use SCALING_MODE_SCALE and submit a larger size than the surface
895 // size.
896 if (mClipSurfaceToBounds && mClipBounds != null) {
897 mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
898 } else {
899 mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
900 mSurfaceHeight);
901 }
902 }
903 mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
904 if (sizeChanged && !creating) {
905 mTmpTransaction.setBufferSize(mSurfaceControl, mSurfaceWidth,
906 mSurfaceHeight);
907 }
908
909 mTmpTransaction.apply();
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800910
Robert Carrd5c7dd62017-03-08 10:39:30 -0800911 if (sizeChanged || creating) {
912 redrawNeeded = true;
913 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800914
Dianne Hackborn726426e2010-03-31 22:04:36 -0700915 mSurfaceFrame.left = 0;
916 mSurfaceFrame.top = 0;
Issei Suzukif0412592019-07-02 12:31:34 +0200917 if (translator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800918 mSurfaceFrame.right = mSurfaceWidth;
919 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700920 } else {
Issei Suzukif0412592019-07-02 12:31:34 +0200921 float appInvertedScale = translator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800922 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
923 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700924 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700925
Dianne Hackborn726426e2010-03-31 22:04:36 -0700926 final int surfaceWidth = mSurfaceFrame.right;
927 final int surfaceHeight = mSurfaceFrame.bottom;
928 realSizeChanged = mLastSurfaceWidth != surfaceWidth
929 || mLastSurfaceHeight != surfaceHeight;
930 mLastSurfaceWidth = surfaceWidth;
931 mLastSurfaceHeight = surfaceHeight;
932 } finally {
933 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700934 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700935
936 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800937 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700938
Issei Suzuki60557b52019-07-03 20:04:48 +0200939 SurfaceHolder.Callback[] callbacks = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700940
Robert Carrd5c7dd62017-03-08 10:39:30 -0800941 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800942 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
943 mSurfaceCreated = false;
944 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700945 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
946 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800947 callbacks = getSurfaceCallbacks();
948 for (SurfaceHolder.Callback c : callbacks) {
949 c.surfaceDestroyed(mSurfaceHolder);
950 }
Robert Carr387838b2016-09-07 14:12:44 -0700951 // Since Android N the same surface may be reused and given to us
952 // again by the system server at a later point. However
953 // as we didn't do this in previous releases, clients weren't
954 // necessarily required to clean up properly in
955 // surfaceDestroyed. This leads to problems for example when
956 // clients don't destroy their EGL context, and try
957 // and create a new one on the same surface following reuse.
958 // Since there is no valid use of the surface in-between
959 // surfaceDestroyed and surfaceCreated, we force a disconnect,
960 // so the next connect will always work if we end up reusing
961 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700962 if (mSurface.isValid()) {
963 mSurface.forceScopedDisconnect();
964 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700965 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800966 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700967
Robert Carrd5c7dd62017-03-08 10:39:30 -0800968 if (creating) {
Robert Carrb923f542019-05-13 12:27:51 -0700969 mSurface.copyFrom(mSurfaceControl);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800970 }
971
Bryce Lee453fc362017-06-20 10:47:55 -0700972 if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
Bryce Lee02949f12017-06-16 07:20:34 -0700973 < Build.VERSION_CODES.O) {
974 // Some legacy applications use the underlying native {@link Surface} object
975 // as a key to whether anything has changed. In these cases, updates to the
976 // existing {@link Surface} will be ignored when the size changes.
977 // Therefore, we must explicitly recreate the {@link Surface} in these
978 // cases.
Robert Carrb923f542019-05-13 12:27:51 -0700979 mSurface.createFrom(mSurfaceControl);
Bryce Lee02949f12017-06-16 07:20:34 -0700980 }
981
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200982 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800983 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
984 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700985 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700986 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
987 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800988 if (callbacks == null) {
989 callbacks = getSurfaceCallbacks();
990 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700991 for (SurfaceHolder.Callback c : callbacks) {
992 c.surfaceCreated(mSurfaceHolder);
993 }
994 }
995 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700996 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700997 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
998 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800999 + " w=" + myWidth + " h=" + myHeight);
1000 if (callbacks == null) {
1001 callbacks = getSurfaceCallbacks();
1002 }
Dianne Hackborn251fd432010-07-14 16:56:31 -07001003 for (SurfaceHolder.Callback c : callbacks) {
1004 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
1005 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001006 }
1007 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -07001008 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
1009 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001010 if (callbacks == null) {
1011 callbacks = getSurfaceCallbacks();
1012 }
Robert Carr8508bb22017-03-27 15:46:27 -07001013
1014 mPendingReportDraws++;
1015 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -08001016 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -08001017 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -08001018 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001019 }
1020 }
1021 } finally {
1022 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001023 if (mSurfaceControl != null && !mSurfaceCreated) {
Robert Carrb923f542019-05-13 12:27:51 -07001024 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -08001025 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001026 }
Robert Carrd5c7dd62017-03-08 10:39:30 -08001027 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -07001028 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001029 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001030 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -08001031 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
1032 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
1033 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -07001034 } else {
1035 // Calculate the window position in case RT loses the window
1036 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -08001037 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -08001038 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
1039 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -08001040 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
1041 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -08001042 if (positionChanged || layoutSizeChanged) { // Only the position has changed
1043 mWindowSpaceLeft = mLocation[0];
1044 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -08001045 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -08001046 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -08001047 mLocation[0] = getWidth();
1048 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -08001049
Robert Carrd5c7dd62017-03-08 10:39:30 -08001050 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
Robert Carrc90e5f82017-07-18 13:10:02 -07001051 mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
John Reckf057fb52016-04-15 13:46:29 -07001052
Issei Suzukif0412592019-07-02 12:31:34 +02001053 if (translator != null) {
1054 translator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -07001055 }
1056
Robert Carr3651ab82017-04-25 12:05:34 -07001057 if (mSurfaceControl == null) {
1058 return;
1059 }
1060
Bryce Lee16e50892017-04-11 01:59:37 +00001061 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
John Reckf23a1b82016-06-22 14:23:31 -07001062 try {
Issei Suzuki006b71f2019-06-17 15:56:57 +02001063 if (DEBUG_POSITION) {
1064 Log.d(TAG, String.format("%d updateSurfacePosition UI, "
1065 + "position = [%d, %d, %d, %d]",
1066 System.identityHashCode(this),
1067 mScreenRect.left, mScreenRect.top,
1068 mScreenRect.right, mScreenRect.bottom));
1069 }
Robert Carrd5c7dd62017-03-08 10:39:30 -08001070 setParentSpaceRectangle(mScreenRect, -1);
1071 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -07001072 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -07001073 }
John Reckf6481082016-02-02 15:18:23 -08001074 }
Rob Carr64e516f2015-10-29 00:20:45 +00001075 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001076 }
1077 }
1078
Robert Carrd5c7dd62017-03-08 10:39:30 -08001079 private void onDrawFinished() {
1080 if (DEBUG) {
1081 Log.i(TAG, System.identityHashCode(this) + " "
1082 + "finishedDrawing");
1083 }
Robert Carr3bc95b52017-03-20 21:57:23 -07001084
1085 if (mDeferredDestroySurfaceControl != null) {
chaviw9f6171e2019-06-07 16:33:50 -07001086 mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
Robert Carr3bc95b52017-03-20 21:57:23 -07001087 mDeferredDestroySurfaceControl = null;
1088 }
1089
Issei Suzuki60557b52019-07-03 20:04:48 +02001090 runOnUiThread(this::performDrawFinished);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001091 }
1092
Robert Carr27a800a2018-03-16 13:33:45 -07001093 /**
1094 * A place to over-ride for applying child-surface transactions.
1095 * These can be synchronized with the viewroot surface using deferTransaction.
1096 *
1097 * Called from RenderWorker while UI thread is paused.
1098 * @hide
1099 */
1100 protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
1101 Surface viewRootSurface, long nextViewRootFrameNumber) {
1102 }
1103
Robert Carr386fd702018-03-23 13:46:39 -07001104 private void applySurfaceTransforms(SurfaceControl surface, Rect position, long frameNumber) {
Robert Carr27a800a2018-03-16 13:33:45 -07001105 if (frameNumber > 0) {
Robert Carr386fd702018-03-23 13:46:39 -07001106 final ViewRootImpl viewRoot = getViewRootImpl();
1107
1108 mRtTransaction.deferTransactionUntilSurface(surface, viewRoot.mSurface,
Robert Carr27a800a2018-03-16 13:33:45 -07001109 frameNumber);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001110 }
Robert Carr386fd702018-03-23 13:46:39 -07001111
1112 mRtTransaction.setPosition(surface, position.left, position.top);
1113 mRtTransaction.setMatrix(surface,
Robert Carr27a800a2018-03-16 13:33:45 -07001114 position.width() / (float) mSurfaceWidth,
1115 0.0f, 0.0f,
1116 position.height() / (float) mSurfaceHeight);
John Reckd0abd662019-05-01 12:52:04 -07001117 if (mViewVisibility) {
1118 mRtTransaction.show(surface);
1119 }
Robert Carr386fd702018-03-23 13:46:39 -07001120 }
1121
1122 private void setParentSpaceRectangle(Rect position, long frameNumber) {
1123 final ViewRootImpl viewRoot = getViewRootImpl();
1124
Robert Carrb923f542019-05-13 12:27:51 -07001125 applySurfaceTransforms(mSurfaceControl, position, frameNumber);
Robert Carr27a800a2018-03-16 13:33:45 -07001126
1127 applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface,
1128 frameNumber);
1129
1130 mRtTransaction.apply();
Robert Carrd5c7dd62017-03-08 10:39:30 -08001131 }
1132
John Reckf6481082016-02-02 15:18:23 -08001133 private Rect mRTLastReportedPosition = new Rect();
1134
John Reck6b164402018-09-24 15:25:42 -07001135 private RenderNode.PositionUpdateListener mPositionListener =
1136 new RenderNode.PositionUpdateListener() {
Robert Carrd5c7dd62017-03-08 10:39:30 -08001137
John Reck6b164402018-09-24 15:25:42 -07001138 @Override
1139 public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
1140 if (mSurfaceControl == null) {
1141 return;
John Reckf6481082016-02-02 15:18:23 -08001142 }
John Reckf6481082016-02-02 15:18:23 -08001143
John Reck6b164402018-09-24 15:25:42 -07001144 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
1145 // its 2nd frame if RenderThread is running slowly could potentially see
1146 // this as false, enter the branch, get pre-empted, then this comes along
1147 // and reports a new position, then the UI thread resumes and reports
1148 // its position. This could therefore be de-sync'd in that interval, but
1149 // the synchronization would violate the rule that RT must never block
1150 // on the UI thread which would open up potential deadlocks. The risk of
1151 // a single-frame desync is therefore preferable for now.
Robert Carr005c63e2019-09-20 14:31:24 -07001152 synchronized(mSurfaceControlLock) {
1153 mRtHandlingPositionUpdates = true;
1154 }
John Reck6b164402018-09-24 15:25:42 -07001155 if (mRTLastReportedPosition.left == left
1156 && mRTLastReportedPosition.top == top
1157 && mRTLastReportedPosition.right == right
1158 && mRTLastReportedPosition.bottom == bottom) {
1159 return;
1160 }
1161 try {
Issei Suzuki006b71f2019-06-17 15:56:57 +02001162 if (DEBUG_POSITION) {
John Reck6b164402018-09-24 15:25:42 -07001163 Log.d(TAG, String.format(
1164 "%d updateSurfacePosition RenderWorker, frameNr = %d, "
Issei Suzuki60557b52019-07-03 20:04:48 +02001165 + "position = [%d, %d, %d, %d]",
John Reck6b164402018-09-24 15:25:42 -07001166 System.identityHashCode(this), frameNumber,
1167 left, top, right, bottom));
1168 }
1169 mRTLastReportedPosition.set(left, top, right, bottom);
1170 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
1171 // Now overwrite mRTLastReportedPosition with our values
1172 } catch (Exception ex) {
1173 Log.e(TAG, "Exception from repositionChild", ex);
1174 }
John Reckaa6e84f2016-06-16 15:36:13 -07001175 }
Robert Carrad3a4932017-06-20 14:55:21 -07001176
John Reck6b164402018-09-24 15:25:42 -07001177 @Override
1178 public void positionLost(long frameNumber) {
1179 if (DEBUG) {
1180 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
1181 System.identityHashCode(this), frameNumber));
1182 }
1183 mRTLastReportedPosition.setEmpty();
1184
1185 if (mSurfaceControl == null) {
1186 return;
1187 }
John Reckd0abd662019-05-01 12:52:04 -07001188
Robert Carr94210482019-09-26 10:44:16 -07001189 final ViewRootImpl viewRoot = getViewRootImpl();
1190 if (frameNumber > 0 && viewRoot != null) {
1191 if (viewRoot.mSurface.isValid()) {
1192 mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface,
1193 frameNumber);
1194 }
John Reckf23a1b82016-06-22 14:23:31 -07001195 }
Robert Carrb923f542019-05-13 12:27:51 -07001196 mRtTransaction.hide(mSurfaceControl);
Robert Carr005c63e2019-09-20 14:31:24 -07001197
1198 synchronized (mSurfaceControlLock) {
1199 if (mRtReleaseSurfaces) {
1200 mRtReleaseSurfaces = false;
1201 mRtTransaction.remove(mSurfaceControl);
1202 mRtTransaction.remove(mBackgroundControl);
1203 mSurfaceControl = null;
1204 mBackgroundControl = null;
1205 }
1206 mRtHandlingPositionUpdates = false;
1207 }
1208
John Reckd0abd662019-05-01 12:52:04 -07001209 mRtTransaction.apply();
John Reckf23a1b82016-06-22 14:23:31 -07001210 }
John Reck6b164402018-09-24 15:25:42 -07001211 };
John Reckaa6e84f2016-06-16 15:36:13 -07001212
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001213 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
Issei Suzuki60557b52019-07-03 20:04:48 +02001214 SurfaceHolder.Callback[] callbacks;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001215 synchronized (mCallbacks) {
1216 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
1217 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001218 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001219 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001220 }
1221
John Reck79925002017-05-26 13:57:14 -07001222 private void runOnUiThread(Runnable runnable) {
1223 Handler handler = getHandler();
1224 if (handler != null && handler.getLooper() != Looper.myLooper()) {
1225 handler.post(runnable);
1226 } else {
1227 runnable.run();
1228 }
1229 }
1230
Yohei Yukawa3b5011a2017-03-16 15:34:12 -07001231 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -04001232 * Check to see if the surface has fixed size dimensions or if the surface's
1233 * dimensions are dimensions are dependent on its current layout.
1234 *
1235 * @return true if the surface has dimensions that are fixed in size
1236 * @hide
1237 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01001238 @UnsupportedAppUsage
Derek Sollenberger7179b812010-03-22 13:41:20 -04001239 public boolean isFixedSize() {
1240 return (mRequestedWidth != -1 || mRequestedHeight != -1);
1241 }
1242
Robert Carrd5c7dd62017-03-08 10:39:30 -08001243 private boolean isAboveParent() {
1244 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001245 }
1246
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001247 /**
1248 * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
1249 * and size of the content hasn't updated yet. This color will fill the expanded area when the
1250 * view becomes larger.
1251 * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
1252 * @hide
1253 */
1254 public void setResizeBackgroundColor(int bgColor) {
Robert Carrb923f542019-05-13 12:27:51 -07001255 if (mBackgroundControl == null) {
1256 return;
1257 }
1258
1259 final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
1260 Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
1261
chaviw619da692019-06-10 15:39:40 -07001262 mTmpTransaction.setColor(mBackgroundControl, colorComponents).apply();
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001263 }
1264
Mathew Inwooda570dee2018-08-17 14:56:00 +01001265 @UnsupportedAppUsage
Igor Murashkina86ab6402013-08-30 12:58:36 -07001266 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001267 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -07001268
1269 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001270 public boolean isCreating() {
1271 return mIsCreating;
1272 }
1273
Igor Murashkina86ab6402013-08-30 12:58:36 -07001274 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001275 public void addCallback(Callback callback) {
1276 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -07001277 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001278 // have only a couple callbacks, so it doesn't matter.
Issei Suzukif0412592019-07-02 12:31:34 +02001279 if (!mCallbacks.contains(callback)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001280 mCallbacks.add(callback);
1281 }
1282 }
1283 }
1284
Igor Murashkina86ab6402013-08-30 12:58:36 -07001285 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001286 public void removeCallback(Callback callback) {
1287 synchronized (mCallbacks) {
1288 mCallbacks.remove(callback);
1289 }
1290 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001291
1292 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001293 public void setFixedSize(int width, int height) {
1294 if (mRequestedWidth != width || mRequestedHeight != height) {
1295 mRequestedWidth = width;
1296 mRequestedHeight = height;
1297 requestLayout();
1298 }
1299 }
1300
Igor Murashkina86ab6402013-08-30 12:58:36 -07001301 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001302 public void setSizeFromLayout() {
1303 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
1304 mRequestedWidth = mRequestedHeight = -1;
1305 requestLayout();
1306 }
1307 }
1308
Igor Murashkina86ab6402013-08-30 12:58:36 -07001309 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001310 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -07001311 // for backward compatibility reason, OPAQUE always
1312 // means 565 for SurfaceView
1313 if (format == PixelFormat.OPAQUE)
1314 format = PixelFormat.RGB_565;
1315
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001316 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001317 if (mSurfaceControl != null) {
1318 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001319 }
1320 }
1321
Mathias Agopiand2112302010-12-07 19:38:17 -08001322 /**
1323 * @deprecated setType is now ignored.
1324 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001325 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -08001326 @Deprecated
1327 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001328
Igor Murashkina86ab6402013-08-30 12:58:36 -07001329 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001330 public void setKeepScreenOn(boolean screenOn) {
John Reck79925002017-05-26 13:57:14 -07001331 runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001332 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001333
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001334 /**
1335 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1336 *
1337 * After drawing into the provided {@link Canvas}, the caller must
1338 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1339 *
1340 * The caller must redraw the entire surface.
1341 * @return A canvas for drawing into the surface.
1342 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001343 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001344 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -07001345 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001346 }
1347
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001348 /**
1349 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1350 *
1351 * After drawing into the provided {@link Canvas}, the caller must
1352 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1353 *
1354 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1355 * to redraw. This function may choose to expand the dirty rectangle if for example
1356 * the surface has been resized or if the previous contents of the surface were
1357 * not available. The caller must redraw the entire dirty region as represented
1358 * by the contents of the inOutDirty rectangle upon return from this function.
1359 * The caller may also pass <code>null</code> instead, in the case where the
1360 * entire surface should be redrawn.
1361 * @return A canvas for drawing into the surface.
1362 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001363 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001364 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -07001365 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001366 }
1367
John Reck6bc70142016-10-26 16:49:17 -07001368 @Override
1369 public Canvas lockHardwareCanvas() {
1370 return internalLockCanvas(null, true);
1371 }
1372
1373 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001374 mSurfaceLock.lock();
1375
John Reckaa6e84f2016-06-16 15:36:13 -07001376 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001377 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001378
1379 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001380 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001381 try {
John Reck6bc70142016-10-26 16:49:17 -07001382 if (hardware) {
1383 c = mSurface.lockHardwareCanvas();
1384 } else {
1385 c = mSurface.lockCanvas(dirty);
1386 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001387 } catch (Exception e) {
1388 Log.e(LOG_TAG, "Exception locking surface", e);
1389 }
1390 }
1391
John Reckaa6e84f2016-06-16 15:36:13 -07001392 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001393 if (c != null) {
1394 mLastLockTime = SystemClock.uptimeMillis();
1395 return c;
1396 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001397
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001398 // If the Surface is not ready to be drawn, then return null,
1399 // but throttle calls to this function so it isn't called more
1400 // than every 100ms.
1401 long now = SystemClock.uptimeMillis();
1402 long nextTime = mLastLockTime + 100;
1403 if (nextTime > now) {
1404 try {
1405 Thread.sleep(nextTime-now);
1406 } catch (InterruptedException e) {
1407 }
1408 now = SystemClock.uptimeMillis();
1409 }
1410 mLastLockTime = now;
1411 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001412
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001413 return null;
1414 }
1415
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001416 /**
1417 * Posts the new contents of the {@link Canvas} to the surface and
1418 * releases the {@link Canvas}.
1419 *
1420 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1421 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001422 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001423 public void unlockCanvasAndPost(Canvas canvas) {
1424 mSurface.unlockCanvasAndPost(canvas);
1425 mSurfaceLock.unlock();
1426 }
1427
Igor Murashkina86ab6402013-08-30 12:58:36 -07001428 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001429 public Surface getSurface() {
1430 return mSurface;
1431 }
1432
Igor Murashkina86ab6402013-08-30 12:58:36 -07001433 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001434 public Rect getSurfaceFrame() {
1435 return mSurfaceFrame;
1436 }
1437 };
Robert Carr55235552017-06-02 14:21:03 -07001438
chaviwff2e7d82018-11-02 11:11:27 -07001439 /**
Robert Carr76907ee2019-01-11 13:38:19 -08001440 * Return a SurfaceControl which can be used for parenting Surfaces to
1441 * this SurfaceView.
1442 *
1443 * @return The SurfaceControl for this SurfaceView.
chaviwff2e7d82018-11-02 11:11:27 -07001444 */
1445 public SurfaceControl getSurfaceControl() {
Robert Carrb923f542019-05-13 12:27:51 -07001446 return mSurfaceControl;
chaviwff2e7d82018-11-02 11:11:27 -07001447 }
Vishnu Nair3b037f72019-07-22 12:55:58 -07001448
1449 /**
Vishnu Nair5cf253192019-11-07 15:33:20 -08001450 * @return The token used to identify the windows input channel.
1451 * @hide
1452 */
1453 @TestApi
1454 public @Nullable IBinder getInputToken() {
1455 final ViewRootImpl viewRoot = getViewRootImpl();
1456 if (viewRoot == null) {
1457 return null;
1458 }
1459 return viewRoot.getInputToken();
1460 }
1461
1462 /**
Vishnu Nair3b037f72019-07-22 12:55:58 -07001463 * Set window stopped to false and update surface visibility when ViewRootImpl surface is
1464 * created.
1465 * @hide
1466 */
1467 @Override
1468 public void surfaceCreated(SurfaceControl.Transaction t) {
1469 setWindowStopped(false);
1470 }
1471
1472 /**
1473 * Set window stopped to true and update surface visibility when ViewRootImpl surface is
1474 * destroyed.
1475 * @hide
1476 */
1477 @Override
1478 public void surfaceDestroyed() {
1479 setWindowStopped(true);
1480 }
1481
1482 /**
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001483 * Called when a valid ViewRootImpl surface is replaced by another valid surface. In this
1484 * case update relative z to the new parent surface.
Vishnu Nair3b037f72019-07-22 12:55:58 -07001485 * @hide
1486 */
1487 @Override
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001488 public void surfaceReplaced(Transaction t) {
1489 if (mSurfaceControl != null && mBackgroundControl != null) {
chaviw619da692019-06-10 15:39:40 -07001490 updateRelativeZ(t);
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001491 }
1492 }
Vishnu Nair3b037f72019-07-22 12:55:58 -07001493
chaviw619da692019-06-10 15:39:40 -07001494 private void updateRelativeZ(Transaction t) {
Vishnu Nair8cb00ae2019-08-02 15:20:29 -07001495 SurfaceControl viewRoot = getViewRootImpl().getSurfaceControl();
1496 t.setRelativeLayer(mBackgroundControl, viewRoot, Integer.MIN_VALUE);
1497 t.setRelativeLayer(mSurfaceControl, viewRoot, mSubLayer);
Vishnu Nair3b037f72019-07-22 12:55:58 -07001498 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001499}