blob: d11548d687b1532fad8702f74de90257d2bb2a20 [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;
Mark Renouf34d04f32019-05-13 15:53:18 -040026import android.graphics.BlendMode;
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;
Mark Renouf34d04f32019-05-13 15:53:18 -040029import android.graphics.Paint;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070030import android.graphics.PixelFormat;
31import android.graphics.PorterDuff;
32import android.graphics.Rect;
33import android.graphics.Region;
John Reck32f140aa62018-10-04 15:08:24 -070034import android.graphics.RenderNode;
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070035import android.os.Build;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070036import android.os.Handler;
John Reck79925002017-05-26 13:57:14 -070037import android.os.Looper;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070038import android.os.SystemClock;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070039import android.util.AttributeSet;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070040import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070041
Robert Carr25cfa132016-11-16 13:24:09 -080042import com.android.internal.view.SurfaceCallbackHelper;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070043
Jon Larimer9bdf5762009-01-02 18:55:15 -050044import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070045import java.util.concurrent.locks.ReentrantLock;
46
47/**
48 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
49 * You can control the format of this surface and, if you like, its size; the
50 * SurfaceView takes care of placing the surface at the correct location on the
51 * screen
Igor Murashkina86ab6402013-08-30 12:58:36 -070052 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070053 * <p>The surface is Z ordered so that it is behind the window holding its
54 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070055 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070056 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070057 * 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 -070058 * buttons on top of the Surface, though note however that it can have an
59 * impact on performance since a full alpha-blended composite will be performed
60 * each time the Surface changes.
Igor Murashkina86ab6402013-08-30 12:58:36 -070061 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070062 * <p> The transparent region that makes the surface visible is based on the
63 * layout positions in the view hierarchy. If the post-layout transform
64 * properties are used to draw a sibling view on top of the SurfaceView, the
65 * view may not be properly composited with the surface.
66 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070067 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
68 * which can be retrieved by calling {@link #getHolder}.
Igor Murashkina86ab6402013-08-30 12:58:36 -070069 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070070 * <p>The Surface will be created for you while the SurfaceView's window is
71 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
72 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
73 * Surface is created and destroyed as the window is shown and hidden.
Igor Murashkina86ab6402013-08-30 12:58:36 -070074 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070075 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070076 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070077 * this way, you need to be aware of some threading semantics:
Igor Murashkina86ab6402013-08-30 12:58:36 -070078 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070079 * <ul>
80 * <li> All SurfaceView and
81 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
82 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070083 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070084 * state that is also touched by the drawing thread.
85 * <li> You must ensure that the drawing thread only touches the underlying
86 * Surface while it is valid -- between
87 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
88 * and
89 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
90 * </ul>
Chris Craik6ee192f2016-05-17 14:29:10 -070091 *
92 * <p class="note"><strong>Note:</strong> Starting in platform version
93 * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
94 * updated synchronously with other View rendering. This means that translating
95 * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
96 * artifacts may occur on previous versions of the platform when its window is
97 * positioned asynchronously.</p>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070098 */
Robert Carr414ebc62017-04-12 12:01:00 -070099public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800100 private static final String TAG = "SurfaceView";
101 private static final boolean DEBUG = false;
Issei Suzuki927fe872019-06-17 15:56:57 +0200102 private static final boolean DEBUG_POSITION = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700103
Mathew Inwooda570dee2018-08-17 14:56:00 +0100104 @UnsupportedAppUsage
Issei Suzuki33727a02019-07-02 12:31:34 +0200105 final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<>();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700106
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800107 final int[] mLocation = new int[2];
Igor Murashkina86ab6402013-08-30 12:58:36 -0700108
Mathew Inwooda570dee2018-08-17 14:56:00 +0100109 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700110 final ReentrantLock mSurfaceLock = new ReentrantLock();
Mathew Inwooda570dee2018-08-17 14:56:00 +0100111 @UnsupportedAppUsage
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800112 final Surface mSurface = new Surface(); // Current surface in use
Mathew Inwood31755f92018-12-20 13:53:36 +0000113 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700114 boolean mDrawingStopped = true;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800115 // We use this to track if the application has produced a frame
116 // in to the Surface. Up until that point, we should be careful not to punch
117 // holes.
118 boolean mDrawFinished = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700119
Robert Carrd5c7dd62017-03-08 10:39:30 -0800120 final Rect mScreenRect = new Rect();
121 SurfaceSession mSurfaceSession;
122
Robert Carrb923f542019-05-13 12:27:51 -0700123 SurfaceControl mSurfaceControl;
Robert Carr3bc95b52017-03-20 21:57:23 -0700124 // In the case of format changes we switch out the surface in-place
125 // we need to preserve the old one until the new one has drawn.
Robert Carrb923f542019-05-13 12:27:51 -0700126 SurfaceControl mDeferredDestroySurfaceControl;
127 SurfaceControl mBackgroundControl;
Issei Suzuki927fe872019-06-17 15:56:57 +0200128 final Object mSurfaceControlLock = new Object();
Robert Carr33879132016-09-06 14:41:40 -0700129 final Rect mTmpRect = new Rect();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700130
Mark Renouf34d04f32019-05-13 15:53:18 -0400131 Paint mRoundedViewportPaint;
132
Robert Carrd5c7dd62017-03-08 10:39:30 -0800133 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700134
Mathew Inwood31755f92018-12-20 13:53:36 +0000135 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700136 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700137 private volatile boolean mRtHandlingPositionUpdates = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700138
Issei Suzuki33727a02019-07-02 12:31:34 +0200139 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener =
140 this::updateSurface;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700141
Mathew Inwooda570dee2018-08-17 14:56:00 +0100142 @UnsupportedAppUsage
Issei Suzuki33727a02019-07-02 12:31:34 +0200143 private final ViewTreeObserver.OnPreDrawListener mDrawListener = () -> {
144 // reposition ourselves where the surface is
145 mHaveFrame = getWidth() > 0 && getHeight() > 0;
146 updateSurface();
147 return true;
148 };
John Reckf6481082016-02-02 15:18:23 -0800149
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700150 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700151 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800152 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700153 boolean mViewVisibility = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700154 boolean mWindowStopped = false;
155
Mathew Inwood31755f92018-12-20 13:53:36 +0000156 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700157 int mRequestedWidth = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000158 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700159 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700160 /* Set SurfaceView's format to 565 by default to maintain backward
161 * compatibility with applications assuming this format.
162 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100163 @UnsupportedAppUsage
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700164 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700165
Issei Suzuki927fe872019-06-17 15:56:57 +0200166 boolean mUseAlpha = false;
167 float mSurfaceAlpha = 1f;
168
Mathew Inwooda570dee2018-08-17 14:56:00 +0100169 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700170 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800171 boolean mSurfaceCreated = false;
Mathew Inwood31755f92018-12-20 13:53:36 +0000172 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700173 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700174
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700175 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800176 int mWindowSpaceLeft = -1;
177 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800178 int mSurfaceWidth = -1;
179 int mSurfaceHeight = -1;
Mark Renouf34d04f32019-05-13 15:53:18 -0400180 float mCornerRadius;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100181 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700182 int mFormat = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000183 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700184 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700185 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Romain Guyf2499fa2011-01-26 18:31:23 -0800186
Romain Guy01d5edc2011-01-28 11:28:53 -0800187 private boolean mGlobalListenersAdded;
Robert Carr8508bb22017-03-27 15:46:27 -0700188 private boolean mAttachedToWindow;
Romain Guyf2499fa2011-01-26 18:31:23 -0800189
Robert Carrd5c7dd62017-03-08 10:39:30 -0800190 private int mSurfaceFlags = SurfaceControl.HIDDEN;
191
Robert Carr8508bb22017-03-27 15:46:27 -0700192 private int mPendingReportDraws;
193
Robert Carr27a800a2018-03-16 13:33:45 -0700194 private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
chaviwdd5bde02019-06-07 16:33:50 -0700195 private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
Robert Carr27a800a2018-03-16 13:33:45 -0700196
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700197 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400198 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700199 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700200
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700201 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400202 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700203 }
204
Alan Viverette617feb92013-09-09 18:09:13 -0700205 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400206 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700207 }
208
209 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
210 super(context, attrs, defStyleAttr, defStyleRes);
Adam Powell769b8632019-02-04 11:28:22 -0800211 mRenderNode.addPositionUpdateListener(mPositionListener);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700212
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700213 setWillNotDraw(true);
214 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700215
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700216 /**
217 * Return the SurfaceHolder providing access and control over this
218 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700219 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700220 * @return SurfaceHolder The holder of the surface.
221 */
222 public SurfaceHolder getHolder() {
223 return mSurfaceHolder;
224 }
225
Robert Carr414ebc62017-04-12 12:01:00 -0700226 private void updateRequestedVisibility() {
227 mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
228 }
229
230 /** @hide */
231 @Override
232 public void windowStopped(boolean stopped) {
233 mWindowStopped = stopped;
234 updateRequestedVisibility();
235 updateSurface();
236 }
237
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700238 @Override
239 protected void onAttachedToWindow() {
240 super.onAttachedToWindow();
Robert Carr414ebc62017-04-12 12:01:00 -0700241
242 getViewRootImpl().addWindowStoppedCallback(this);
Robert Carr00177cc2017-05-15 15:49:17 -0700243 mWindowStopped = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700244
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700245 mViewVisibility = getVisibility() == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700246 updateRequestedVisibility();
Romain Guy01d5edc2011-01-28 11:28:53 -0800247
Robert Carr8508bb22017-03-27 15:46:27 -0700248 mAttachedToWindow = true;
Karthik Ravi Shankara59c3a52017-09-11 17:36:25 -0700249 mParent.requestTransparentRegion(SurfaceView.this);
Romain Guy01d5edc2011-01-28 11:28:53 -0800250 if (!mGlobalListenersAdded) {
251 ViewTreeObserver observer = getViewTreeObserver();
252 observer.addOnScrollChangedListener(mScrollChangedListener);
253 observer.addOnPreDrawListener(mDrawListener);
254 mGlobalListenersAdded = true;
255 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700256 }
257
258 @Override
259 protected void onWindowVisibilityChanged(int visibility) {
260 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700261 mWindowVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700262 updateRequestedVisibility();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800263 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700264 }
265
266 @Override
267 public void setVisibility(int visibility) {
268 super.setVisibility(visibility);
269 mViewVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700270 boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700271 if (newRequestedVisible != mRequestedVisible) {
272 // our base class (View) invalidates the layout only when
273 // we go from/to the GONE state. However, SurfaceView needs
274 // to request a re-layout when the visibility changes at all.
275 // This is needed because the transparent region is computed
276 // as part of the layout phase, and it changes (obviously) when
277 // the visibility changes.
278 requestLayout();
279 }
280 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800281 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700282 }
Romain Guyafc3e112010-06-07 17:04:33 -0700283
Issei Suzuki927fe872019-06-17 15:56:57 +0200284 /**
285 * Make alpha value of this view reflect onto the surface. This can only be called from at most
286 * one SurfaceView within a view tree.
287 *
288 * <p class="note"><strong>Note:</strong> Alpha value of the view is ignored and the underlying
289 * surface is rendered opaque by default.</p>
290 *
291 * @hide
292 */
293 public void setUseAlpha() {
294 if (!mUseAlpha) {
295 mUseAlpha = true;
296 updateSurfaceAlpha();
297 }
298 }
299
300 @Override
301 public void setAlpha(float alpha) {
302 // Sets the opacity of the view to a value, where 0 means the view is completely transparent
303 // and 1 means the view is completely opaque.
304 //
305 // Note: Alpha value of this view is ignored by default. To enable alpha blending, you need
306 // to call setUseAlpha() as well.
307 // This view doesn't support translucent opacity if the view is located z-below, since the
308 // logic to punch a hole in the view hierarchy cannot handle such case. See also
309 // #clearSurfaceViewPort(Canvas)
310 if (DEBUG) {
311 Log.d(TAG, System.identityHashCode(this)
312 + " setAlpha: mUseAlpha = " + mUseAlpha + " alpha=" + alpha);
313 }
314 super.setAlpha(alpha);
315 updateSurfaceAlpha();
316 }
317
318 private float getFixedAlpha() {
319 // Compute alpha value to be set on the underlying surface.
320 final float alpha = getAlpha();
321 return mUseAlpha && (mSubLayer > 0 || alpha == 0f) ? alpha : 1f;
322 }
323
324 private void updateSurfaceAlpha() {
325 if (!mUseAlpha) {
326 if (DEBUG) {
327 Log.d(TAG, System.identityHashCode(this)
328 + " updateSurfaceAlpha: setUseAlpha() is not called, ignored.");
329 }
330 return;
331 }
332 final float viewAlpha = getAlpha();
333 if (mSubLayer < 0 && 0f < viewAlpha && viewAlpha < 1f) {
334 Log.w(TAG, System.identityHashCode(this)
335 + " updateSurfaceAlpha:"
336 + " translucent color is not supported for a surface placed z-below.");
337 }
338 if (!mHaveFrame) {
339 if (DEBUG) {
340 Log.d(TAG, System.identityHashCode(this)
341 + " updateSurfaceAlpha: has no surface.");
342 }
343 return;
344 }
345 final ViewRootImpl viewRoot = getViewRootImpl();
346 if (viewRoot == null) {
347 if (DEBUG) {
348 Log.d(TAG, System.identityHashCode(this)
349 + " updateSurfaceAlpha: ViewRootImpl not available.");
350 }
351 return;
352 }
353 if (mSurfaceControl == null) {
354 if (DEBUG) {
355 Log.d(TAG, System.identityHashCode(this)
356 + "updateSurfaceAlpha:"
357 + " surface is not yet created, or already released.");
358 }
359 return;
360 }
361 final Surface parent = viewRoot.mSurface;
362 if (parent == null || !parent.isValid()) {
363 if (DEBUG) {
364 Log.d(TAG, System.identityHashCode(this)
365 + " updateSurfaceAlpha: ViewRootImpl has no valid surface");
366 }
367 return;
368 }
369 final float alpha = getFixedAlpha();
370 if (alpha != mSurfaceAlpha) {
371 if (isHardwareAccelerated()) {
372 /*
373 * Schedule a callback that reflects an alpha value onto the underlying surfaces.
374 * This gets called on a RenderThread worker thread, so members accessed here must
375 * be protected by a lock.
376 */
377 viewRoot.registerRtFrameCallback(frame -> {
378 try {
379 final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
380 synchronized (mSurfaceControlLock) {
381 if (!parent.isValid()) {
382 if (DEBUG) {
383 Log.d(TAG, System.identityHashCode(this)
384 + " updateSurfaceAlpha RT:"
385 + " ViewRootImpl has no valid surface");
386 }
387 return;
388 }
389 if (mSurfaceControl == null) {
390 if (DEBUG) {
391 Log.d(TAG, System.identityHashCode(this)
392 + "updateSurfaceAlpha RT:"
393 + " mSurfaceControl has already released");
394 }
395 return;
396 }
397 if (DEBUG) {
398 Log.d(TAG, System.identityHashCode(this)
399 + " updateSurfaceAlpha RT: set alpha=" + alpha);
400 }
401 t.setAlpha(mSurfaceControl, alpha);
402 t.deferTransactionUntilSurface(mSurfaceControl, parent, frame);
403 }
404 // It's possible that mSurfaceControl is released in the UI thread before
405 // the transaction completes. If that happens, an exception is thrown, which
406 // must be caught immediately.
407 t.apply();
408 } catch (Exception e) {
409 Log.e(TAG, System.identityHashCode(this)
410 + "updateSurfaceAlpha RT: Exception during surface transaction", e);
411 }
412 });
413 damageInParent();
414 } else {
415 if (DEBUG) {
416 Log.d(TAG, System.identityHashCode(this)
417 + " updateSurfaceAlpha: set alpha=" + alpha);
418 }
419 SurfaceControl.openTransaction();
420 try {
421 mSurfaceControl.setAlpha(alpha);
422 } finally {
423 SurfaceControl.closeTransaction();
424 }
425 }
426 mSurfaceAlpha = alpha;
427 }
428 }
429
Robert Carrb53670a2017-05-25 18:20:49 -0700430 private void performDrawFinished() {
431 if (mPendingReportDraws > 0) {
432 mDrawFinished = true;
433 if (mAttachedToWindow) {
Robert Carrb53670a2017-05-25 18:20:49 -0700434 notifyDrawFinished();
435 invalidate();
436 }
437 } else {
438 Log.e(TAG, System.identityHashCode(this) + "finished drawing"
439 + " but no pending report draw (extra call"
440 + " to draw completion runnable?)");
441 }
442 }
443
Robert Carr8508bb22017-03-27 15:46:27 -0700444 void notifyDrawFinished() {
445 ViewRootImpl viewRoot = getViewRootImpl();
446 if (viewRoot != null) {
447 viewRoot.pendingDrawFinished();
448 }
449 mPendingReportDraws--;
450 }
451
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700452 @Override
John Reck77e4a522014-10-01 10:38:07 -0700453 protected void onDetachedFromWindow() {
Lucas Dupin0c207342017-04-14 19:47:23 -0700454 ViewRootImpl viewRoot = getViewRootImpl();
455 // It's possible to create a SurfaceView using the default constructor and never
456 // attach it to a view hierarchy, this is a common use case when dealing with
457 // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
458 // the lifecycle. Instead of attaching it to a view, he/she can just pass
459 // the SurfaceHolder forward, most live wallpapers do it.
460 if (viewRoot != null) {
461 viewRoot.removeWindowStoppedCallback(this);
462 }
Robert Carr414ebc62017-04-12 12:01:00 -0700463
Robert Carr8508bb22017-03-27 15:46:27 -0700464 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800465 if (mGlobalListenersAdded) {
466 ViewTreeObserver observer = getViewTreeObserver();
467 observer.removeOnScrollChangedListener(mScrollChangedListener);
468 observer.removeOnPreDrawListener(mDrawListener);
469 mGlobalListenersAdded = false;
470 }
471
Robert Carr8508bb22017-03-27 15:46:27 -0700472 while (mPendingReportDraws > 0) {
473 notifyDrawFinished();
474 }
475
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700476 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800477
Robert Carrd5c7dd62017-03-08 10:39:30 -0800478 updateSurface();
Issei Suzuki927fe872019-06-17 15:56:57 +0200479 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800480 mHaveFrame = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700481
John Reck77e4a522014-10-01 10:38:07 -0700482 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700483 }
484
485 @Override
486 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800487 int width = mRequestedWidth >= 0
488 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
489 : getDefaultSize(0, widthMeasureSpec);
490 int height = mRequestedHeight >= 0
491 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
492 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700493 setMeasuredDimension(width, height);
494 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700495
Mathias Agopianef115302010-10-04 20:15:08 -0700496 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700497 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100498 @UnsupportedAppUsage
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700499 protected boolean setFrame(int left, int top, int right, int bottom) {
500 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800501 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700502 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700503 }
504
505 @Override
506 public boolean gatherTransparentRegion(Region region) {
Robert Carr3ca12be72017-05-22 14:57:48 -0700507 if (isAboveParent() || !mDrawFinished) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700508 return super.gatherTransparentRegion(region);
509 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700510
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700511 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700512 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700513 // this view draws, remove it from the transparent region
514 opaque = super.gatherTransparentRegion(region);
515 } else if (region != null) {
516 int w = getWidth();
517 int h = getHeight();
518 if (w>0 && h>0) {
519 getLocationInWindow(mLocation);
520 // otherwise, punch a hole in the whole hierarchy
521 int l = mLocation[0];
522 int t = mLocation[1];
523 region.op(l, t, l+w, t+h, Region.Op.UNION);
524 }
525 }
526 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
527 opaque = false;
528 }
529 return opaque;
530 }
531
532 @Override
533 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800534 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700535 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700536 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700537 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400538 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700539 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700540 }
541 super.draw(canvas);
542 }
543
544 @Override
545 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800546 if (mDrawFinished && !isAboveParent()) {
547 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700548 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700549 // punch a whole in the view-hierarchy below us
Mark Renouf34d04f32019-05-13 15:53:18 -0400550 clearSurfaceViewPort(canvas);
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700551 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700552 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700553 super.dispatchDraw(canvas);
554 }
555
Mark Renouf34d04f32019-05-13 15:53:18 -0400556 private void clearSurfaceViewPort(Canvas canvas) {
557 if (mCornerRadius > 0f) {
558 canvas.getClipBounds(mTmpRect);
559 canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
560 mCornerRadius, mCornerRadius, mRoundedViewportPaint);
561 } else {
562 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
563 }
564 }
565
566 /**
567 * Sets the corner radius for the SurfaceView. This will round both the corners of the
568 * underlying surface, as well as the corners of the hole created to expose the surface.
569 *
570 * @param cornerRadius the new radius of the corners in pixels
571 * @hide
572 */
573 public void setCornerRadius(float cornerRadius) {
574 mCornerRadius = cornerRadius;
575 if (mCornerRadius > 0f && mRoundedViewportPaint == null) {
576 mRoundedViewportPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
577 mRoundedViewportPaint.setBlendMode(BlendMode.CLEAR);
578 mRoundedViewportPaint.setColor(0);
579 }
580 invalidate();
581 }
582
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700583 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700584 * Control whether the surface view's surface is placed on top of another
585 * regular surface view in the window (but still behind the window itself).
586 * This is typically used to place overlays on top of an underlying media
587 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700588 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700589 * <p>Note that this must be set before the surface view's containing
590 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700591 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700592 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
593 */
594 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800595 mSubLayer = isMediaOverlay
596 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700597 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700598
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700599 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700600 * Control whether the surface view's surface is placed on top of its
601 * window. Normally it is placed behind the window, to allow it to
602 * (for the most part) appear to composite with the views in the
603 * hierarchy. By setting this, you cause it to be placed above the
604 * window. This means that none of the contents of the window this
605 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700606 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700607 * <p>Note that this must be set before the surface view's containing
608 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700609 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700610 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700611 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700612 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500613 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800614 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500615 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800616 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500617 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700618 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700619
620 /**
621 * Control whether the surface view's content should be treated as secure,
622 * preventing it from appearing in screenshots or from being viewed on
623 * non-secure displays.
624 *
625 * <p>Note that this must be set before the surface view's containing
626 * window is attached to the window manager.
627 *
628 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
629 *
630 * @param isSecure True if the surface view is secure.
631 */
632 public void setSecure(boolean isSecure) {
633 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800634 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700635 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800636 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700637 }
638 }
639
Robert Carr55235552017-06-02 14:21:03 -0700640 private void updateOpaqueFlag() {
Robert Carr851e7e42017-06-06 14:04:50 -0700641 if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
Robert Carr55235552017-06-02 14:21:03 -0700642 mSurfaceFlags |= SurfaceControl.OPAQUE;
643 } else {
644 mSurfaceFlags &= ~SurfaceControl.OPAQUE;
645 }
646 }
647
Robert Carrb923f542019-05-13 12:27:51 -0700648 private void updateBackgroundVisibilityInTransaction(SurfaceControl viewRoot) {
649 if (mBackgroundControl == null) {
650 return;
651 }
652 if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
653 mBackgroundControl.show();
654 mBackgroundControl.setRelativeLayer(viewRoot, Integer.MIN_VALUE);
655 } else {
656 mBackgroundControl.hide();
657 }
658 }
659
660 private void releaseSurfaces() {
Issei Suzuki927fe872019-06-17 15:56:57 +0200661 synchronized (mSurfaceControlLock) {
662 if (mSurfaceControl != null) {
663 mTmpTransaction.remove(mSurfaceControl);
664 mSurfaceControl = null;
665 }
666 if (mBackgroundControl != null) {
667 mTmpTransaction.remove(mBackgroundControl);
668 mBackgroundControl = null;
669 }
670 mTmpTransaction.apply();
Robert Carrb923f542019-05-13 12:27:51 -0700671 }
Issei Suzuki927fe872019-06-17 15:56:57 +0200672 mSurfaceAlpha = 1f;
Robert Carrb923f542019-05-13 12:27:51 -0700673 }
674
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900675 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800676 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700677 if (!mHaveFrame) {
Issei Suzuki927fe872019-06-17 15:56:57 +0200678 if (DEBUG) {
679 Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
680 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700681 return;
682 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800683 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800684 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
Issei Suzuki927fe872019-06-17 15:56:57 +0200685 if (DEBUG) {
686 Log.d(TAG, System.identityHashCode(this)
687 + " updateSurface: no valid surface");
688 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800689 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700690 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700691
Issei Suzuki33727a02019-07-02 12:31:34 +0200692 final Translator translator = viewRoot.mTranslator;
693 if (translator != null) {
694 mSurface.setCompatibilityTranslator(translator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700695 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700696
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700697 int myWidth = mRequestedWidth;
698 if (myWidth <= 0) myWidth = getWidth();
699 int myHeight = mRequestedHeight;
700 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700701
Issei Suzuki927fe872019-06-17 15:56:57 +0200702 final float alpha = getFixedAlpha();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700703 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700704 final boolean visibleChanged = mVisible != mRequestedVisible;
Issei Suzuki927fe872019-06-17 15:56:57 +0200705 final boolean alphaChanged = mSurfaceAlpha != alpha;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700706 final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
Robert Carrd5c7dd62017-03-08 10:39:30 -0800707 && mRequestedVisible;
708 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800709 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700710 boolean redrawNeeded = false;
711
Issei Suzuki927fe872019-06-17 15:56:57 +0200712 if (creating || formatChanged || sizeChanged || visibleChanged || (mUseAlpha
713 && alphaChanged) || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800714 getLocationInWindow(mLocation);
715
John Reckaa6e84f2016-06-16 15:36:13 -0700716 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
717 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700718 + " format=" + formatChanged + " size=" + sizeChanged
Issei Suzuki927fe872019-06-17 15:56:57 +0200719 + " visible=" + visibleChanged + " alpha=" + alphaChanged
720 + " mUseAlpha=" + mUseAlpha
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700721 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800722 + " left=" + (mWindowSpaceLeft != mLocation[0])
723 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700724
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700725 try {
726 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800727 mWindowSpaceLeft = mLocation[0];
728 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800729 mSurfaceWidth = myWidth;
730 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700731 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800732 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700733
Robert Carrd5c7dd62017-03-08 10:39:30 -0800734 mScreenRect.left = mWindowSpaceLeft;
735 mScreenRect.top = mWindowSpaceTop;
736 mScreenRect.right = mWindowSpaceLeft + getWidth();
737 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Issei Suzuki33727a02019-07-02 12:31:34 +0200738 if (translator != null) {
739 translator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700740 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700741
Issei Suzuki927fe872019-06-17 15:56:57 +0200742 final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800743 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
744
745 if (creating) {
Vishnu Nairb040c012018-09-07 11:38:32 -0700746 viewRoot.createBoundsSurface(mSubLayer);
Robert Carr5fea55b2018-12-10 13:05:52 -0800747 mSurfaceSession = new SurfaceSession();
Robert Carr3bc95b52017-03-20 21:57:23 -0700748 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carr55235552017-06-02 14:21:03 -0700749
750 updateOpaqueFlag();
Robert Carre625fcf2017-09-01 12:36:28 -0700751 final String name = "SurfaceView - " + viewRoot.getTitle().toString();
752
Robert Carrb923f542019-05-13 12:27:51 -0700753 mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
754 .setName(name)
755 .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
756 .setBufferSize(mSurfaceWidth, mSurfaceHeight)
757 .setFormat(mFormat)
758 .setParent(viewRoot.getSurfaceControl())
759 .setFlags(mSurfaceFlags)
760 .build();
761 mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
762 .setName("Background for -" + name)
763 .setOpaque(true)
764 .setColorLayer()
765 .setParent(mSurfaceControl)
766 .build();
767
Robert Carr44ab5752017-03-20 21:47:11 -0700768 } else if (mSurfaceControl == null) {
769 return;
Robert Carr64aadd02015-11-06 13:54:20 -0800770 }
771
Robert Carrd5c7dd62017-03-08 10:39:30 -0800772 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800773
Dianne Hackborn726426e2010-03-31 22:04:36 -0700774 mSurfaceLock.lock();
775 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700776 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700777
John Reckaa6e84f2016-06-16 15:36:13 -0700778 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
779 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800780
Robert Carrd5c7dd62017-03-08 10:39:30 -0800781 SurfaceControl.openTransaction();
782 try {
783 mSurfaceControl.setLayer(mSubLayer);
Robert Carrb923f542019-05-13 12:27:51 -0700784
Robert Carrd5c7dd62017-03-08 10:39:30 -0800785 if (mViewVisibility) {
786 mSurfaceControl.show();
787 } else {
788 mSurfaceControl.hide();
789 }
Robert Carrb923f542019-05-13 12:27:51 -0700790 updateBackgroundVisibilityInTransaction(viewRoot.getSurfaceControl());
Issei Suzuki927fe872019-06-17 15:56:57 +0200791 if (mUseAlpha) {
792 mSurfaceControl.setAlpha(alpha);
793 mSurfaceAlpha = alpha;
794 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800795
796 // While creating the surface, we will set it's initial
797 // geometry. Outside of that though, we should generally
798 // leave it to the RenderThread.
Robert Carr511719f2017-03-13 15:27:15 -0700799 //
800 // There is one more case when the buffer size changes we aren't yet
801 // prepared to sync (as even following the transaction applying
802 // we still need to latch a buffer).
803 // b/28866173
804 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800805 mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
806 mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
807 0.0f, 0.0f,
808 mScreenRect.height() / (float) mSurfaceHeight);
Vishnu Naire86bd982018-11-28 13:23:17 -0800809 // Set a window crop when creating the surface or changing its size to
810 // crop the buffer to the surface size since the buffer producer may
811 // use SCALING_MODE_SCALE and submit a larger size than the surface
812 // size.
813 mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800814 }
Mark Renouf34d04f32019-05-13 15:53:18 -0400815 mSurfaceControl.setCornerRadius(mCornerRadius);
youngmin0822.lee4dde7d12018-07-09 14:25:32 +0900816 if (sizeChanged && !creating) {
Vishnu Naire86bd982018-11-28 13:23:17 -0800817 mSurfaceControl.setBufferSize(mSurfaceWidth, mSurfaceHeight);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800818 }
819 } finally {
820 SurfaceControl.closeTransaction();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700821 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800822
Robert Carrd5c7dd62017-03-08 10:39:30 -0800823 if (sizeChanged || creating) {
824 redrawNeeded = true;
825 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800826
Dianne Hackborn726426e2010-03-31 22:04:36 -0700827 mSurfaceFrame.left = 0;
828 mSurfaceFrame.top = 0;
Issei Suzuki33727a02019-07-02 12:31:34 +0200829 if (translator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800830 mSurfaceFrame.right = mSurfaceWidth;
831 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700832 } else {
Issei Suzuki33727a02019-07-02 12:31:34 +0200833 float appInvertedScale = translator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800834 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
835 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700836 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700837
Dianne Hackborn726426e2010-03-31 22:04:36 -0700838 final int surfaceWidth = mSurfaceFrame.right;
839 final int surfaceHeight = mSurfaceFrame.bottom;
840 realSizeChanged = mLastSurfaceWidth != surfaceWidth
841 || mLastSurfaceHeight != surfaceHeight;
842 mLastSurfaceWidth = surfaceWidth;
843 mLastSurfaceHeight = surfaceHeight;
844 } finally {
845 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700846 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700847
848 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800849 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700850
Issei Suzuki03c2c102019-07-03 20:04:48 +0200851 SurfaceHolder.Callback[] callbacks = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700852
Robert Carrd5c7dd62017-03-08 10:39:30 -0800853 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800854 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
855 mSurfaceCreated = false;
856 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700857 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
858 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800859 callbacks = getSurfaceCallbacks();
860 for (SurfaceHolder.Callback c : callbacks) {
861 c.surfaceDestroyed(mSurfaceHolder);
862 }
Robert Carr387838b2016-09-07 14:12:44 -0700863 // Since Android N the same surface may be reused and given to us
864 // again by the system server at a later point. However
865 // as we didn't do this in previous releases, clients weren't
866 // necessarily required to clean up properly in
867 // surfaceDestroyed. This leads to problems for example when
868 // clients don't destroy their EGL context, and try
869 // and create a new one on the same surface following reuse.
870 // Since there is no valid use of the surface in-between
871 // surfaceDestroyed and surfaceCreated, we force a disconnect,
872 // so the next connect will always work if we end up reusing
873 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700874 if (mSurface.isValid()) {
875 mSurface.forceScopedDisconnect();
876 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700877 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800878 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700879
Robert Carrd5c7dd62017-03-08 10:39:30 -0800880 if (creating) {
Robert Carrb923f542019-05-13 12:27:51 -0700881 mSurface.copyFrom(mSurfaceControl);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800882 }
883
Bryce Lee453fc362017-06-20 10:47:55 -0700884 if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
Bryce Lee02949f12017-06-16 07:20:34 -0700885 < Build.VERSION_CODES.O) {
886 // Some legacy applications use the underlying native {@link Surface} object
887 // as a key to whether anything has changed. In these cases, updates to the
888 // existing {@link Surface} will be ignored when the size changes.
889 // Therefore, we must explicitly recreate the {@link Surface} in these
890 // cases.
Robert Carrb923f542019-05-13 12:27:51 -0700891 mSurface.createFrom(mSurfaceControl);
Bryce Lee02949f12017-06-16 07:20:34 -0700892 }
893
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200894 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800895 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
896 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700897 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700898 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
899 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800900 if (callbacks == null) {
901 callbacks = getSurfaceCallbacks();
902 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700903 for (SurfaceHolder.Callback c : callbacks) {
904 c.surfaceCreated(mSurfaceHolder);
905 }
906 }
907 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700908 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700909 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
910 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800911 + " w=" + myWidth + " h=" + myHeight);
912 if (callbacks == null) {
913 callbacks = getSurfaceCallbacks();
914 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700915 for (SurfaceHolder.Callback c : callbacks) {
916 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
917 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700918 }
919 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -0700920 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
921 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800922 if (callbacks == null) {
923 callbacks = getSurfaceCallbacks();
924 }
Robert Carr8508bb22017-03-27 15:46:27 -0700925
926 mPendingReportDraws++;
927 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -0800928 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -0800929 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -0800930 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700931 }
932 }
933 } finally {
934 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800935 if (mSurfaceControl != null && !mSurfaceCreated) {
Robert Carrde844432017-05-04 13:45:45 -0700936 mSurface.release();
Robert Carrb923f542019-05-13 12:27:51 -0700937 releaseSurfaces();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800938 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700939 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800940 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700941 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700942 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800943 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -0800944 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
945 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
946 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -0700947 } else {
948 // Calculate the window position in case RT loses the window
949 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -0800950 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -0800951 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
952 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800953 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
954 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -0800955 if (positionChanged || layoutSizeChanged) { // Only the position has changed
956 mWindowSpaceLeft = mLocation[0];
957 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800958 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -0800959 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800960 mLocation[0] = getWidth();
961 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -0800962
Robert Carrd5c7dd62017-03-08 10:39:30 -0800963 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
Robert Carrc90e5f82017-07-18 13:10:02 -0700964 mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
John Reckf057fb52016-04-15 13:46:29 -0700965
Issei Suzuki33727a02019-07-02 12:31:34 +0200966 if (translator != null) {
967 translator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -0700968 }
969
Robert Carr3651ab82017-04-25 12:05:34 -0700970 if (mSurfaceControl == null) {
971 return;
972 }
973
Bryce Lee16e50892017-04-11 01:59:37 +0000974 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
John Reckf23a1b82016-06-22 14:23:31 -0700975 try {
Issei Suzuki927fe872019-06-17 15:56:57 +0200976 if (DEBUG_POSITION) {
977 Log.d(TAG, String.format("%d updateSurfacePosition UI, "
978 + "position = [%d, %d, %d, %d]",
979 System.identityHashCode(this),
980 mScreenRect.left, mScreenRect.top,
981 mScreenRect.right, mScreenRect.bottom));
982 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800983 setParentSpaceRectangle(mScreenRect, -1);
984 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700985 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -0700986 }
John Reckf6481082016-02-02 15:18:23 -0800987 }
Rob Carr64e516f2015-10-29 00:20:45 +0000988 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700989 }
990 }
991
Robert Carrd5c7dd62017-03-08 10:39:30 -0800992 private void onDrawFinished() {
993 if (DEBUG) {
994 Log.i(TAG, System.identityHashCode(this) + " "
995 + "finishedDrawing");
996 }
Robert Carr3bc95b52017-03-20 21:57:23 -0700997
998 if (mDeferredDestroySurfaceControl != null) {
chaviwdd5bde02019-06-07 16:33:50 -0700999 mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
Robert Carr3bc95b52017-03-20 21:57:23 -07001000 mDeferredDestroySurfaceControl = null;
1001 }
1002
Issei Suzuki03c2c102019-07-03 20:04:48 +02001003 runOnUiThread(this::performDrawFinished);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001004 }
1005
Robert Carr27a800a2018-03-16 13:33:45 -07001006 /**
1007 * A place to over-ride for applying child-surface transactions.
1008 * These can be synchronized with the viewroot surface using deferTransaction.
1009 *
1010 * Called from RenderWorker while UI thread is paused.
1011 * @hide
1012 */
1013 protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
1014 Surface viewRootSurface, long nextViewRootFrameNumber) {
1015 }
1016
Robert Carr386fd702018-03-23 13:46:39 -07001017 private void applySurfaceTransforms(SurfaceControl surface, Rect position, long frameNumber) {
Robert Carr27a800a2018-03-16 13:33:45 -07001018 if (frameNumber > 0) {
Robert Carr386fd702018-03-23 13:46:39 -07001019 final ViewRootImpl viewRoot = getViewRootImpl();
1020
1021 mRtTransaction.deferTransactionUntilSurface(surface, viewRoot.mSurface,
Robert Carr27a800a2018-03-16 13:33:45 -07001022 frameNumber);
Robert Carrd5c7dd62017-03-08 10:39:30 -08001023 }
Robert Carr386fd702018-03-23 13:46:39 -07001024
1025 mRtTransaction.setPosition(surface, position.left, position.top);
1026 mRtTransaction.setMatrix(surface,
Robert Carr27a800a2018-03-16 13:33:45 -07001027 position.width() / (float) mSurfaceWidth,
1028 0.0f, 0.0f,
1029 position.height() / (float) mSurfaceHeight);
John Reckd0abd662019-05-01 12:52:04 -07001030 if (mViewVisibility) {
1031 mRtTransaction.show(surface);
1032 }
Robert Carr386fd702018-03-23 13:46:39 -07001033 }
1034
1035 private void setParentSpaceRectangle(Rect position, long frameNumber) {
1036 final ViewRootImpl viewRoot = getViewRootImpl();
1037
Robert Carrb923f542019-05-13 12:27:51 -07001038 applySurfaceTransforms(mSurfaceControl, position, frameNumber);
Robert Carr27a800a2018-03-16 13:33:45 -07001039
1040 applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface,
1041 frameNumber);
1042
1043 mRtTransaction.apply();
Robert Carrd5c7dd62017-03-08 10:39:30 -08001044 }
1045
John Reckf6481082016-02-02 15:18:23 -08001046 private Rect mRTLastReportedPosition = new Rect();
1047
John Reck6b164402018-09-24 15:25:42 -07001048 private RenderNode.PositionUpdateListener mPositionListener =
1049 new RenderNode.PositionUpdateListener() {
Robert Carrd5c7dd62017-03-08 10:39:30 -08001050
John Reck6b164402018-09-24 15:25:42 -07001051 @Override
1052 public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
1053 if (mSurfaceControl == null) {
1054 return;
John Reckf6481082016-02-02 15:18:23 -08001055 }
John Reckf6481082016-02-02 15:18:23 -08001056
John Reck6b164402018-09-24 15:25:42 -07001057 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
1058 // its 2nd frame if RenderThread is running slowly could potentially see
1059 // this as false, enter the branch, get pre-empted, then this comes along
1060 // and reports a new position, then the UI thread resumes and reports
1061 // its position. This could therefore be de-sync'd in that interval, but
1062 // the synchronization would violate the rule that RT must never block
1063 // on the UI thread which would open up potential deadlocks. The risk of
1064 // a single-frame desync is therefore preferable for now.
1065 mRtHandlingPositionUpdates = true;
1066 if (mRTLastReportedPosition.left == left
1067 && mRTLastReportedPosition.top == top
1068 && mRTLastReportedPosition.right == right
1069 && mRTLastReportedPosition.bottom == bottom) {
1070 return;
1071 }
1072 try {
Issei Suzuki927fe872019-06-17 15:56:57 +02001073 if (DEBUG_POSITION) {
John Reck6b164402018-09-24 15:25:42 -07001074 Log.d(TAG, String.format(
1075 "%d updateSurfacePosition RenderWorker, frameNr = %d, "
Issei Suzuki03c2c102019-07-03 20:04:48 +02001076 + "position = [%d, %d, %d, %d]",
John Reck6b164402018-09-24 15:25:42 -07001077 System.identityHashCode(this), frameNumber,
1078 left, top, right, bottom));
1079 }
1080 mRTLastReportedPosition.set(left, top, right, bottom);
1081 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
1082 // Now overwrite mRTLastReportedPosition with our values
1083 } catch (Exception ex) {
1084 Log.e(TAG, "Exception from repositionChild", ex);
1085 }
John Reckaa6e84f2016-06-16 15:36:13 -07001086 }
Robert Carrad3a4932017-06-20 14:55:21 -07001087
John Reck6b164402018-09-24 15:25:42 -07001088 @Override
1089 public void positionLost(long frameNumber) {
1090 if (DEBUG) {
1091 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
1092 System.identityHashCode(this), frameNumber));
1093 }
1094 mRTLastReportedPosition.setEmpty();
1095
1096 if (mSurfaceControl == null) {
1097 return;
1098 }
John Reckd0abd662019-05-01 12:52:04 -07001099
1100 if (frameNumber > 0) {
1101 final ViewRootImpl viewRoot = getViewRootImpl();
1102
Robert Carrb923f542019-05-13 12:27:51 -07001103 mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface,
John Reckd0abd662019-05-01 12:52:04 -07001104 frameNumber);
John Reckf23a1b82016-06-22 14:23:31 -07001105 }
Robert Carrb923f542019-05-13 12:27:51 -07001106 mRtTransaction.hide(mSurfaceControl);
John Reckd0abd662019-05-01 12:52:04 -07001107 mRtTransaction.apply();
John Reckf23a1b82016-06-22 14:23:31 -07001108 }
John Reck6b164402018-09-24 15:25:42 -07001109 };
John Reckaa6e84f2016-06-16 15:36:13 -07001110
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001111 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
Issei Suzuki03c2c102019-07-03 20:04:48 +02001112 SurfaceHolder.Callback[] callbacks;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001113 synchronized (mCallbacks) {
1114 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
1115 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001116 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -08001117 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001118 }
1119
John Reck79925002017-05-26 13:57:14 -07001120 private void runOnUiThread(Runnable runnable) {
1121 Handler handler = getHandler();
1122 if (handler != null && handler.getLooper() != Looper.myLooper()) {
1123 handler.post(runnable);
1124 } else {
1125 runnable.run();
1126 }
1127 }
1128
Yohei Yukawa3b5011a2017-03-16 15:34:12 -07001129 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -04001130 * Check to see if the surface has fixed size dimensions or if the surface's
1131 * dimensions are dimensions are dependent on its current layout.
1132 *
1133 * @return true if the surface has dimensions that are fixed in size
1134 * @hide
1135 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01001136 @UnsupportedAppUsage
Derek Sollenberger7179b812010-03-22 13:41:20 -04001137 public boolean isFixedSize() {
1138 return (mRequestedWidth != -1 || mRequestedHeight != -1);
1139 }
1140
Robert Carrd5c7dd62017-03-08 10:39:30 -08001141 private boolean isAboveParent() {
1142 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001143 }
1144
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001145 /**
1146 * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
1147 * and size of the content hasn't updated yet. This color will fill the expanded area when the
1148 * view becomes larger.
1149 * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
1150 * @hide
1151 */
1152 public void setResizeBackgroundColor(int bgColor) {
Robert Carrb923f542019-05-13 12:27:51 -07001153 if (mBackgroundControl == null) {
1154 return;
1155 }
1156
1157 final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
1158 Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
1159
1160 SurfaceControl.openTransaction();
1161 try {
1162 mBackgroundControl.setColor(colorComponents);
1163 } finally {
1164 SurfaceControl.closeTransaction();
1165 }
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001166 }
1167
Mathew Inwooda570dee2018-08-17 14:56:00 +01001168 @UnsupportedAppUsage
Igor Murashkina86ab6402013-08-30 12:58:36 -07001169 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001170 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -07001171
1172 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001173 public boolean isCreating() {
1174 return mIsCreating;
1175 }
1176
Igor Murashkina86ab6402013-08-30 12:58:36 -07001177 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001178 public void addCallback(Callback callback) {
1179 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -07001180 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001181 // have only a couple callbacks, so it doesn't matter.
Issei Suzuki33727a02019-07-02 12:31:34 +02001182 if (!mCallbacks.contains(callback)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001183 mCallbacks.add(callback);
1184 }
1185 }
1186 }
1187
Igor Murashkina86ab6402013-08-30 12:58:36 -07001188 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001189 public void removeCallback(Callback callback) {
1190 synchronized (mCallbacks) {
1191 mCallbacks.remove(callback);
1192 }
1193 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001194
1195 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001196 public void setFixedSize(int width, int height) {
1197 if (mRequestedWidth != width || mRequestedHeight != height) {
1198 mRequestedWidth = width;
1199 mRequestedHeight = height;
1200 requestLayout();
1201 }
1202 }
1203
Igor Murashkina86ab6402013-08-30 12:58:36 -07001204 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001205 public void setSizeFromLayout() {
1206 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
1207 mRequestedWidth = mRequestedHeight = -1;
1208 requestLayout();
1209 }
1210 }
1211
Igor Murashkina86ab6402013-08-30 12:58:36 -07001212 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001213 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -07001214 // for backward compatibility reason, OPAQUE always
1215 // means 565 for SurfaceView
1216 if (format == PixelFormat.OPAQUE)
1217 format = PixelFormat.RGB_565;
1218
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001219 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001220 if (mSurfaceControl != null) {
1221 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001222 }
1223 }
1224
Mathias Agopiand2112302010-12-07 19:38:17 -08001225 /**
1226 * @deprecated setType is now ignored.
1227 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001228 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -08001229 @Deprecated
1230 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001231
Igor Murashkina86ab6402013-08-30 12:58:36 -07001232 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001233 public void setKeepScreenOn(boolean screenOn) {
John Reck79925002017-05-26 13:57:14 -07001234 runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001235 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001236
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001237 /**
1238 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1239 *
1240 * After drawing into the provided {@link Canvas}, the caller must
1241 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1242 *
1243 * The caller must redraw the entire surface.
1244 * @return A canvas for drawing into the surface.
1245 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001246 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001247 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -07001248 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001249 }
1250
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001251 /**
1252 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1253 *
1254 * After drawing into the provided {@link Canvas}, the caller must
1255 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1256 *
1257 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1258 * to redraw. This function may choose to expand the dirty rectangle if for example
1259 * the surface has been resized or if the previous contents of the surface were
1260 * not available. The caller must redraw the entire dirty region as represented
1261 * by the contents of the inOutDirty rectangle upon return from this function.
1262 * The caller may also pass <code>null</code> instead, in the case where the
1263 * entire surface should be redrawn.
1264 * @return A canvas for drawing into the surface.
1265 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001266 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001267 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -07001268 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001269 }
1270
John Reck6bc70142016-10-26 16:49:17 -07001271 @Override
1272 public Canvas lockHardwareCanvas() {
1273 return internalLockCanvas(null, true);
1274 }
1275
1276 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001277 mSurfaceLock.lock();
1278
John Reckaa6e84f2016-06-16 15:36:13 -07001279 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001280 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001281
1282 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001283 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001284 try {
John Reck6bc70142016-10-26 16:49:17 -07001285 if (hardware) {
1286 c = mSurface.lockHardwareCanvas();
1287 } else {
1288 c = mSurface.lockCanvas(dirty);
1289 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001290 } catch (Exception e) {
1291 Log.e(LOG_TAG, "Exception locking surface", e);
1292 }
1293 }
1294
John Reckaa6e84f2016-06-16 15:36:13 -07001295 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001296 if (c != null) {
1297 mLastLockTime = SystemClock.uptimeMillis();
1298 return c;
1299 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001300
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001301 // If the Surface is not ready to be drawn, then return null,
1302 // but throttle calls to this function so it isn't called more
1303 // than every 100ms.
1304 long now = SystemClock.uptimeMillis();
1305 long nextTime = mLastLockTime + 100;
1306 if (nextTime > now) {
1307 try {
1308 Thread.sleep(nextTime-now);
1309 } catch (InterruptedException e) {
1310 }
1311 now = SystemClock.uptimeMillis();
1312 }
1313 mLastLockTime = now;
1314 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001315
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001316 return null;
1317 }
1318
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001319 /**
1320 * Posts the new contents of the {@link Canvas} to the surface and
1321 * releases the {@link Canvas}.
1322 *
1323 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1324 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001325 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001326 public void unlockCanvasAndPost(Canvas canvas) {
1327 mSurface.unlockCanvasAndPost(canvas);
1328 mSurfaceLock.unlock();
1329 }
1330
Igor Murashkina86ab6402013-08-30 12:58:36 -07001331 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001332 public Surface getSurface() {
1333 return mSurface;
1334 }
1335
Igor Murashkina86ab6402013-08-30 12:58:36 -07001336 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001337 public Rect getSurfaceFrame() {
1338 return mSurfaceFrame;
1339 }
1340 };
Robert Carr55235552017-06-02 14:21:03 -07001341
chaviwff2e7d82018-11-02 11:11:27 -07001342 /**
Robert Carr76907ee2019-01-11 13:38:19 -08001343 * Return a SurfaceControl which can be used for parenting Surfaces to
1344 * this SurfaceView.
1345 *
1346 * @return The SurfaceControl for this SurfaceView.
chaviwff2e7d82018-11-02 11:11:27 -07001347 */
1348 public SurfaceControl getSurfaceControl() {
Robert Carrb923f542019-05-13 12:27:51 -07001349 return mSurfaceControl;
chaviwff2e7d82018-11-02 11:11:27 -07001350 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001351}