blob: 254d04e8715deaf8ef14dce5b144803facff5e88 [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;
Mark Renouf34d04f32019-05-13 15:53:18 -040027import android.graphics.BlendMode;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070028import android.graphics.Canvas;
Andrii Kuliancf8f6832018-01-23 19:43:30 -080029import android.graphics.Color;
Mark Renouf34d04f32019-05-13 15:53:18 -040030import android.graphics.Paint;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070031import android.graphics.PixelFormat;
32import android.graphics.PorterDuff;
33import android.graphics.Rect;
34import android.graphics.Region;
John Reck32f140aa62018-10-04 15:08:24 -070035import android.graphics.RenderNode;
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070036import android.os.Build;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070037import android.os.Handler;
John Reck79925002017-05-26 13:57:14 -070038import android.os.Looper;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070039import android.os.SystemClock;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070040import android.util.AttributeSet;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070041import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070042
Robert Carr25cfa132016-11-16 13:24:09 -080043import com.android.internal.view.SurfaceCallbackHelper;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070044
Jon Larimer9bdf5762009-01-02 18:55:15 -050045import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070046import java.util.concurrent.locks.ReentrantLock;
47
48/**
49 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
50 * You can control the format of this surface and, if you like, its size; the
51 * SurfaceView takes care of placing the surface at the correct location on the
52 * screen
Igor Murashkina86ab6402013-08-30 12:58:36 -070053 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070054 * <p>The surface is Z ordered so that it is behind the window holding its
55 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070056 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070057 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070058 * 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 -070059 * buttons on top of the Surface, though note however that it can have an
60 * impact on performance since a full alpha-blended composite will be performed
61 * each time the Surface changes.
Igor Murashkina86ab6402013-08-30 12:58:36 -070062 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070063 * <p> The transparent region that makes the surface visible is based on the
64 * layout positions in the view hierarchy. If the post-layout transform
65 * properties are used to draw a sibling view on top of the SurfaceView, the
66 * view may not be properly composited with the surface.
67 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070068 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
69 * which can be retrieved by calling {@link #getHolder}.
Igor Murashkina86ab6402013-08-30 12:58:36 -070070 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070071 * <p>The Surface will be created for you while the SurfaceView's window is
72 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
73 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
74 * Surface is created and destroyed as the window is shown and hidden.
Igor Murashkina86ab6402013-08-30 12:58:36 -070075 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070076 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070077 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070078 * this way, you need to be aware of some threading semantics:
Igor Murashkina86ab6402013-08-30 12:58:36 -070079 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070080 * <ul>
81 * <li> All SurfaceView and
82 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
83 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070084 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070085 * state that is also touched by the drawing thread.
86 * <li> You must ensure that the drawing thread only touches the underlying
87 * Surface while it is valid -- between
88 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
89 * and
90 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
91 * </ul>
Chris Craik6ee192f2016-05-17 14:29:10 -070092 *
93 * <p class="note"><strong>Note:</strong> Starting in platform version
94 * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
95 * updated synchronously with other View rendering. This means that translating
96 * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
97 * artifacts may occur on previous versions of the platform when its window is
98 * positioned asynchronously.</p>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070099 */
Robert Carr414ebc62017-04-12 12:01:00 -0700100public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800101 private static final String TAG = "SurfaceView";
102 private static final boolean DEBUG = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700103
Mathew Inwooda570dee2018-08-17 14:56:00 +0100104 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700105 final ArrayList<SurfaceHolder.Callback> mCallbacks
106 = new ArrayList<SurfaceHolder.Callback>();
107
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800108 final int[] mLocation = new int[2];
Igor Murashkina86ab6402013-08-30 12:58:36 -0700109
Mathew Inwooda570dee2018-08-17 14:56:00 +0100110 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700111 final ReentrantLock mSurfaceLock = new ReentrantLock();
Mathew Inwooda570dee2018-08-17 14:56:00 +0100112 @UnsupportedAppUsage
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800113 final Surface mSurface = new Surface(); // Current surface in use
Mathew Inwood31755f92018-12-20 13:53:36 +0000114 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700115 boolean mDrawingStopped = true;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800116 // We use this to track if the application has produced a frame
117 // in to the Surface. Up until that point, we should be careful not to punch
118 // holes.
119 boolean mDrawFinished = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700120
Robert Carrd5c7dd62017-03-08 10:39:30 -0800121 final Rect mScreenRect = new Rect();
122 SurfaceSession mSurfaceSession;
123
Robert Carrb923f542019-05-13 12:27:51 -0700124 SurfaceControl mSurfaceControl;
Robert Carr3bc95b52017-03-20 21:57:23 -0700125 // In the case of format changes we switch out the surface in-place
126 // we need to preserve the old one until the new one has drawn.
Robert Carrb923f542019-05-13 12:27:51 -0700127 SurfaceControl mDeferredDestroySurfaceControl;
128 SurfaceControl mBackgroundControl;
Robert Carr33879132016-09-06 14:41:40 -0700129 final Rect mTmpRect = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700130 final Configuration mConfiguration = new Configuration();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700131
Mark Renouf34d04f32019-05-13 15:53:18 -0400132 Paint mRoundedViewportPaint;
133
Robert Carrd5c7dd62017-03-08 10:39:30 -0800134 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700135
Mathew Inwood31755f92018-12-20 13:53:36 +0000136 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700137 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700138 private volatile boolean mRtHandlingPositionUpdates = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700139
John Reckf6481082016-02-02 15:18:23 -0800140 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700141 = new ViewTreeObserver.OnScrollChangedListener() {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700142 @Override
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700143 public void onScrollChanged() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800144 updateSurface();
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700145 }
146 };
Igor Murashkina86ab6402013-08-30 12:58:36 -0700147
Mathew Inwooda570dee2018-08-17 14:56:00 +0100148 @UnsupportedAppUsage
John Reckf6481082016-02-02 15:18:23 -0800149 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
150 new ViewTreeObserver.OnPreDrawListener() {
151 @Override
152 public boolean onPreDraw() {
153 // reposition ourselves where the surface is
154 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800155 updateSurface();
John Reckf6481082016-02-02 15:18:23 -0800156 return true;
157 }
158 };
159
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700160 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700161 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800162 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700163 boolean mViewVisibility = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700164 boolean mWindowStopped = false;
165
Mathew Inwood31755f92018-12-20 13:53:36 +0000166 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700167 int mRequestedWidth = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000168 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700169 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700170 /* Set SurfaceView's format to 565 by default to maintain backward
171 * compatibility with applications assuming this format.
172 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100173 @UnsupportedAppUsage
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700174 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700175
Mathew Inwooda570dee2018-08-17 14:56:00 +0100176 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700177 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800178 boolean mSurfaceCreated = false;
Mathew Inwood31755f92018-12-20 13:53:36 +0000179 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700180 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700181
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700182 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800183 int mWindowSpaceLeft = -1;
184 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800185 int mSurfaceWidth = -1;
186 int mSurfaceHeight = -1;
Mark Renouf34d04f32019-05-13 15:53:18 -0400187 float mCornerRadius;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100188 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700189 int mFormat = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000190 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700191 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700192 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700193 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800194
Romain Guy01d5edc2011-01-28 11:28:53 -0800195 private boolean mGlobalListenersAdded;
Robert Carr8508bb22017-03-27 15:46:27 -0700196 private boolean mAttachedToWindow;
Romain Guyf2499fa2011-01-26 18:31:23 -0800197
Robert Carrd5c7dd62017-03-08 10:39:30 -0800198 private int mSurfaceFlags = SurfaceControl.HIDDEN;
199
Robert Carr8508bb22017-03-27 15:46:27 -0700200 private int mPendingReportDraws;
201
Robert Carr27a800a2018-03-16 13:33:45 -0700202 private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
203
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
237 /** @hide */
238 @Override
239 public void windowStopped(boolean stopped) {
240 mWindowStopped = stopped;
241 updateRequestedVisibility();
242 updateSurface();
243 }
244
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700245 @Override
246 protected void onAttachedToWindow() {
247 super.onAttachedToWindow();
Robert Carr414ebc62017-04-12 12:01:00 -0700248
249 getViewRootImpl().addWindowStoppedCallback(this);
Robert Carr00177cc2017-05-15 15:49:17 -0700250 mWindowStopped = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700251
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700252 mViewVisibility = getVisibility() == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700253 updateRequestedVisibility();
Romain Guy01d5edc2011-01-28 11:28:53 -0800254
Robert Carr8508bb22017-03-27 15:46:27 -0700255 mAttachedToWindow = true;
Karthik Ravi Shankara59c3a52017-09-11 17:36:25 -0700256 mParent.requestTransparentRegion(SurfaceView.this);
Romain Guy01d5edc2011-01-28 11:28:53 -0800257 if (!mGlobalListenersAdded) {
258 ViewTreeObserver observer = getViewTreeObserver();
259 observer.addOnScrollChangedListener(mScrollChangedListener);
260 observer.addOnPreDrawListener(mDrawListener);
261 mGlobalListenersAdded = true;
262 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700263 }
264
265 @Override
266 protected void onWindowVisibilityChanged(int visibility) {
267 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700268 mWindowVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700269 updateRequestedVisibility();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800270 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700271 }
272
273 @Override
274 public void setVisibility(int visibility) {
275 super.setVisibility(visibility);
276 mViewVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700277 boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700278 if (newRequestedVisible != mRequestedVisible) {
279 // our base class (View) invalidates the layout only when
280 // we go from/to the GONE state. However, SurfaceView needs
281 // to request a re-layout when the visibility changes at all.
282 // This is needed because the transparent region is computed
283 // as part of the layout phase, and it changes (obviously) when
284 // the visibility changes.
285 requestLayout();
286 }
287 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800288 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700289 }
Romain Guyafc3e112010-06-07 17:04:33 -0700290
Robert Carrb53670a2017-05-25 18:20:49 -0700291 private void performDrawFinished() {
292 if (mPendingReportDraws > 0) {
293 mDrawFinished = true;
294 if (mAttachedToWindow) {
Robert Carrb53670a2017-05-25 18:20:49 -0700295 notifyDrawFinished();
296 invalidate();
297 }
298 } else {
299 Log.e(TAG, System.identityHashCode(this) + "finished drawing"
300 + " but no pending report draw (extra call"
301 + " to draw completion runnable?)");
302 }
303 }
304
Robert Carr8508bb22017-03-27 15:46:27 -0700305 void notifyDrawFinished() {
306 ViewRootImpl viewRoot = getViewRootImpl();
307 if (viewRoot != null) {
308 viewRoot.pendingDrawFinished();
309 }
310 mPendingReportDraws--;
311 }
312
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700313 @Override
John Reck77e4a522014-10-01 10:38:07 -0700314 protected void onDetachedFromWindow() {
Lucas Dupin0c207342017-04-14 19:47:23 -0700315 ViewRootImpl viewRoot = getViewRootImpl();
316 // It's possible to create a SurfaceView using the default constructor and never
317 // attach it to a view hierarchy, this is a common use case when dealing with
318 // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
319 // the lifecycle. Instead of attaching it to a view, he/she can just pass
320 // the SurfaceHolder forward, most live wallpapers do it.
321 if (viewRoot != null) {
322 viewRoot.removeWindowStoppedCallback(this);
323 }
Robert Carr414ebc62017-04-12 12:01:00 -0700324
Robert Carr8508bb22017-03-27 15:46:27 -0700325 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800326 if (mGlobalListenersAdded) {
327 ViewTreeObserver observer = getViewTreeObserver();
328 observer.removeOnScrollChangedListener(mScrollChangedListener);
329 observer.removeOnPreDrawListener(mDrawListener);
330 mGlobalListenersAdded = false;
331 }
332
Robert Carr8508bb22017-03-27 15:46:27 -0700333 while (mPendingReportDraws > 0) {
334 notifyDrawFinished();
335 }
336
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700337 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800338
Robert Carrd5c7dd62017-03-08 10:39:30 -0800339 updateSurface();
340 if (mSurfaceControl != null) {
Robert Carr5ea304d2019-02-04 16:04:55 -0800341 mSurfaceControl.remove();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800342 }
343 mSurfaceControl = null;
344
345 mHaveFrame = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700346
John Reck77e4a522014-10-01 10:38:07 -0700347 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700348 }
349
350 @Override
351 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800352 int width = mRequestedWidth >= 0
353 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
354 : getDefaultSize(0, widthMeasureSpec);
355 int height = mRequestedHeight >= 0
356 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
357 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700358 setMeasuredDimension(width, height);
359 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700360
Mathias Agopianef115302010-10-04 20:15:08 -0700361 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700362 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100363 @UnsupportedAppUsage
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700364 protected boolean setFrame(int left, int top, int right, int bottom) {
365 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800366 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700367 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700368 }
369
370 @Override
371 public boolean gatherTransparentRegion(Region region) {
Robert Carr3ca12be72017-05-22 14:57:48 -0700372 if (isAboveParent() || !mDrawFinished) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700373 return super.gatherTransparentRegion(region);
374 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700375
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700376 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700377 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700378 // this view draws, remove it from the transparent region
379 opaque = super.gatherTransparentRegion(region);
380 } else if (region != null) {
381 int w = getWidth();
382 int h = getHeight();
383 if (w>0 && h>0) {
384 getLocationInWindow(mLocation);
385 // otherwise, punch a hole in the whole hierarchy
386 int l = mLocation[0];
387 int t = mLocation[1];
388 region.op(l, t, l+w, t+h, Region.Op.UNION);
389 }
390 }
391 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
392 opaque = false;
393 }
394 return opaque;
395 }
396
397 @Override
398 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800399 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700400 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700401 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700402 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400403 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700404 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700405 }
406 super.draw(canvas);
407 }
408
409 @Override
410 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800411 if (mDrawFinished && !isAboveParent()) {
412 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700413 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700414 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400415 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700416 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700417 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700418 super.dispatchDraw(canvas);
419 }
420
Mark Renouf34d04f32019-05-13 15:53:18 -0400421 private void clearSurfaceViewPort(Canvas canvas) {
422 if (mCornerRadius > 0f) {
423 canvas.getClipBounds(mTmpRect);
424 canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
425 mCornerRadius, mCornerRadius, mRoundedViewportPaint);
426 } else {
427 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
428 }
429 }
430
431 /**
432 * Sets the corner radius for the SurfaceView. This will round both the corners of the
433 * underlying surface, as well as the corners of the hole created to expose the surface.
434 *
435 * @param cornerRadius the new radius of the corners in pixels
436 * @hide
437 */
438 public void setCornerRadius(float cornerRadius) {
439 mCornerRadius = cornerRadius;
440 if (mCornerRadius > 0f && mRoundedViewportPaint == null) {
441 mRoundedViewportPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
442 mRoundedViewportPaint.setBlendMode(BlendMode.CLEAR);
443 mRoundedViewportPaint.setColor(0);
444 }
445 invalidate();
446 }
447
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700448 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700449 * Control whether the surface view's surface is placed on top of another
450 * regular surface view in the window (but still behind the window itself).
451 * This is typically used to place overlays on top of an underlying media
452 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700453 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700454 * <p>Note that this must be set before the surface view's containing
455 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700456 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700457 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
458 */
459 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800460 mSubLayer = isMediaOverlay
461 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700462 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700463
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700464 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700465 * Control whether the surface view's surface is placed on top of its
466 * window. Normally it is placed behind the window, to allow it to
467 * (for the most part) appear to composite with the views in the
468 * hierarchy. By setting this, you cause it to be placed above the
469 * window. This means that none of the contents of the window this
470 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700471 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700472 * <p>Note that this must be set before the surface view's containing
473 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700474 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700475 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700476 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700477 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500478 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800479 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500480 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800481 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500482 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700483 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700484
485 /**
486 * Control whether the surface view's content should be treated as secure,
487 * preventing it from appearing in screenshots or from being viewed on
488 * non-secure displays.
489 *
490 * <p>Note that this must be set before the surface view's containing
491 * window is attached to the window manager.
492 *
493 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
494 *
495 * @param isSecure True if the surface view is secure.
496 */
497 public void setSecure(boolean isSecure) {
498 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800499 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700500 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800501 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700502 }
503 }
504
Robert Carr55235552017-06-02 14:21:03 -0700505 private void updateOpaqueFlag() {
Robert Carr851e7e42017-06-06 14:04:50 -0700506 if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
Robert Carr55235552017-06-02 14:21:03 -0700507 mSurfaceFlags |= SurfaceControl.OPAQUE;
508 } else {
509 mSurfaceFlags &= ~SurfaceControl.OPAQUE;
510 }
511 }
512
Robert Carrd5c7dd62017-03-08 10:39:30 -0800513 private Rect getParentSurfaceInsets() {
514 final ViewRootImpl root = getViewRootImpl();
515 if (root == null) {
516 return null;
517 } else {
518 return root.mWindowAttributes.surfaceInsets;
519 }
Jeff Tinker3896db12017-03-03 00:20:22 +0000520 }
521
Robert Carrb923f542019-05-13 12:27:51 -0700522 private void updateBackgroundVisibilityInTransaction(SurfaceControl viewRoot) {
523 if (mBackgroundControl == null) {
524 return;
525 }
526 if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
527 mBackgroundControl.show();
528 mBackgroundControl.setRelativeLayer(viewRoot, Integer.MIN_VALUE);
529 } else {
530 mBackgroundControl.hide();
531 }
532 }
533
534 private void releaseSurfaces() {
535 if (mSurfaceControl != null) {
536 mSurfaceControl.remove();
537 mSurfaceControl = null;
538 }
539 if (mBackgroundControl != null) {
540 mBackgroundControl.remove();
541 mBackgroundControl = null;
542 }
543 }
544
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900545 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800546 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700547 if (!mHaveFrame) {
548 return;
549 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800550 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800551 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
552 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700553 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700554
Robert Carrd5c7dd62017-03-08 10:39:30 -0800555 mTranslator = viewRoot.mTranslator;
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700556 if (mTranslator != null) {
557 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700558 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700559
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700560 int myWidth = mRequestedWidth;
561 if (myWidth <= 0) myWidth = getWidth();
562 int myHeight = mRequestedHeight;
563 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700564
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700565 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700566 final boolean visibleChanged = mVisible != mRequestedVisible;
567 final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
Robert Carrd5c7dd62017-03-08 10:39:30 -0800568 && mRequestedVisible;
569 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800570 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700571 boolean redrawNeeded = false;
572
Robert Carrd5c7dd62017-03-08 10:39:30 -0800573 if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800574 getLocationInWindow(mLocation);
575
John Reckaa6e84f2016-06-16 15:36:13 -0700576 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
577 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700578 + " format=" + formatChanged + " size=" + sizeChanged
579 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800580 + " left=" + (mWindowSpaceLeft != mLocation[0])
581 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700582
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700583 try {
584 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800585 mWindowSpaceLeft = mLocation[0];
586 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800587 mSurfaceWidth = myWidth;
588 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700589 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800590 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700591
Robert Carrd5c7dd62017-03-08 10:39:30 -0800592 mScreenRect.left = mWindowSpaceLeft;
593 mScreenRect.top = mWindowSpaceTop;
594 mScreenRect.right = mWindowSpaceLeft + getWidth();
595 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700596 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800597 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700598 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700599
Robert Carrd5c7dd62017-03-08 10:39:30 -0800600 final Rect surfaceInsets = getParentSurfaceInsets();
601 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
602
603 if (creating) {
Vishnu Nairb040c012018-09-07 11:38:32 -0700604 viewRoot.createBoundsSurface(mSubLayer);
Robert Carr5fea55b2018-12-10 13:05:52 -0800605 mSurfaceSession = new SurfaceSession();
Robert Carr3bc95b52017-03-20 21:57:23 -0700606 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carr55235552017-06-02 14:21:03 -0700607
608 updateOpaqueFlag();
Robert Carre625fcf2017-09-01 12:36:28 -0700609 final String name = "SurfaceView - " + viewRoot.getTitle().toString();
610
Robert Carrb923f542019-05-13 12:27:51 -0700611 mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
612 .setName(name)
613 .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
614 .setBufferSize(mSurfaceWidth, mSurfaceHeight)
615 .setFormat(mFormat)
616 .setParent(viewRoot.getSurfaceControl())
617 .setFlags(mSurfaceFlags)
618 .build();
619 mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
620 .setName("Background for -" + name)
621 .setOpaque(true)
622 .setColorLayer()
623 .setParent(mSurfaceControl)
624 .build();
625
Robert Carr44ab5752017-03-20 21:47:11 -0700626 } else if (mSurfaceControl == null) {
627 return;
Robert Carr64aadd02015-11-06 13:54:20 -0800628 }
629
Robert Carrd5c7dd62017-03-08 10:39:30 -0800630 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800631
Dianne Hackborn726426e2010-03-31 22:04:36 -0700632 mSurfaceLock.lock();
633 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700634 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700635
John Reckaa6e84f2016-06-16 15:36:13 -0700636 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
637 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800638
Robert Carrd5c7dd62017-03-08 10:39:30 -0800639 SurfaceControl.openTransaction();
640 try {
641 mSurfaceControl.setLayer(mSubLayer);
Robert Carrb923f542019-05-13 12:27:51 -0700642
Robert Carrd5c7dd62017-03-08 10:39:30 -0800643 if (mViewVisibility) {
644 mSurfaceControl.show();
645 } else {
646 mSurfaceControl.hide();
647 }
Robert Carrb923f542019-05-13 12:27:51 -0700648 updateBackgroundVisibilityInTransaction(viewRoot.getSurfaceControl());
Robert Carrd5c7dd62017-03-08 10:39:30 -0800649
650 // While creating the surface, we will set it's initial
651 // geometry. Outside of that though, we should generally
652 // leave it to the RenderThread.
Robert Carr511719f2017-03-13 15:27:15 -0700653 //
654 // There is one more case when the buffer size changes we aren't yet
655 // prepared to sync (as even following the transaction applying
656 // we still need to latch a buffer).
657 // b/28866173
658 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800659 mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
660 mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
661 0.0f, 0.0f,
662 mScreenRect.height() / (float) mSurfaceHeight);
Vishnu Naire86bd982018-11-28 13:23:17 -0800663 // Set a window crop when creating the surface or changing its size to
664 // crop the buffer to the surface size since the buffer producer may
665 // use SCALING_MODE_SCALE and submit a larger size than the surface
666 // size.
667 mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800668 }
Mark Renouf34d04f32019-05-13 15:53:18 -0400669 mSurfaceControl.setCornerRadius(mCornerRadius);
youngmin0822.lee4dde7d12018-07-09 14:25:32 +0900670 if (sizeChanged && !creating) {
Vishnu Naire86bd982018-11-28 13:23:17 -0800671 mSurfaceControl.setBufferSize(mSurfaceWidth, mSurfaceHeight);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800672 }
673 } finally {
674 SurfaceControl.closeTransaction();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700675 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800676
Robert Carrd5c7dd62017-03-08 10:39:30 -0800677 if (sizeChanged || creating) {
678 redrawNeeded = true;
679 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800680
Dianne Hackborn726426e2010-03-31 22:04:36 -0700681 mSurfaceFrame.left = 0;
682 mSurfaceFrame.top = 0;
683 if (mTranslator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800684 mSurfaceFrame.right = mSurfaceWidth;
685 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700686 } else {
687 float appInvertedScale = mTranslator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800688 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
689 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700690 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700691
Dianne Hackborn726426e2010-03-31 22:04:36 -0700692 final int surfaceWidth = mSurfaceFrame.right;
693 final int surfaceHeight = mSurfaceFrame.bottom;
694 realSizeChanged = mLastSurfaceWidth != surfaceWidth
695 || mLastSurfaceHeight != surfaceHeight;
696 mLastSurfaceWidth = surfaceWidth;
697 mLastSurfaceHeight = surfaceHeight;
698 } finally {
699 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700700 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700701
702 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800703 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700704
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800705 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700706
Robert Carrd5c7dd62017-03-08 10:39:30 -0800707 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800708 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
709 mSurfaceCreated = false;
710 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700711 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
712 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800713 callbacks = getSurfaceCallbacks();
714 for (SurfaceHolder.Callback c : callbacks) {
715 c.surfaceDestroyed(mSurfaceHolder);
716 }
Robert Carr387838b2016-09-07 14:12:44 -0700717 // Since Android N the same surface may be reused and given to us
718 // again by the system server at a later point. However
719 // as we didn't do this in previous releases, clients weren't
720 // necessarily required to clean up properly in
721 // surfaceDestroyed. This leads to problems for example when
722 // clients don't destroy their EGL context, and try
723 // and create a new one on the same surface following reuse.
724 // Since there is no valid use of the surface in-between
725 // surfaceDestroyed and surfaceCreated, we force a disconnect,
726 // so the next connect will always work if we end up reusing
727 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700728 if (mSurface.isValid()) {
729 mSurface.forceScopedDisconnect();
730 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700731 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800732 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700733
Robert Carrd5c7dd62017-03-08 10:39:30 -0800734 if (creating) {
Robert Carrb923f542019-05-13 12:27:51 -0700735 mSurface.copyFrom(mSurfaceControl);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800736 }
737
Bryce Lee453fc362017-06-20 10:47:55 -0700738 if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
Bryce Lee02949f12017-06-16 07:20:34 -0700739 < Build.VERSION_CODES.O) {
740 // Some legacy applications use the underlying native {@link Surface} object
741 // as a key to whether anything has changed. In these cases, updates to the
742 // existing {@link Surface} will be ignored when the size changes.
743 // Therefore, we must explicitly recreate the {@link Surface} in these
744 // cases.
Robert Carrb923f542019-05-13 12:27:51 -0700745 mSurface.createFrom(mSurfaceControl);
Bryce Lee02949f12017-06-16 07:20:34 -0700746 }
747
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200748 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800749 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
750 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700751 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700752 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
753 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800754 if (callbacks == null) {
755 callbacks = getSurfaceCallbacks();
756 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700757 for (SurfaceHolder.Callback c : callbacks) {
758 c.surfaceCreated(mSurfaceHolder);
759 }
760 }
761 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700762 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700763 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
764 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800765 + " w=" + myWidth + " h=" + myHeight);
766 if (callbacks == null) {
767 callbacks = getSurfaceCallbacks();
768 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700769 for (SurfaceHolder.Callback c : callbacks) {
770 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
771 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700772 }
773 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -0700774 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
775 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800776 if (callbacks == null) {
777 callbacks = getSurfaceCallbacks();
778 }
Robert Carr8508bb22017-03-27 15:46:27 -0700779
780 mPendingReportDraws++;
781 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -0800782 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -0800783 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -0800784 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700785 }
786 }
787 } finally {
788 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800789 if (mSurfaceControl != null && !mSurfaceCreated) {
Robert Carrde844432017-05-04 13:45:45 -0700790 mSurface.release();
Robert Carr29daa922018-04-27 11:56:48 -0700791
Robert Carrb923f542019-05-13 12:27:51 -0700792 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800793 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700794 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800795 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700796 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700797 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800798 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -0800799 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
800 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
801 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -0700802 } else {
803 // Calculate the window position in case RT loses the window
804 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -0800805 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -0800806 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
807 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800808 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
809 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -0800810 if (positionChanged || layoutSizeChanged) { // Only the position has changed
811 mWindowSpaceLeft = mLocation[0];
812 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800813 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -0800814 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800815 mLocation[0] = getWidth();
816 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -0800817
Robert Carrd5c7dd62017-03-08 10:39:30 -0800818 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
Robert Carrc90e5f82017-07-18 13:10:02 -0700819 mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
John Reckf057fb52016-04-15 13:46:29 -0700820
821 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800822 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -0700823 }
824
Robert Carr3651ab82017-04-25 12:05:34 -0700825 if (mSurfaceControl == null) {
826 return;
827 }
828
Bryce Lee16e50892017-04-11 01:59:37 +0000829 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
John Reckf23a1b82016-06-22 14:23:31 -0700830 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800831 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
John Reckf23a1b82016-06-22 14:23:31 -0700832 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800833 mScreenRect.left, mScreenRect.top,
834 mScreenRect.right, mScreenRect.bottom));
835 setParentSpaceRectangle(mScreenRect, -1);
836 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700837 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -0700838 }
John Reckf6481082016-02-02 15:18:23 -0800839 }
Rob Carr64e516f2015-10-29 00:20:45 +0000840 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700841 }
842 }
843
Robert Carrd5c7dd62017-03-08 10:39:30 -0800844 private void onDrawFinished() {
845 if (DEBUG) {
846 Log.i(TAG, System.identityHashCode(this) + " "
847 + "finishedDrawing");
848 }
Robert Carr3bc95b52017-03-20 21:57:23 -0700849
850 if (mDeferredDestroySurfaceControl != null) {
Robert Carr5ea304d2019-02-04 16:04:55 -0800851 mDeferredDestroySurfaceControl.remove();
Robert Carr3bc95b52017-03-20 21:57:23 -0700852 mDeferredDestroySurfaceControl = null;
853 }
854
John Reck79925002017-05-26 13:57:14 -0700855 runOnUiThread(() -> {
Robert Carrb53670a2017-05-25 18:20:49 -0700856 performDrawFinished();
John Reck79925002017-05-26 13:57:14 -0700857 });
Robert Carrd5c7dd62017-03-08 10:39:30 -0800858 }
859
Robert Carr27a800a2018-03-16 13:33:45 -0700860 /**
861 * A place to over-ride for applying child-surface transactions.
862 * These can be synchronized with the viewroot surface using deferTransaction.
863 *
864 * Called from RenderWorker while UI thread is paused.
865 * @hide
866 */
867 protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
868 Surface viewRootSurface, long nextViewRootFrameNumber) {
869 }
870
Robert Carr386fd702018-03-23 13:46:39 -0700871 private void applySurfaceTransforms(SurfaceControl surface, Rect position, long frameNumber) {
Robert Carr27a800a2018-03-16 13:33:45 -0700872 if (frameNumber > 0) {
Robert Carr386fd702018-03-23 13:46:39 -0700873 final ViewRootImpl viewRoot = getViewRootImpl();
874
875 mRtTransaction.deferTransactionUntilSurface(surface, viewRoot.mSurface,
Robert Carr27a800a2018-03-16 13:33:45 -0700876 frameNumber);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800877 }
Robert Carr386fd702018-03-23 13:46:39 -0700878
879 mRtTransaction.setPosition(surface, position.left, position.top);
880 mRtTransaction.setMatrix(surface,
Robert Carr27a800a2018-03-16 13:33:45 -0700881 position.width() / (float) mSurfaceWidth,
882 0.0f, 0.0f,
883 position.height() / (float) mSurfaceHeight);
John Reckd0abd662019-05-01 12:52:04 -0700884 if (mViewVisibility) {
885 mRtTransaction.show(surface);
886 }
887
Robert Carr386fd702018-03-23 13:46:39 -0700888 }
889
890 private void setParentSpaceRectangle(Rect position, long frameNumber) {
891 final ViewRootImpl viewRoot = getViewRootImpl();
892
Robert Carrb923f542019-05-13 12:27:51 -0700893 applySurfaceTransforms(mSurfaceControl, position, frameNumber);
Robert Carr27a800a2018-03-16 13:33:45 -0700894
895 applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface,
896 frameNumber);
897
898 mRtTransaction.apply();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800899 }
900
John Reckf6481082016-02-02 15:18:23 -0800901 private Rect mRTLastReportedPosition = new Rect();
902
John Reck6b164402018-09-24 15:25:42 -0700903 private RenderNode.PositionUpdateListener mPositionListener =
904 new RenderNode.PositionUpdateListener() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800905
John Reck6b164402018-09-24 15:25:42 -0700906 @Override
907 public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
908 if (mSurfaceControl == null) {
909 return;
John Reckf6481082016-02-02 15:18:23 -0800910 }
John Reckf6481082016-02-02 15:18:23 -0800911
John Reck6b164402018-09-24 15:25:42 -0700912 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
913 // its 2nd frame if RenderThread is running slowly could potentially see
914 // this as false, enter the branch, get pre-empted, then this comes along
915 // and reports a new position, then the UI thread resumes and reports
916 // its position. This could therefore be de-sync'd in that interval, but
917 // the synchronization would violate the rule that RT must never block
918 // on the UI thread which would open up potential deadlocks. The risk of
919 // a single-frame desync is therefore preferable for now.
920 mRtHandlingPositionUpdates = true;
921 if (mRTLastReportedPosition.left == left
922 && mRTLastReportedPosition.top == top
923 && mRTLastReportedPosition.right == right
924 && mRTLastReportedPosition.bottom == bottom) {
925 return;
926 }
927 try {
928 if (DEBUG) {
929 Log.d(TAG, String.format(
930 "%d updateSurfacePosition RenderWorker, frameNr = %d, "
931 + "postion = [%d, %d, %d, %d]",
932 System.identityHashCode(this), frameNumber,
933 left, top, right, bottom));
934 }
935 mRTLastReportedPosition.set(left, top, right, bottom);
936 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
937 // Now overwrite mRTLastReportedPosition with our values
938 } catch (Exception ex) {
939 Log.e(TAG, "Exception from repositionChild", ex);
940 }
John Reckaa6e84f2016-06-16 15:36:13 -0700941 }
Robert Carrad3a4932017-06-20 14:55:21 -0700942
John Reck6b164402018-09-24 15:25:42 -0700943 @Override
944 public void positionLost(long frameNumber) {
945 if (DEBUG) {
946 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
947 System.identityHashCode(this), frameNumber));
948 }
949 mRTLastReportedPosition.setEmpty();
950
951 if (mSurfaceControl == null) {
952 return;
953 }
John Reckd0abd662019-05-01 12:52:04 -0700954
955 if (frameNumber > 0) {
956 final ViewRootImpl viewRoot = getViewRootImpl();
957
Robert Carrb923f542019-05-13 12:27:51 -0700958 mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface,
John Reckd0abd662019-05-01 12:52:04 -0700959 frameNumber);
John Reckf23a1b82016-06-22 14:23:31 -0700960 }
Robert Carrb923f542019-05-13 12:27:51 -0700961 mRtTransaction.hide(mSurfaceControl);
John Reckd0abd662019-05-01 12:52:04 -0700962 mRtTransaction.apply();
John Reckf23a1b82016-06-22 14:23:31 -0700963 }
John Reck6b164402018-09-24 15:25:42 -0700964 };
John Reckaa6e84f2016-06-16 15:36:13 -0700965
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800966 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
967 SurfaceHolder.Callback callbacks[];
968 synchronized (mCallbacks) {
969 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
970 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700971 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800972 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700973 }
974
John Reck79925002017-05-26 13:57:14 -0700975 private void runOnUiThread(Runnable runnable) {
976 Handler handler = getHandler();
977 if (handler != null && handler.getLooper() != Looper.myLooper()) {
978 handler.post(runnable);
979 } else {
980 runnable.run();
981 }
982 }
983
Yohei Yukawa3b5011a2017-03-16 15:34:12 -0700984 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -0400985 * Check to see if the surface has fixed size dimensions or if the surface's
986 * dimensions are dimensions are dependent on its current layout.
987 *
988 * @return true if the surface has dimensions that are fixed in size
989 * @hide
990 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100991 @UnsupportedAppUsage
Derek Sollenberger7179b812010-03-22 13:41:20 -0400992 public boolean isFixedSize() {
993 return (mRequestedWidth != -1 || mRequestedHeight != -1);
994 }
995
Robert Carrd5c7dd62017-03-08 10:39:30 -0800996 private boolean isAboveParent() {
997 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700998 }
999
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001000 /**
1001 * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
1002 * and size of the content hasn't updated yet. This color will fill the expanded area when the
1003 * view becomes larger.
1004 * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
1005 * @hide
1006 */
1007 public void setResizeBackgroundColor(int bgColor) {
Robert Carrb923f542019-05-13 12:27:51 -07001008 if (mBackgroundControl == null) {
1009 return;
1010 }
1011
1012 final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
1013 Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
1014
1015 SurfaceControl.openTransaction();
1016 try {
1017 mBackgroundControl.setColor(colorComponents);
1018 } finally {
1019 SurfaceControl.closeTransaction();
1020 }
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001021 }
1022
Mathew Inwooda570dee2018-08-17 14:56:00 +01001023 @UnsupportedAppUsage
Igor Murashkina86ab6402013-08-30 12:58:36 -07001024 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001025 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -07001026
1027 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001028 public boolean isCreating() {
1029 return mIsCreating;
1030 }
1031
Igor Murashkina86ab6402013-08-30 12:58:36 -07001032 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001033 public void addCallback(Callback callback) {
1034 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -07001035 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001036 // have only a couple callbacks, so it doesn't matter.
Igor Murashkina86ab6402013-08-30 12:58:36 -07001037 if (mCallbacks.contains(callback) == false) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001038 mCallbacks.add(callback);
1039 }
1040 }
1041 }
1042
Igor Murashkina86ab6402013-08-30 12:58:36 -07001043 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001044 public void removeCallback(Callback callback) {
1045 synchronized (mCallbacks) {
1046 mCallbacks.remove(callback);
1047 }
1048 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001049
1050 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001051 public void setFixedSize(int width, int height) {
1052 if (mRequestedWidth != width || mRequestedHeight != height) {
1053 mRequestedWidth = width;
1054 mRequestedHeight = height;
1055 requestLayout();
1056 }
1057 }
1058
Igor Murashkina86ab6402013-08-30 12:58:36 -07001059 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001060 public void setSizeFromLayout() {
1061 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
1062 mRequestedWidth = mRequestedHeight = -1;
1063 requestLayout();
1064 }
1065 }
1066
Igor Murashkina86ab6402013-08-30 12:58:36 -07001067 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001068 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -07001069 // for backward compatibility reason, OPAQUE always
1070 // means 565 for SurfaceView
1071 if (format == PixelFormat.OPAQUE)
1072 format = PixelFormat.RGB_565;
1073
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001074 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001075 if (mSurfaceControl != null) {
1076 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001077 }
1078 }
1079
Mathias Agopiand2112302010-12-07 19:38:17 -08001080 /**
1081 * @deprecated setType is now ignored.
1082 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001083 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -08001084 @Deprecated
1085 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001086
Igor Murashkina86ab6402013-08-30 12:58:36 -07001087 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001088 public void setKeepScreenOn(boolean screenOn) {
John Reck79925002017-05-26 13:57:14 -07001089 runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001090 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001091
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001092 /**
1093 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1094 *
1095 * After drawing into the provided {@link Canvas}, the caller must
1096 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1097 *
1098 * The caller must redraw the entire surface.
1099 * @return A canvas for drawing into the surface.
1100 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001101 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001102 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -07001103 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001104 }
1105
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001106 /**
1107 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1108 *
1109 * After drawing into the provided {@link Canvas}, the caller must
1110 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1111 *
1112 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1113 * to redraw. This function may choose to expand the dirty rectangle if for example
1114 * the surface has been resized or if the previous contents of the surface were
1115 * not available. The caller must redraw the entire dirty region as represented
1116 * by the contents of the inOutDirty rectangle upon return from this function.
1117 * The caller may also pass <code>null</code> instead, in the case where the
1118 * entire surface should be redrawn.
1119 * @return A canvas for drawing into the surface.
1120 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001121 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001122 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -07001123 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001124 }
1125
John Reck6bc70142016-10-26 16:49:17 -07001126 @Override
1127 public Canvas lockHardwareCanvas() {
1128 return internalLockCanvas(null, true);
1129 }
1130
1131 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001132 mSurfaceLock.lock();
1133
John Reckaa6e84f2016-06-16 15:36:13 -07001134 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001135 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001136
1137 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001138 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001139 try {
John Reck6bc70142016-10-26 16:49:17 -07001140 if (hardware) {
1141 c = mSurface.lockHardwareCanvas();
1142 } else {
1143 c = mSurface.lockCanvas(dirty);
1144 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001145 } catch (Exception e) {
1146 Log.e(LOG_TAG, "Exception locking surface", e);
1147 }
1148 }
1149
John Reckaa6e84f2016-06-16 15:36:13 -07001150 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001151 if (c != null) {
1152 mLastLockTime = SystemClock.uptimeMillis();
1153 return c;
1154 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001155
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001156 // If the Surface is not ready to be drawn, then return null,
1157 // but throttle calls to this function so it isn't called more
1158 // than every 100ms.
1159 long now = SystemClock.uptimeMillis();
1160 long nextTime = mLastLockTime + 100;
1161 if (nextTime > now) {
1162 try {
1163 Thread.sleep(nextTime-now);
1164 } catch (InterruptedException e) {
1165 }
1166 now = SystemClock.uptimeMillis();
1167 }
1168 mLastLockTime = now;
1169 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001170
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001171 return null;
1172 }
1173
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001174 /**
1175 * Posts the new contents of the {@link Canvas} to the surface and
1176 * releases the {@link Canvas}.
1177 *
1178 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1179 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001180 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001181 public void unlockCanvasAndPost(Canvas canvas) {
1182 mSurface.unlockCanvasAndPost(canvas);
1183 mSurfaceLock.unlock();
1184 }
1185
Igor Murashkina86ab6402013-08-30 12:58:36 -07001186 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001187 public Surface getSurface() {
1188 return mSurface;
1189 }
1190
Igor Murashkina86ab6402013-08-30 12:58:36 -07001191 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001192 public Rect getSurfaceFrame() {
1193 return mSurfaceFrame;
1194 }
1195 };
Robert Carr55235552017-06-02 14:21:03 -07001196
chaviwff2e7d82018-11-02 11:11:27 -07001197 /**
Robert Carr76907ee2019-01-11 13:38:19 -08001198 * Return a SurfaceControl which can be used for parenting Surfaces to
1199 * this SurfaceView.
1200 *
1201 * @return The SurfaceControl for this SurfaceView.
chaviwff2e7d82018-11-02 11:11:27 -07001202 */
1203 public SurfaceControl getSurfaceControl() {
Robert Carrb923f542019-05-13 12:27:51 -07001204 return mSurfaceControl;
chaviwff2e7d82018-11-02 11:11:27 -07001205 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001206}