blob: ee8d66313ea2aa90a4699621d0ae95905ded78de [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
Mathew Inwooda570dee2018-08-17 14:56:00 +010023import android.annotation.UnsupportedAppUsage;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070024import android.content.Context;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070025import android.content.res.CompatibilityInfo.Translator;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070026import android.content.res.Configuration;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070027import android.graphics.Canvas;
Andrii Kuliancf8f6832018-01-23 19:43:30 -080028import android.graphics.Color;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070029import android.graphics.PixelFormat;
30import android.graphics.PorterDuff;
31import android.graphics.Rect;
32import android.graphics.Region;
John Reck32f140aa62018-10-04 15:08:24 -070033import android.graphics.RenderNode;
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070034import android.os.Build;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070035import android.os.Handler;
John Reck79925002017-05-26 13:57:14 -070036import android.os.Looper;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070037import android.os.SystemClock;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070038import android.util.AttributeSet;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070039import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070040
Robert Carr25cfa132016-11-16 13:24:09 -080041import com.android.internal.view.SurfaceCallbackHelper;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070042
Jon Larimer9bdf5762009-01-02 18:55:15 -050043import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070044import java.util.concurrent.locks.ReentrantLock;
45
46/**
47 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
48 * You can control the format of this surface and, if you like, its size; the
49 * SurfaceView takes care of placing the surface at the correct location on the
50 * screen
Igor Murashkina86ab6402013-08-30 12:58:36 -070051 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070052 * <p>The surface is Z ordered so that it is behind the window holding its
53 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070054 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070055 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070056 * 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 -070057 * buttons on top of the Surface, though note however that it can have an
58 * impact on performance since a full alpha-blended composite will be performed
59 * each time the Surface changes.
Igor Murashkina86ab6402013-08-30 12:58:36 -070060 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070061 * <p> The transparent region that makes the surface visible is based on the
62 * layout positions in the view hierarchy. If the post-layout transform
63 * properties are used to draw a sibling view on top of the SurfaceView, the
64 * view may not be properly composited with the surface.
65 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070066 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
67 * which can be retrieved by calling {@link #getHolder}.
Igor Murashkina86ab6402013-08-30 12:58:36 -070068 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070069 * <p>The Surface will be created for you while the SurfaceView's window is
70 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
71 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
72 * Surface is created and destroyed as the window is shown and hidden.
Igor Murashkina86ab6402013-08-30 12:58:36 -070073 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070074 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070075 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070076 * this way, you need to be aware of some threading semantics:
Igor Murashkina86ab6402013-08-30 12:58:36 -070077 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070078 * <ul>
79 * <li> All SurfaceView and
80 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
81 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070082 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070083 * state that is also touched by the drawing thread.
84 * <li> You must ensure that the drawing thread only touches the underlying
85 * Surface while it is valid -- between
86 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
87 * and
88 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
89 * </ul>
Chris Craik6ee192f2016-05-17 14:29:10 -070090 *
91 * <p class="note"><strong>Note:</strong> Starting in platform version
92 * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
93 * updated synchronously with other View rendering. This means that translating
94 * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
95 * artifacts may occur on previous versions of the platform when its window is
96 * positioned asynchronously.</p>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070097 */
Robert Carr414ebc62017-04-12 12:01:00 -070098public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback {
Robert Carrd5c7dd62017-03-08 10:39:30 -080099 private static final String TAG = "SurfaceView";
100 private static final boolean DEBUG = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700101
Mathew Inwooda570dee2018-08-17 14:56:00 +0100102 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700103 final ArrayList<SurfaceHolder.Callback> mCallbacks
104 = new ArrayList<SurfaceHolder.Callback>();
105
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800106 final int[] mLocation = new int[2];
Igor Murashkina86ab6402013-08-30 12:58:36 -0700107
Mathew Inwooda570dee2018-08-17 14:56:00 +0100108 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700109 final ReentrantLock mSurfaceLock = new ReentrantLock();
Mathew Inwooda570dee2018-08-17 14:56:00 +0100110 @UnsupportedAppUsage
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800111 final Surface mSurface = new Surface(); // Current surface in use
Mathew Inwood31755f92018-12-20 13:53:36 +0000112 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700113 boolean mDrawingStopped = true;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800114 // We use this to track if the application has produced a frame
115 // in to the Surface. Up until that point, we should be careful not to punch
116 // holes.
117 boolean mDrawFinished = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700118
Robert Carrd5c7dd62017-03-08 10:39:30 -0800119 final Rect mScreenRect = new Rect();
120 SurfaceSession mSurfaceSession;
121
Robert Carr18a82192019-01-15 13:11:46 -0800122 SurfaceControl mSurfaceControl;
Robert Carr3bc95b52017-03-20 21:57:23 -0700123 // In the case of format changes we switch out the surface in-place
124 // we need to preserve the old one until the new one has drawn.
125 SurfaceControl mDeferredDestroySurfaceControl;
Robert Carr18a82192019-01-15 13:11:46 -0800126 SurfaceControl mBackgroundControl;
Robert Carr33879132016-09-06 14:41:40 -0700127 final Rect mTmpRect = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700128 final Configuration mConfiguration = new Configuration();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700129
Robert Carrd5c7dd62017-03-08 10:39:30 -0800130 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700131
Mathew Inwood31755f92018-12-20 13:53:36 +0000132 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700133 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700134 private volatile boolean mRtHandlingPositionUpdates = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700135
John Reckf6481082016-02-02 15:18:23 -0800136 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700137 = new ViewTreeObserver.OnScrollChangedListener() {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700138 @Override
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700139 public void onScrollChanged() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800140 updateSurface();
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700141 }
142 };
Igor Murashkina86ab6402013-08-30 12:58:36 -0700143
Mathew Inwooda570dee2018-08-17 14:56:00 +0100144 @UnsupportedAppUsage
John Reckf6481082016-02-02 15:18:23 -0800145 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
146 new ViewTreeObserver.OnPreDrawListener() {
147 @Override
148 public boolean onPreDraw() {
149 // reposition ourselves where the surface is
150 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800151 updateSurface();
John Reckf6481082016-02-02 15:18:23 -0800152 return true;
153 }
154 };
155
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700156 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700157 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800158 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700159 boolean mViewVisibility = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700160 boolean mWindowStopped = false;
161
Mathew Inwood31755f92018-12-20 13:53:36 +0000162 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700163 int mRequestedWidth = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000164 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700165 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700166 /* Set SurfaceView's format to 565 by default to maintain backward
167 * compatibility with applications assuming this format.
168 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100169 @UnsupportedAppUsage
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700170 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700171
Mathew Inwooda570dee2018-08-17 14:56:00 +0100172 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700173 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800174 boolean mSurfaceCreated = false;
Mathew Inwood31755f92018-12-20 13:53:36 +0000175 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700176 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700177
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700178 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800179 int mWindowSpaceLeft = -1;
180 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800181 int mSurfaceWidth = -1;
182 int mSurfaceHeight = -1;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100183 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700184 int mFormat = -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 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700187 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700188 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800189
Romain Guy01d5edc2011-01-28 11:28:53 -0800190 private boolean mGlobalListenersAdded;
Robert Carr8508bb22017-03-27 15:46:27 -0700191 private boolean mAttachedToWindow;
Romain Guyf2499fa2011-01-26 18:31:23 -0800192
Robert Carrd5c7dd62017-03-08 10:39:30 -0800193 private int mSurfaceFlags = SurfaceControl.HIDDEN;
194
Robert Carr8508bb22017-03-27 15:46:27 -0700195 private int mPendingReportDraws;
196
Robert Carr27a800a2018-03-16 13:33:45 -0700197 private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
198
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700199 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400200 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700201 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700202
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700203 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400204 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700205 }
206
Alan Viverette617feb92013-09-09 18:09:13 -0700207 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400208 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700209 }
210
211 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
212 super(context, attrs, defStyleAttr, defStyleRes);
Adam Powell769b8632019-02-04 11:28:22 -0800213 mRenderNode.addPositionUpdateListener(mPositionListener);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700214
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700215 setWillNotDraw(true);
216 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700217
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700218 /**
219 * Return the SurfaceHolder providing access and control over this
220 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700221 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700222 * @return SurfaceHolder The holder of the surface.
223 */
224 public SurfaceHolder getHolder() {
225 return mSurfaceHolder;
226 }
227
Robert Carr414ebc62017-04-12 12:01:00 -0700228 private void updateRequestedVisibility() {
229 mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
230 }
231
232 /** @hide */
233 @Override
234 public void windowStopped(boolean stopped) {
235 mWindowStopped = stopped;
236 updateRequestedVisibility();
237 updateSurface();
238 }
239
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700240 @Override
241 protected void onAttachedToWindow() {
242 super.onAttachedToWindow();
Robert Carr414ebc62017-04-12 12:01:00 -0700243
244 getViewRootImpl().addWindowStoppedCallback(this);
Robert Carr00177cc2017-05-15 15:49:17 -0700245 mWindowStopped = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700246
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700247 mViewVisibility = getVisibility() == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700248 updateRequestedVisibility();
Romain Guy01d5edc2011-01-28 11:28:53 -0800249
Robert Carr8508bb22017-03-27 15:46:27 -0700250 mAttachedToWindow = true;
Karthik Ravi Shankara59c3a52017-09-11 17:36:25 -0700251 mParent.requestTransparentRegion(SurfaceView.this);
Romain Guy01d5edc2011-01-28 11:28:53 -0800252 if (!mGlobalListenersAdded) {
253 ViewTreeObserver observer = getViewTreeObserver();
254 observer.addOnScrollChangedListener(mScrollChangedListener);
255 observer.addOnPreDrawListener(mDrawListener);
256 mGlobalListenersAdded = true;
257 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700258 }
259
260 @Override
261 protected void onWindowVisibilityChanged(int visibility) {
262 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700263 mWindowVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700264 updateRequestedVisibility();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800265 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700266 }
267
268 @Override
269 public void setVisibility(int visibility) {
270 super.setVisibility(visibility);
271 mViewVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700272 boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700273 if (newRequestedVisible != mRequestedVisible) {
274 // our base class (View) invalidates the layout only when
275 // we go from/to the GONE state. However, SurfaceView needs
276 // to request a re-layout when the visibility changes at all.
277 // This is needed because the transparent region is computed
278 // as part of the layout phase, and it changes (obviously) when
279 // the visibility changes.
280 requestLayout();
281 }
282 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800283 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700284 }
Romain Guyafc3e112010-06-07 17:04:33 -0700285
Robert Carrb53670a2017-05-25 18:20:49 -0700286 private void performDrawFinished() {
287 if (mPendingReportDraws > 0) {
288 mDrawFinished = true;
289 if (mAttachedToWindow) {
Robert Carrb53670a2017-05-25 18:20:49 -0700290 notifyDrawFinished();
291 invalidate();
292 }
293 } else {
294 Log.e(TAG, System.identityHashCode(this) + "finished drawing"
295 + " but no pending report draw (extra call"
296 + " to draw completion runnable?)");
297 }
298 }
299
Robert Carr8508bb22017-03-27 15:46:27 -0700300 void notifyDrawFinished() {
301 ViewRootImpl viewRoot = getViewRootImpl();
302 if (viewRoot != null) {
303 viewRoot.pendingDrawFinished();
304 }
305 mPendingReportDraws--;
306 }
307
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700308 @Override
John Reck77e4a522014-10-01 10:38:07 -0700309 protected void onDetachedFromWindow() {
Lucas Dupin0c207342017-04-14 19:47:23 -0700310 ViewRootImpl viewRoot = getViewRootImpl();
311 // It's possible to create a SurfaceView using the default constructor and never
312 // attach it to a view hierarchy, this is a common use case when dealing with
313 // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
314 // the lifecycle. Instead of attaching it to a view, he/she can just pass
315 // the SurfaceHolder forward, most live wallpapers do it.
316 if (viewRoot != null) {
317 viewRoot.removeWindowStoppedCallback(this);
318 }
Robert Carr414ebc62017-04-12 12:01:00 -0700319
Robert Carr8508bb22017-03-27 15:46:27 -0700320 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800321 if (mGlobalListenersAdded) {
322 ViewTreeObserver observer = getViewTreeObserver();
323 observer.removeOnScrollChangedListener(mScrollChangedListener);
324 observer.removeOnPreDrawListener(mDrawListener);
325 mGlobalListenersAdded = false;
326 }
327
Robert Carr8508bb22017-03-27 15:46:27 -0700328 while (mPendingReportDraws > 0) {
329 notifyDrawFinished();
330 }
331
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700332 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800333
Robert Carrd5c7dd62017-03-08 10:39:30 -0800334 updateSurface();
335 if (mSurfaceControl != null) {
Robert Carr5ea304d2019-02-04 16:04:55 -0800336 mSurfaceControl.remove();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800337 }
338 mSurfaceControl = null;
339
340 mHaveFrame = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700341
John Reck77e4a522014-10-01 10:38:07 -0700342 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700343 }
344
345 @Override
346 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800347 int width = mRequestedWidth >= 0
348 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
349 : getDefaultSize(0, widthMeasureSpec);
350 int height = mRequestedHeight >= 0
351 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
352 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700353 setMeasuredDimension(width, height);
354 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700355
Mathias Agopianef115302010-10-04 20:15:08 -0700356 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700357 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100358 @UnsupportedAppUsage
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700359 protected boolean setFrame(int left, int top, int right, int bottom) {
360 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800361 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700362 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700363 }
364
365 @Override
366 public boolean gatherTransparentRegion(Region region) {
Robert Carr3ca12be72017-05-22 14:57:48 -0700367 if (isAboveParent() || !mDrawFinished) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700368 return super.gatherTransparentRegion(region);
369 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700370
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700371 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700372 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700373 // this view draws, remove it from the transparent region
374 opaque = super.gatherTransparentRegion(region);
375 } else if (region != null) {
376 int w = getWidth();
377 int h = getHeight();
378 if (w>0 && h>0) {
379 getLocationInWindow(mLocation);
380 // otherwise, punch a hole in the whole hierarchy
381 int l = mLocation[0];
382 int t = mLocation[1];
383 region.op(l, t, l+w, t+h, Region.Op.UNION);
384 }
385 }
386 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
387 opaque = false;
388 }
389 return opaque;
390 }
391
392 @Override
393 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800394 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700395 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700396 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700397 // punch a whole in the view-hierarchy below us
398 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
399 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700400 }
401 super.draw(canvas);
402 }
403
404 @Override
405 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800406 if (mDrawFinished && !isAboveParent()) {
407 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700408 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700409 // punch a whole in the view-hierarchy below us
410 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
411 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700412 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700413 super.dispatchDraw(canvas);
414 }
415
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700416 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700417 * Control whether the surface view's surface is placed on top of another
418 * regular surface view in the window (but still behind the window itself).
419 * This is typically used to place overlays on top of an underlying media
420 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700421 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700422 * <p>Note that this must be set before the surface view's containing
423 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700424 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700425 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
426 */
427 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800428 mSubLayer = isMediaOverlay
429 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700430 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700431
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700432 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700433 * Control whether the surface view's surface is placed on top of its
434 * window. Normally it is placed behind the window, to allow it to
435 * (for the most part) appear to composite with the views in the
436 * hierarchy. By setting this, you cause it to be placed above the
437 * window. This means that none of the contents of the window this
438 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700439 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700440 * <p>Note that this must be set before the surface view's containing
441 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700442 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700443 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700444 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700445 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500446 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800447 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500448 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800449 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500450 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700451 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700452
453 /**
454 * Control whether the surface view's content should be treated as secure,
455 * preventing it from appearing in screenshots or from being viewed on
456 * non-secure displays.
457 *
458 * <p>Note that this must be set before the surface view's containing
459 * window is attached to the window manager.
460 *
461 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
462 *
463 * @param isSecure True if the surface view is secure.
464 */
465 public void setSecure(boolean isSecure) {
466 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800467 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700468 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800469 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700470 }
471 }
472
Robert Carr55235552017-06-02 14:21:03 -0700473 private void updateOpaqueFlag() {
Robert Carr851e7e42017-06-06 14:04:50 -0700474 if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
Robert Carr55235552017-06-02 14:21:03 -0700475 mSurfaceFlags |= SurfaceControl.OPAQUE;
476 } else {
477 mSurfaceFlags &= ~SurfaceControl.OPAQUE;
478 }
479 }
480
Robert Carrd5c7dd62017-03-08 10:39:30 -0800481 private Rect getParentSurfaceInsets() {
482 final ViewRootImpl root = getViewRootImpl();
483 if (root == null) {
484 return null;
485 } else {
486 return root.mWindowAttributes.surfaceInsets;
487 }
Jeff Tinker3896db12017-03-03 00:20:22 +0000488 }
489
Robert Carr18a82192019-01-15 13:11:46 -0800490 private void updateBackgroundVisibilityInTransaction() {
491 if (mBackgroundControl == null) {
492 return;
493 }
Robert Carrd76074a2019-02-04 12:24:17 -0800494 if ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) {
Robert Carr18a82192019-01-15 13:11:46 -0800495 mBackgroundControl.show();
496 mBackgroundControl.setLayer(Integer.MIN_VALUE);
497 } else {
498 mBackgroundControl.hide();
499 }
500 }
501
502 private void releaseSurfaces() {
503 if (mSurfaceControl != null) {
Robert Carr5ea304d2019-02-04 16:04:55 -0800504 mSurfaceControl.remove();
Robert Carr18a82192019-01-15 13:11:46 -0800505 mSurfaceControl = null;
506 }
507 if (mBackgroundControl != null) {
Robert Carr5ea304d2019-02-04 16:04:55 -0800508 mBackgroundControl.remove();
Robert Carr18a82192019-01-15 13:11:46 -0800509 mBackgroundControl = null;
510 }
511 }
512
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900513 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800514 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700515 if (!mHaveFrame) {
516 return;
517 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800518 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800519 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
520 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700521 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700522
Robert Carrd5c7dd62017-03-08 10:39:30 -0800523 mTranslator = viewRoot.mTranslator;
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700524 if (mTranslator != null) {
525 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700526 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700527
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700528 int myWidth = mRequestedWidth;
529 if (myWidth <= 0) myWidth = getWidth();
530 int myHeight = mRequestedHeight;
531 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700532
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700533 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700534 final boolean visibleChanged = mVisible != mRequestedVisible;
535 final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
Robert Carrd5c7dd62017-03-08 10:39:30 -0800536 && mRequestedVisible;
537 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800538 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700539 boolean redrawNeeded = false;
540
Robert Carrd5c7dd62017-03-08 10:39:30 -0800541 if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800542 getLocationInWindow(mLocation);
543
John Reckaa6e84f2016-06-16 15:36:13 -0700544 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
545 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700546 + " format=" + formatChanged + " size=" + sizeChanged
547 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800548 + " left=" + (mWindowSpaceLeft != mLocation[0])
549 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700550
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700551 try {
552 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800553 mWindowSpaceLeft = mLocation[0];
554 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800555 mSurfaceWidth = myWidth;
556 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700557 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800558 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700559
Robert Carrd5c7dd62017-03-08 10:39:30 -0800560 mScreenRect.left = mWindowSpaceLeft;
561 mScreenRect.top = mWindowSpaceTop;
562 mScreenRect.right = mWindowSpaceLeft + getWidth();
563 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700564 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800565 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700566 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700567
Robert Carrd5c7dd62017-03-08 10:39:30 -0800568 final Rect surfaceInsets = getParentSurfaceInsets();
569 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
570
571 if (creating) {
Vishnu Nairb040c012018-09-07 11:38:32 -0700572 viewRoot.createBoundsSurface(mSubLayer);
Robert Carr5fea55b2018-12-10 13:05:52 -0800573 mSurfaceSession = new SurfaceSession();
Robert Carr3bc95b52017-03-20 21:57:23 -0700574 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carr55235552017-06-02 14:21:03 -0700575
576 updateOpaqueFlag();
Robert Carre625fcf2017-09-01 12:36:28 -0700577 final String name = "SurfaceView - " + viewRoot.getTitle().toString();
578
Robert Carr18a82192019-01-15 13:11:46 -0800579 mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
580 .setName(name)
581 .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
582 .setBufferSize(mSurfaceWidth, mSurfaceHeight)
583 .setFormat(mFormat)
584 .setParent(viewRoot.getSurfaceControl())
585 .setFlags(mSurfaceFlags)
586 .build();
587 mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
588 .setName("Background for -" + name)
589 .setOpaque(true)
Chavi Weingarten6ef9cc62019-02-07 16:28:45 +0000590 .setColorLayer()
Robert Carr18a82192019-01-15 13:11:46 -0800591 .setParent(mSurfaceControl)
592 .build();
593
Robert Carr44ab5752017-03-20 21:47:11 -0700594 } else if (mSurfaceControl == null) {
595 return;
Robert Carr64aadd02015-11-06 13:54:20 -0800596 }
597
Robert Carrd5c7dd62017-03-08 10:39:30 -0800598 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800599
Dianne Hackborn726426e2010-03-31 22:04:36 -0700600 mSurfaceLock.lock();
601 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700602 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700603
John Reckaa6e84f2016-06-16 15:36:13 -0700604 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
605 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800606
Robert Carrd5c7dd62017-03-08 10:39:30 -0800607 SurfaceControl.openTransaction();
608 try {
609 mSurfaceControl.setLayer(mSubLayer);
Robert Carr18a82192019-01-15 13:11:46 -0800610
Robert Carrd5c7dd62017-03-08 10:39:30 -0800611 if (mViewVisibility) {
612 mSurfaceControl.show();
613 } else {
614 mSurfaceControl.hide();
615 }
Robert Carr18a82192019-01-15 13:11:46 -0800616 updateBackgroundVisibilityInTransaction();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800617
618 // While creating the surface, we will set it's initial
619 // geometry. Outside of that though, we should generally
620 // leave it to the RenderThread.
Robert Carr511719f2017-03-13 15:27:15 -0700621 //
622 // There is one more case when the buffer size changes we aren't yet
623 // prepared to sync (as even following the transaction applying
624 // we still need to latch a buffer).
625 // b/28866173
626 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800627 mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
628 mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
629 0.0f, 0.0f,
630 mScreenRect.height() / (float) mSurfaceHeight);
Vishnu Naire86bd982018-11-28 13:23:17 -0800631 // Set a window crop when creating the surface or changing its size to
632 // crop the buffer to the surface size since the buffer producer may
633 // use SCALING_MODE_SCALE and submit a larger size than the surface
634 // size.
635 mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800636 }
youngmin0822.lee4dde7d12018-07-09 14:25:32 +0900637 if (sizeChanged && !creating) {
Vishnu Naire86bd982018-11-28 13:23:17 -0800638 mSurfaceControl.setBufferSize(mSurfaceWidth, mSurfaceHeight);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800639 }
640 } finally {
641 SurfaceControl.closeTransaction();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700642 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800643
Robert Carrd5c7dd62017-03-08 10:39:30 -0800644 if (sizeChanged || creating) {
645 redrawNeeded = true;
646 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800647
Dianne Hackborn726426e2010-03-31 22:04:36 -0700648 mSurfaceFrame.left = 0;
649 mSurfaceFrame.top = 0;
650 if (mTranslator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800651 mSurfaceFrame.right = mSurfaceWidth;
652 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700653 } else {
654 float appInvertedScale = mTranslator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800655 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
656 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700657 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700658
Dianne Hackborn726426e2010-03-31 22:04:36 -0700659 final int surfaceWidth = mSurfaceFrame.right;
660 final int surfaceHeight = mSurfaceFrame.bottom;
661 realSizeChanged = mLastSurfaceWidth != surfaceWidth
662 || mLastSurfaceHeight != surfaceHeight;
663 mLastSurfaceWidth = surfaceWidth;
664 mLastSurfaceHeight = surfaceHeight;
665 } finally {
666 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700667 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700668
669 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800670 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700671
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800672 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700673
Robert Carrd5c7dd62017-03-08 10:39:30 -0800674 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800675 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
676 mSurfaceCreated = false;
677 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700678 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
679 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800680 callbacks = getSurfaceCallbacks();
681 for (SurfaceHolder.Callback c : callbacks) {
682 c.surfaceDestroyed(mSurfaceHolder);
683 }
Robert Carr387838b2016-09-07 14:12:44 -0700684 // Since Android N the same surface may be reused and given to us
685 // again by the system server at a later point. However
686 // as we didn't do this in previous releases, clients weren't
687 // necessarily required to clean up properly in
688 // surfaceDestroyed. This leads to problems for example when
689 // clients don't destroy their EGL context, and try
690 // and create a new one on the same surface following reuse.
691 // Since there is no valid use of the surface in-between
692 // surfaceDestroyed and surfaceCreated, we force a disconnect,
693 // so the next connect will always work if we end up reusing
694 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700695 if (mSurface.isValid()) {
696 mSurface.forceScopedDisconnect();
697 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700698 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800699 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700700
Robert Carrd5c7dd62017-03-08 10:39:30 -0800701 if (creating) {
702 mSurface.copyFrom(mSurfaceControl);
703 }
704
Bryce Lee453fc362017-06-20 10:47:55 -0700705 if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
Bryce Lee02949f12017-06-16 07:20:34 -0700706 < Build.VERSION_CODES.O) {
707 // Some legacy applications use the underlying native {@link Surface} object
708 // as a key to whether anything has changed. In these cases, updates to the
709 // existing {@link Surface} will be ignored when the size changes.
710 // Therefore, we must explicitly recreate the {@link Surface} in these
711 // cases.
712 mSurface.createFrom(mSurfaceControl);
713 }
714
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200715 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800716 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
717 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700718 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700719 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
720 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800721 if (callbacks == null) {
722 callbacks = getSurfaceCallbacks();
723 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700724 for (SurfaceHolder.Callback c : callbacks) {
725 c.surfaceCreated(mSurfaceHolder);
726 }
727 }
728 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700729 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700730 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
731 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800732 + " w=" + myWidth + " h=" + myHeight);
733 if (callbacks == null) {
734 callbacks = getSurfaceCallbacks();
735 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700736 for (SurfaceHolder.Callback c : callbacks) {
737 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
738 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700739 }
740 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -0700741 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
742 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800743 if (callbacks == null) {
744 callbacks = getSurfaceCallbacks();
745 }
Robert Carr8508bb22017-03-27 15:46:27 -0700746
747 mPendingReportDraws++;
748 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -0800749 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -0800750 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -0800751 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700752 }
753 }
754 } finally {
755 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800756 if (mSurfaceControl != null && !mSurfaceCreated) {
Robert Carrde844432017-05-04 13:45:45 -0700757 mSurface.release();
Robert Carr29daa922018-04-27 11:56:48 -0700758
Robert Carr18a82192019-01-15 13:11:46 -0800759 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800760 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700761 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800762 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700763 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700764 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800765 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -0800766 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
767 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
768 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -0700769 } else {
770 // Calculate the window position in case RT loses the window
771 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -0800772 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -0800773 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
774 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800775 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
776 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -0800777 if (positionChanged || layoutSizeChanged) { // Only the position has changed
778 mWindowSpaceLeft = mLocation[0];
779 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800780 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -0800781 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800782 mLocation[0] = getWidth();
783 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -0800784
Robert Carrd5c7dd62017-03-08 10:39:30 -0800785 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
Robert Carrc90e5f82017-07-18 13:10:02 -0700786 mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
John Reckf057fb52016-04-15 13:46:29 -0700787
788 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800789 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -0700790 }
791
Robert Carr3651ab82017-04-25 12:05:34 -0700792 if (mSurfaceControl == null) {
793 return;
794 }
795
Bryce Lee16e50892017-04-11 01:59:37 +0000796 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
John Reckf23a1b82016-06-22 14:23:31 -0700797 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800798 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
John Reckf23a1b82016-06-22 14:23:31 -0700799 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800800 mScreenRect.left, mScreenRect.top,
801 mScreenRect.right, mScreenRect.bottom));
802 setParentSpaceRectangle(mScreenRect, -1);
803 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700804 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -0700805 }
John Reckf6481082016-02-02 15:18:23 -0800806 }
Rob Carr64e516f2015-10-29 00:20:45 +0000807 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700808 }
809 }
810
Robert Carrd5c7dd62017-03-08 10:39:30 -0800811 private void onDrawFinished() {
812 if (DEBUG) {
813 Log.i(TAG, System.identityHashCode(this) + " "
814 + "finishedDrawing");
815 }
Robert Carr3bc95b52017-03-20 21:57:23 -0700816
817 if (mDeferredDestroySurfaceControl != null) {
Robert Carr5ea304d2019-02-04 16:04:55 -0800818 mDeferredDestroySurfaceControl.remove();
Robert Carr3bc95b52017-03-20 21:57:23 -0700819 mDeferredDestroySurfaceControl = null;
820 }
821
John Reck79925002017-05-26 13:57:14 -0700822 runOnUiThread(() -> {
Robert Carrb53670a2017-05-25 18:20:49 -0700823 performDrawFinished();
John Reck79925002017-05-26 13:57:14 -0700824 });
Robert Carrd5c7dd62017-03-08 10:39:30 -0800825 }
826
Robert Carr27a800a2018-03-16 13:33:45 -0700827 /**
828 * A place to over-ride for applying child-surface transactions.
829 * These can be synchronized with the viewroot surface using deferTransaction.
830 *
831 * Called from RenderWorker while UI thread is paused.
832 * @hide
833 */
834 protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
835 Surface viewRootSurface, long nextViewRootFrameNumber) {
836 }
837
Robert Carr386fd702018-03-23 13:46:39 -0700838 private void applySurfaceTransforms(SurfaceControl surface, Rect position, long frameNumber) {
Robert Carr27a800a2018-03-16 13:33:45 -0700839 if (frameNumber > 0) {
Robert Carr386fd702018-03-23 13:46:39 -0700840 final ViewRootImpl viewRoot = getViewRootImpl();
841
842 mRtTransaction.deferTransactionUntilSurface(surface, viewRoot.mSurface,
Robert Carr27a800a2018-03-16 13:33:45 -0700843 frameNumber);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800844 }
Robert Carr386fd702018-03-23 13:46:39 -0700845
846 mRtTransaction.setPosition(surface, position.left, position.top);
847 mRtTransaction.setMatrix(surface,
Robert Carr27a800a2018-03-16 13:33:45 -0700848 position.width() / (float) mSurfaceWidth,
849 0.0f, 0.0f,
850 position.height() / (float) mSurfaceHeight);
Robert Carr386fd702018-03-23 13:46:39 -0700851 }
852
853 private void setParentSpaceRectangle(Rect position, long frameNumber) {
854 final ViewRootImpl viewRoot = getViewRootImpl();
855
856 applySurfaceTransforms(mSurfaceControl, position, frameNumber);
Robert Carr27a800a2018-03-16 13:33:45 -0700857
858 applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface,
859 frameNumber);
860
861 mRtTransaction.apply();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800862 }
863
John Reckf6481082016-02-02 15:18:23 -0800864 private Rect mRTLastReportedPosition = new Rect();
865
John Reck6b164402018-09-24 15:25:42 -0700866 private RenderNode.PositionUpdateListener mPositionListener =
867 new RenderNode.PositionUpdateListener() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800868
John Reck6b164402018-09-24 15:25:42 -0700869 @Override
870 public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
871 if (mSurfaceControl == null) {
872 return;
John Reckf6481082016-02-02 15:18:23 -0800873 }
John Reckf6481082016-02-02 15:18:23 -0800874
John Reck6b164402018-09-24 15:25:42 -0700875 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
876 // its 2nd frame if RenderThread is running slowly could potentially see
877 // this as false, enter the branch, get pre-empted, then this comes along
878 // and reports a new position, then the UI thread resumes and reports
879 // its position. This could therefore be de-sync'd in that interval, but
880 // the synchronization would violate the rule that RT must never block
881 // on the UI thread which would open up potential deadlocks. The risk of
882 // a single-frame desync is therefore preferable for now.
883 mRtHandlingPositionUpdates = true;
884 if (mRTLastReportedPosition.left == left
885 && mRTLastReportedPosition.top == top
886 && mRTLastReportedPosition.right == right
887 && mRTLastReportedPosition.bottom == bottom) {
888 return;
889 }
890 try {
891 if (DEBUG) {
892 Log.d(TAG, String.format(
893 "%d updateSurfacePosition RenderWorker, frameNr = %d, "
894 + "postion = [%d, %d, %d, %d]",
895 System.identityHashCode(this), frameNumber,
896 left, top, right, bottom));
897 }
898 mRTLastReportedPosition.set(left, top, right, bottom);
899 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
900 // Now overwrite mRTLastReportedPosition with our values
901 } catch (Exception ex) {
902 Log.e(TAG, "Exception from repositionChild", ex);
903 }
John Reckaa6e84f2016-06-16 15:36:13 -0700904 }
Robert Carrad3a4932017-06-20 14:55:21 -0700905
John Reck6b164402018-09-24 15:25:42 -0700906 @Override
907 public void positionLost(long frameNumber) {
908 if (DEBUG) {
909 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
910 System.identityHashCode(this), frameNumber));
911 }
912 mRTLastReportedPosition.setEmpty();
913
914 if (mSurfaceControl == null) {
915 return;
916 }
917 if (mRtHandlingPositionUpdates) {
918 mRtHandlingPositionUpdates = false;
919 // This callback will happen while the UI thread is blocked, so we can
920 // safely access other member variables at this time.
921 // So do what the UI thread would have done if RT wasn't handling position
922 // updates.
923 if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
924 try {
925 if (DEBUG) {
926 Log.d(TAG, String.format("%d updateSurfacePosition, "
927 + "postion = [%d, %d, %d, %d]",
928 System.identityHashCode(this),
929 mScreenRect.left, mScreenRect.top,
930 mScreenRect.right, mScreenRect.bottom));
931 }
932 setParentSpaceRectangle(mScreenRect, frameNumber);
933 } catch (Exception ex) {
934 Log.e(TAG, "Exception configuring surface", ex);
935 }
John Reckf23a1b82016-06-22 14:23:31 -0700936 }
937 }
John Reckf23a1b82016-06-22 14:23:31 -0700938 }
John Reck6b164402018-09-24 15:25:42 -0700939 };
John Reckaa6e84f2016-06-16 15:36:13 -0700940
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800941 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
942 SurfaceHolder.Callback callbacks[];
943 synchronized (mCallbacks) {
944 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
945 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700946 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800947 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700948 }
949
John Reck79925002017-05-26 13:57:14 -0700950 private void runOnUiThread(Runnable runnable) {
951 Handler handler = getHandler();
952 if (handler != null && handler.getLooper() != Looper.myLooper()) {
953 handler.post(runnable);
954 } else {
955 runnable.run();
956 }
957 }
958
Yohei Yukawa3b5011a2017-03-16 15:34:12 -0700959 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -0400960 * Check to see if the surface has fixed size dimensions or if the surface's
961 * dimensions are dimensions are dependent on its current layout.
962 *
963 * @return true if the surface has dimensions that are fixed in size
964 * @hide
965 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100966 @UnsupportedAppUsage
Derek Sollenberger7179b812010-03-22 13:41:20 -0400967 public boolean isFixedSize() {
968 return (mRequestedWidth != -1 || mRequestedHeight != -1);
969 }
970
Robert Carrd5c7dd62017-03-08 10:39:30 -0800971 private boolean isAboveParent() {
972 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700973 }
974
Andrii Kuliancf8f6832018-01-23 19:43:30 -0800975 /**
976 * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
977 * and size of the content hasn't updated yet. This color will fill the expanded area when the
978 * view becomes larger.
979 * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
980 * @hide
981 */
982 public void setResizeBackgroundColor(int bgColor) {
Robert Carr18a82192019-01-15 13:11:46 -0800983 if (mBackgroundControl == null) {
984 return;
985 }
986
987 final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
988 Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
989
990 SurfaceControl.openTransaction();
991 try {
992 mBackgroundControl.setColor(colorComponents);
993 } finally {
994 SurfaceControl.closeTransaction();
995 }
Andrii Kuliancf8f6832018-01-23 19:43:30 -0800996 }
997
Mathew Inwooda570dee2018-08-17 14:56:00 +0100998 @UnsupportedAppUsage
Igor Murashkina86ab6402013-08-30 12:58:36 -0700999 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001000 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -07001001
1002 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001003 public boolean isCreating() {
1004 return mIsCreating;
1005 }
1006
Igor Murashkina86ab6402013-08-30 12:58:36 -07001007 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001008 public void addCallback(Callback callback) {
1009 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -07001010 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001011 // have only a couple callbacks, so it doesn't matter.
Igor Murashkina86ab6402013-08-30 12:58:36 -07001012 if (mCallbacks.contains(callback) == false) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001013 mCallbacks.add(callback);
1014 }
1015 }
1016 }
1017
Igor Murashkina86ab6402013-08-30 12:58:36 -07001018 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001019 public void removeCallback(Callback callback) {
1020 synchronized (mCallbacks) {
1021 mCallbacks.remove(callback);
1022 }
1023 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001024
1025 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001026 public void setFixedSize(int width, int height) {
1027 if (mRequestedWidth != width || mRequestedHeight != height) {
1028 mRequestedWidth = width;
1029 mRequestedHeight = height;
1030 requestLayout();
1031 }
1032 }
1033
Igor Murashkina86ab6402013-08-30 12:58:36 -07001034 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001035 public void setSizeFromLayout() {
1036 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
1037 mRequestedWidth = mRequestedHeight = -1;
1038 requestLayout();
1039 }
1040 }
1041
Igor Murashkina86ab6402013-08-30 12:58:36 -07001042 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001043 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -07001044 // for backward compatibility reason, OPAQUE always
1045 // means 565 for SurfaceView
1046 if (format == PixelFormat.OPAQUE)
1047 format = PixelFormat.RGB_565;
1048
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001049 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001050 if (mSurfaceControl != null) {
1051 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001052 }
1053 }
1054
Mathias Agopiand2112302010-12-07 19:38:17 -08001055 /**
1056 * @deprecated setType is now ignored.
1057 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001058 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -08001059 @Deprecated
1060 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001061
Igor Murashkina86ab6402013-08-30 12:58:36 -07001062 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001063 public void setKeepScreenOn(boolean screenOn) {
John Reck79925002017-05-26 13:57:14 -07001064 runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001065 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001066
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001067 /**
1068 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1069 *
1070 * After drawing into the provided {@link Canvas}, the caller must
1071 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1072 *
1073 * The caller must redraw the entire surface.
1074 * @return A canvas for drawing into the surface.
1075 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001076 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001077 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -07001078 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001079 }
1080
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001081 /**
1082 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1083 *
1084 * After drawing into the provided {@link Canvas}, the caller must
1085 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1086 *
1087 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1088 * to redraw. This function may choose to expand the dirty rectangle if for example
1089 * the surface has been resized or if the previous contents of the surface were
1090 * not available. The caller must redraw the entire dirty region as represented
1091 * by the contents of the inOutDirty rectangle upon return from this function.
1092 * The caller may also pass <code>null</code> instead, in the case where the
1093 * entire surface should be redrawn.
1094 * @return A canvas for drawing into the surface.
1095 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001096 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001097 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -07001098 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001099 }
1100
John Reck6bc70142016-10-26 16:49:17 -07001101 @Override
1102 public Canvas lockHardwareCanvas() {
1103 return internalLockCanvas(null, true);
1104 }
1105
1106 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001107 mSurfaceLock.lock();
1108
John Reckaa6e84f2016-06-16 15:36:13 -07001109 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001110 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001111
1112 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001113 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001114 try {
John Reck6bc70142016-10-26 16:49:17 -07001115 if (hardware) {
1116 c = mSurface.lockHardwareCanvas();
1117 } else {
1118 c = mSurface.lockCanvas(dirty);
1119 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001120 } catch (Exception e) {
1121 Log.e(LOG_TAG, "Exception locking surface", e);
1122 }
1123 }
1124
John Reckaa6e84f2016-06-16 15:36:13 -07001125 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001126 if (c != null) {
1127 mLastLockTime = SystemClock.uptimeMillis();
1128 return c;
1129 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001130
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001131 // If the Surface is not ready to be drawn, then return null,
1132 // but throttle calls to this function so it isn't called more
1133 // than every 100ms.
1134 long now = SystemClock.uptimeMillis();
1135 long nextTime = mLastLockTime + 100;
1136 if (nextTime > now) {
1137 try {
1138 Thread.sleep(nextTime-now);
1139 } catch (InterruptedException e) {
1140 }
1141 now = SystemClock.uptimeMillis();
1142 }
1143 mLastLockTime = now;
1144 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001145
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001146 return null;
1147 }
1148
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001149 /**
1150 * Posts the new contents of the {@link Canvas} to the surface and
1151 * releases the {@link Canvas}.
1152 *
1153 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1154 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001155 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001156 public void unlockCanvasAndPost(Canvas canvas) {
1157 mSurface.unlockCanvasAndPost(canvas);
1158 mSurfaceLock.unlock();
1159 }
1160
Igor Murashkina86ab6402013-08-30 12:58:36 -07001161 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001162 public Surface getSurface() {
1163 return mSurface;
1164 }
1165
Igor Murashkina86ab6402013-08-30 12:58:36 -07001166 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001167 public Rect getSurfaceFrame() {
1168 return mSurfaceFrame;
1169 }
1170 };
Robert Carr55235552017-06-02 14:21:03 -07001171
chaviwff2e7d82018-11-02 11:11:27 -07001172 /**
Robert Carr76907ee2019-01-11 13:38:19 -08001173 * Return a SurfaceControl which can be used for parenting Surfaces to
1174 * this SurfaceView.
1175 *
1176 * @return The SurfaceControl for this SurfaceView.
chaviwff2e7d82018-11-02 11:11:27 -07001177 */
1178 public SurfaceControl getSurfaceControl() {
1179 return mSurfaceControl;
1180 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001181}