blob: a0af83d17abd8388f8093775d8a05e6c04200241 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Adrian Roose99bc052017-11-20 17:55:31 +010019import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
20import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
21import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
Robert Carrd5c7dd62017-03-08 10:39:30 -080022
Mathew Inwooda570dee2018-08-17 14:56:00 +010023import android.annotation.UnsupportedAppUsage;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070024import android.content.Context;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070025import android.content.res.CompatibilityInfo.Translator;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070026import android.content.res.Configuration;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070027import android.graphics.Canvas;
Andrii Kuliancf8f6832018-01-23 19:43:30 -080028import android.graphics.Color;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070029import android.graphics.PixelFormat;
30import android.graphics.PorterDuff;
31import android.graphics.Rect;
32import android.graphics.Region;
John Reck32f140aa62018-10-04 15:08:24 -070033import android.graphics.RenderNode;
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070034import android.os.Build;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070035import android.os.Handler;
Robert Carr55235552017-06-02 14:21:03 -070036import android.os.IBinder;
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;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700102
Mathew Inwooda570dee2018-08-17 14:56:00 +0100103 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700104 final ArrayList<SurfaceHolder.Callback> mCallbacks
105 = new ArrayList<SurfaceHolder.Callback>();
106
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
Andrii Kuliancf8f6832018-01-23 19:43:30 -0800123 SurfaceControlWithBackground 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.
126 SurfaceControl mDeferredDestroySurfaceControl;
Robert Carr33879132016-09-06 14:41:40 -0700127 final Rect mTmpRect = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700128 final Configuration mConfiguration = new Configuration();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700129
Robert Carrd5c7dd62017-03-08 10:39:30 -0800130 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700131
Mathew Inwood31755f92018-12-20 13:53:36 +0000132 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700133 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700134 private volatile boolean mRtHandlingPositionUpdates = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700135
John Reckf6481082016-02-02 15:18:23 -0800136 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700137 = new ViewTreeObserver.OnScrollChangedListener() {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700138 @Override
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700139 public void onScrollChanged() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800140 updateSurface();
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700141 }
142 };
Igor Murashkina86ab6402013-08-30 12:58:36 -0700143
Mathew Inwooda570dee2018-08-17 14:56:00 +0100144 @UnsupportedAppUsage
John Reckf6481082016-02-02 15:18:23 -0800145 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
146 new ViewTreeObserver.OnPreDrawListener() {
147 @Override
148 public boolean onPreDraw() {
149 // reposition ourselves where the surface is
150 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800151 updateSurface();
John Reckf6481082016-02-02 15:18:23 -0800152 return true;
153 }
154 };
155
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700156 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700157 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800158 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700159 boolean mViewVisibility = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700160 boolean mWindowStopped = false;
161
Mathew Inwood31755f92018-12-20 13:53:36 +0000162 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700163 int mRequestedWidth = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000164 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700165 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700166 /* Set SurfaceView's format to 565 by default to maintain backward
167 * compatibility with applications assuming this format.
168 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100169 @UnsupportedAppUsage
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700170 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700171
Mathew Inwooda570dee2018-08-17 14:56:00 +0100172 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700173 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800174 boolean mSurfaceCreated = false;
Mathew Inwood31755f92018-12-20 13:53:36 +0000175 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700176 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700177
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700178 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800179 int mWindowSpaceLeft = -1;
180 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800181 int mSurfaceWidth = -1;
182 int mSurfaceHeight = -1;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100183 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700184 int mFormat = -1;
Mathew Inwood31755f92018-12-20 13:53:36 +0000185 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700186 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700187 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700188 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800189
Romain Guy01d5edc2011-01-28 11:28:53 -0800190 private boolean mGlobalListenersAdded;
Robert Carr8508bb22017-03-27 15:46:27 -0700191 private boolean mAttachedToWindow;
Romain Guyf2499fa2011-01-26 18:31:23 -0800192
Robert Carrd5c7dd62017-03-08 10:39:30 -0800193 private int mSurfaceFlags = SurfaceControl.HIDDEN;
194
Robert Carr8508bb22017-03-27 15:46:27 -0700195 private int mPendingReportDraws;
196
Robert Carr27a800a2018-03-16 13:33:45 -0700197 private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
198
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700199 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400200 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700201 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700202
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700203 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400204 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700205 }
206
Alan Viverette617feb92013-09-09 18:09:13 -0700207 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400208 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700209 }
210
211 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
212 super(context, attrs, defStyleAttr, defStyleRes);
John Reck6b164402018-09-24 15:25:42 -0700213 mRenderNode.requestPositionUpdates(mPositionListener);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700214
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700215 setWillNotDraw(true);
216 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700217
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700218 /**
219 * Return the SurfaceHolder providing access and control over this
220 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700221 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700222 * @return SurfaceHolder The holder of the surface.
223 */
224 public SurfaceHolder getHolder() {
225 return mSurfaceHolder;
226 }
227
Robert Carr414ebc62017-04-12 12:01:00 -0700228 private void updateRequestedVisibility() {
229 mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
230 }
231
232 /** @hide */
233 @Override
234 public void windowStopped(boolean stopped) {
235 mWindowStopped = stopped;
236 updateRequestedVisibility();
237 updateSurface();
238 }
239
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700240 @Override
241 protected void onAttachedToWindow() {
242 super.onAttachedToWindow();
Robert Carr414ebc62017-04-12 12:01:00 -0700243
244 getViewRootImpl().addWindowStoppedCallback(this);
Robert Carr00177cc2017-05-15 15:49:17 -0700245 mWindowStopped = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700246
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700247 mViewVisibility = getVisibility() == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700248 updateRequestedVisibility();
Romain Guy01d5edc2011-01-28 11:28:53 -0800249
Robert Carr8508bb22017-03-27 15:46:27 -0700250 mAttachedToWindow = true;
Karthik Ravi Shankara59c3a52017-09-11 17:36:25 -0700251 mParent.requestTransparentRegion(SurfaceView.this);
Romain Guy01d5edc2011-01-28 11:28:53 -0800252 if (!mGlobalListenersAdded) {
253 ViewTreeObserver observer = getViewTreeObserver();
254 observer.addOnScrollChangedListener(mScrollChangedListener);
255 observer.addOnPreDrawListener(mDrawListener);
256 mGlobalListenersAdded = true;
257 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700258 }
259
260 @Override
261 protected void onWindowVisibilityChanged(int visibility) {
262 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700263 mWindowVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700264 updateRequestedVisibility();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800265 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700266 }
267
268 @Override
269 public void setVisibility(int visibility) {
270 super.setVisibility(visibility);
271 mViewVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700272 boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700273 if (newRequestedVisible != mRequestedVisible) {
274 // our base class (View) invalidates the layout only when
275 // we go from/to the GONE state. However, SurfaceView needs
276 // to request a re-layout when the visibility changes at all.
277 // This is needed because the transparent region is computed
278 // as part of the layout phase, and it changes (obviously) when
279 // the visibility changes.
280 requestLayout();
281 }
282 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800283 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700284 }
Romain Guyafc3e112010-06-07 17:04:33 -0700285
Robert Carrb53670a2017-05-25 18:20:49 -0700286 private void performDrawFinished() {
287 if (mPendingReportDraws > 0) {
288 mDrawFinished = true;
289 if (mAttachedToWindow) {
Robert Carrb53670a2017-05-25 18:20:49 -0700290 notifyDrawFinished();
291 invalidate();
292 }
293 } else {
294 Log.e(TAG, System.identityHashCode(this) + "finished drawing"
295 + " but no pending report draw (extra call"
296 + " to draw completion runnable?)");
297 }
298 }
299
Robert Carr8508bb22017-03-27 15:46:27 -0700300 void notifyDrawFinished() {
301 ViewRootImpl viewRoot = getViewRootImpl();
302 if (viewRoot != null) {
303 viewRoot.pendingDrawFinished();
304 }
305 mPendingReportDraws--;
306 }
307
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700308 @Override
John Reck77e4a522014-10-01 10:38:07 -0700309 protected void onDetachedFromWindow() {
Lucas Dupin0c207342017-04-14 19:47:23 -0700310 ViewRootImpl viewRoot = getViewRootImpl();
311 // It's possible to create a SurfaceView using the default constructor and never
312 // attach it to a view hierarchy, this is a common use case when dealing with
313 // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
314 // the lifecycle. Instead of attaching it to a view, he/she can just pass
315 // the SurfaceHolder forward, most live wallpapers do it.
316 if (viewRoot != null) {
317 viewRoot.removeWindowStoppedCallback(this);
318 }
Robert Carr414ebc62017-04-12 12:01:00 -0700319
Robert Carr8508bb22017-03-27 15:46:27 -0700320 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800321 if (mGlobalListenersAdded) {
322 ViewTreeObserver observer = getViewTreeObserver();
323 observer.removeOnScrollChangedListener(mScrollChangedListener);
324 observer.removeOnPreDrawListener(mDrawListener);
325 mGlobalListenersAdded = false;
326 }
327
Robert Carr8508bb22017-03-27 15:46:27 -0700328 while (mPendingReportDraws > 0) {
329 notifyDrawFinished();
330 }
331
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700332 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800333
Robert Carrd5c7dd62017-03-08 10:39:30 -0800334 updateSurface();
335 if (mSurfaceControl != null) {
336 mSurfaceControl.destroy();
337 }
338 mSurfaceControl = null;
339
340 mHaveFrame = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700341
John Reck77e4a522014-10-01 10:38:07 -0700342 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700343 }
344
345 @Override
346 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800347 int width = mRequestedWidth >= 0
348 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
349 : getDefaultSize(0, widthMeasureSpec);
350 int height = mRequestedHeight >= 0
351 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
352 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700353 setMeasuredDimension(width, height);
354 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700355
Mathias Agopianef115302010-10-04 20:15:08 -0700356 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700357 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100358 @UnsupportedAppUsage
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700359 protected boolean setFrame(int left, int top, int right, int bottom) {
360 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800361 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700362 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700363 }
364
365 @Override
366 public boolean gatherTransparentRegion(Region region) {
Robert Carr3ca12be72017-05-22 14:57:48 -0700367 if (isAboveParent() || !mDrawFinished) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700368 return super.gatherTransparentRegion(region);
369 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700370
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700371 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700372 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700373 // this view draws, remove it from the transparent region
374 opaque = super.gatherTransparentRegion(region);
375 } else if (region != null) {
376 int w = getWidth();
377 int h = getHeight();
378 if (w>0 && h>0) {
379 getLocationInWindow(mLocation);
380 // otherwise, punch a hole in the whole hierarchy
381 int l = mLocation[0];
382 int t = mLocation[1];
383 region.op(l, t, l+w, t+h, Region.Op.UNION);
384 }
385 }
386 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
387 opaque = false;
388 }
389 return opaque;
390 }
391
392 @Override
393 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800394 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700395 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700396 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700397 // punch a whole in the view-hierarchy below us
398 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
399 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700400 }
401 super.draw(canvas);
402 }
403
404 @Override
405 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800406 if (mDrawFinished && !isAboveParent()) {
407 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700408 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700409 // punch a whole in the view-hierarchy below us
410 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
411 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700412 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700413 super.dispatchDraw(canvas);
414 }
415
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700416 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700417 * Control whether the surface view's surface is placed on top of another
418 * regular surface view in the window (but still behind the window itself).
419 * This is typically used to place overlays on top of an underlying media
420 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700421 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700422 * <p>Note that this must be set before the surface view's containing
423 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700424 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700425 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
426 */
427 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800428 mSubLayer = isMediaOverlay
429 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700430 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700431
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700432 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700433 * Control whether the surface view's surface is placed on top of its
434 * window. Normally it is placed behind the window, to allow it to
435 * (for the most part) appear to composite with the views in the
436 * hierarchy. By setting this, you cause it to be placed above the
437 * window. This means that none of the contents of the window this
438 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700439 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700440 * <p>Note that this must be set before the surface view's containing
441 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700442 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700443 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700444 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700445 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500446 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800447 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500448 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800449 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500450 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700451 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700452
453 /**
454 * Control whether the surface view's content should be treated as secure,
455 * preventing it from appearing in screenshots or from being viewed on
456 * non-secure displays.
457 *
458 * <p>Note that this must be set before the surface view's containing
459 * window is attached to the window manager.
460 *
461 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
462 *
463 * @param isSecure True if the surface view is secure.
464 */
465 public void setSecure(boolean isSecure) {
466 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800467 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700468 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800469 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700470 }
471 }
472
Robert Carr55235552017-06-02 14:21:03 -0700473 private void updateOpaqueFlag() {
Robert Carr851e7e42017-06-06 14:04:50 -0700474 if (!PixelFormat.formatHasAlpha(mRequestedFormat)) {
Robert Carr55235552017-06-02 14:21:03 -0700475 mSurfaceFlags |= SurfaceControl.OPAQUE;
476 } else {
477 mSurfaceFlags &= ~SurfaceControl.OPAQUE;
478 }
479 }
480
Robert Carrd5c7dd62017-03-08 10:39:30 -0800481 private Rect getParentSurfaceInsets() {
482 final ViewRootImpl root = getViewRootImpl();
483 if (root == null) {
484 return null;
485 } else {
486 return root.mWindowAttributes.surfaceInsets;
487 }
Jeff Tinker3896db12017-03-03 00:20:22 +0000488 }
489
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900490 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800491 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700492 if (!mHaveFrame) {
493 return;
494 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800495 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800496 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
497 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700498 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700499
Robert Carrd5c7dd62017-03-08 10:39:30 -0800500 mTranslator = viewRoot.mTranslator;
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700501 if (mTranslator != null) {
502 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700503 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700504
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700505 int myWidth = mRequestedWidth;
506 if (myWidth <= 0) myWidth = getWidth();
507 int myHeight = mRequestedHeight;
508 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700509
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700510 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carr7c67b7d2017-07-06 15:28:34 -0700511 final boolean visibleChanged = mVisible != mRequestedVisible;
512 final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
Robert Carrd5c7dd62017-03-08 10:39:30 -0800513 && mRequestedVisible;
514 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800515 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700516 boolean redrawNeeded = false;
517
Robert Carrd5c7dd62017-03-08 10:39:30 -0800518 if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800519 getLocationInWindow(mLocation);
520
John Reckaa6e84f2016-06-16 15:36:13 -0700521 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
522 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700523 + " format=" + formatChanged + " size=" + sizeChanged
524 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800525 + " left=" + (mWindowSpaceLeft != mLocation[0])
526 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700527
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700528 try {
529 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800530 mWindowSpaceLeft = mLocation[0];
531 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800532 mSurfaceWidth = myWidth;
533 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700534 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800535 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700536
Robert Carrd5c7dd62017-03-08 10:39:30 -0800537 mScreenRect.left = mWindowSpaceLeft;
538 mScreenRect.top = mWindowSpaceTop;
539 mScreenRect.right = mWindowSpaceLeft + getWidth();
540 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700541 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800542 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700543 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700544
Robert Carrd5c7dd62017-03-08 10:39:30 -0800545 final Rect surfaceInsets = getParentSurfaceInsets();
546 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
547
548 if (creating) {
Vishnu Nairb040c012018-09-07 11:38:32 -0700549 viewRoot.createBoundsSurface(mSubLayer);
550 mSurfaceSession = new SurfaceSession(viewRoot.mBoundsSurface);
Robert Carr3bc95b52017-03-20 21:57:23 -0700551 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carr55235552017-06-02 14:21:03 -0700552
553 updateOpaqueFlag();
Robert Carre625fcf2017-09-01 12:36:28 -0700554 final String name = "SurfaceView - " + viewRoot.getTitle().toString();
555
556 mSurfaceControl = new SurfaceControlWithBackground(
557 name,
558 (mSurfaceFlags & SurfaceControl.OPAQUE) != 0,
559 new SurfaceControl.Builder(mSurfaceSession)
Vishnu Naire86bd982018-11-28 13:23:17 -0800560 .setBufferSize(mSurfaceWidth, mSurfaceHeight)
Robert Carre625fcf2017-09-01 12:36:28 -0700561 .setFormat(mFormat)
562 .setFlags(mSurfaceFlags));
Robert Carr44ab5752017-03-20 21:47:11 -0700563 } else if (mSurfaceControl == null) {
564 return;
Robert Carr64aadd02015-11-06 13:54:20 -0800565 }
566
Robert Carrd5c7dd62017-03-08 10:39:30 -0800567 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800568
Dianne Hackborn726426e2010-03-31 22:04:36 -0700569 mSurfaceLock.lock();
570 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700571 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700572
John Reckaa6e84f2016-06-16 15:36:13 -0700573 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
574 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800575
Robert Carrd5c7dd62017-03-08 10:39:30 -0800576 SurfaceControl.openTransaction();
577 try {
578 mSurfaceControl.setLayer(mSubLayer);
579 if (mViewVisibility) {
580 mSurfaceControl.show();
581 } else {
582 mSurfaceControl.hide();
583 }
584
585 // While creating the surface, we will set it's initial
586 // geometry. Outside of that though, we should generally
587 // leave it to the RenderThread.
Robert Carr511719f2017-03-13 15:27:15 -0700588 //
589 // There is one more case when the buffer size changes we aren't yet
590 // prepared to sync (as even following the transaction applying
591 // we still need to latch a buffer).
592 // b/28866173
593 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800594 mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
595 mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
596 0.0f, 0.0f,
597 mScreenRect.height() / (float) mSurfaceHeight);
Vishnu Naire86bd982018-11-28 13:23:17 -0800598 // Set a window crop when creating the surface or changing its size to
599 // crop the buffer to the surface size since the buffer producer may
600 // use SCALING_MODE_SCALE and submit a larger size than the surface
601 // size.
602 mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800603 }
youngmin0822.lee4dde7d12018-07-09 14:25:32 +0900604 if (sizeChanged && !creating) {
Vishnu Naire86bd982018-11-28 13:23:17 -0800605 mSurfaceControl.setBufferSize(mSurfaceWidth, mSurfaceHeight);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800606 }
607 } finally {
608 SurfaceControl.closeTransaction();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700609 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800610
Robert Carrd5c7dd62017-03-08 10:39:30 -0800611 if (sizeChanged || creating) {
612 redrawNeeded = true;
613 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800614
Dianne Hackborn726426e2010-03-31 22:04:36 -0700615 mSurfaceFrame.left = 0;
616 mSurfaceFrame.top = 0;
617 if (mTranslator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800618 mSurfaceFrame.right = mSurfaceWidth;
619 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700620 } else {
621 float appInvertedScale = mTranslator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800622 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
623 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700624 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700625
Dianne Hackborn726426e2010-03-31 22:04:36 -0700626 final int surfaceWidth = mSurfaceFrame.right;
627 final int surfaceHeight = mSurfaceFrame.bottom;
628 realSizeChanged = mLastSurfaceWidth != surfaceWidth
629 || mLastSurfaceHeight != surfaceHeight;
630 mLastSurfaceWidth = surfaceWidth;
631 mLastSurfaceHeight = surfaceHeight;
632 } finally {
633 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700634 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700635
636 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800637 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700638
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800639 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700640
Robert Carrd5c7dd62017-03-08 10:39:30 -0800641 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800642 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
643 mSurfaceCreated = false;
644 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700645 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
646 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800647 callbacks = getSurfaceCallbacks();
648 for (SurfaceHolder.Callback c : callbacks) {
649 c.surfaceDestroyed(mSurfaceHolder);
650 }
Robert Carr387838b2016-09-07 14:12:44 -0700651 // Since Android N the same surface may be reused and given to us
652 // again by the system server at a later point. However
653 // as we didn't do this in previous releases, clients weren't
654 // necessarily required to clean up properly in
655 // surfaceDestroyed. This leads to problems for example when
656 // clients don't destroy their EGL context, and try
657 // and create a new one on the same surface following reuse.
658 // Since there is no valid use of the surface in-between
659 // surfaceDestroyed and surfaceCreated, we force a disconnect,
660 // so the next connect will always work if we end up reusing
661 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700662 if (mSurface.isValid()) {
663 mSurface.forceScopedDisconnect();
664 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700665 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800666 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700667
Robert Carrd5c7dd62017-03-08 10:39:30 -0800668 if (creating) {
669 mSurface.copyFrom(mSurfaceControl);
670 }
671
Bryce Lee453fc362017-06-20 10:47:55 -0700672 if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
Bryce Lee02949f12017-06-16 07:20:34 -0700673 < Build.VERSION_CODES.O) {
674 // Some legacy applications use the underlying native {@link Surface} object
675 // as a key to whether anything has changed. In these cases, updates to the
676 // existing {@link Surface} will be ignored when the size changes.
677 // Therefore, we must explicitly recreate the {@link Surface} in these
678 // cases.
679 mSurface.createFrom(mSurfaceControl);
680 }
681
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200682 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800683 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
684 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700685 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700686 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
687 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800688 if (callbacks == null) {
689 callbacks = getSurfaceCallbacks();
690 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700691 for (SurfaceHolder.Callback c : callbacks) {
692 c.surfaceCreated(mSurfaceHolder);
693 }
694 }
695 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700696 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700697 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
698 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800699 + " w=" + myWidth + " h=" + myHeight);
700 if (callbacks == null) {
701 callbacks = getSurfaceCallbacks();
702 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700703 for (SurfaceHolder.Callback c : callbacks) {
704 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
705 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700706 }
707 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -0700708 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
709 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800710 if (callbacks == null) {
711 callbacks = getSurfaceCallbacks();
712 }
Robert Carr8508bb22017-03-27 15:46:27 -0700713
714 mPendingReportDraws++;
715 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -0800716 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -0800717 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -0800718 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700719 }
720 }
721 } finally {
722 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800723 if (mSurfaceControl != null && !mSurfaceCreated) {
Robert Carrde844432017-05-04 13:45:45 -0700724 mSurface.release();
Robert Carr29daa922018-04-27 11:56:48 -0700725
726 mSurfaceControl.destroy();
727 mSurfaceControl = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800728 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700729 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800730 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700731 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700732 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800733 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -0800734 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
735 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
736 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -0700737 } else {
738 // Calculate the window position in case RT loses the window
739 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -0800740 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -0800741 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
742 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800743 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
744 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -0800745 if (positionChanged || layoutSizeChanged) { // Only the position has changed
746 mWindowSpaceLeft = mLocation[0];
747 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800748 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -0800749 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800750 mLocation[0] = getWidth();
751 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -0800752
Robert Carrd5c7dd62017-03-08 10:39:30 -0800753 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
Robert Carrc90e5f82017-07-18 13:10:02 -0700754 mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
John Reckf057fb52016-04-15 13:46:29 -0700755
756 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800757 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -0700758 }
759
Robert Carr3651ab82017-04-25 12:05:34 -0700760 if (mSurfaceControl == null) {
761 return;
762 }
763
Bryce Lee16e50892017-04-11 01:59:37 +0000764 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
John Reckf23a1b82016-06-22 14:23:31 -0700765 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800766 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
John Reckf23a1b82016-06-22 14:23:31 -0700767 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800768 mScreenRect.left, mScreenRect.top,
769 mScreenRect.right, mScreenRect.bottom));
770 setParentSpaceRectangle(mScreenRect, -1);
771 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700772 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -0700773 }
John Reckf6481082016-02-02 15:18:23 -0800774 }
Rob Carr64e516f2015-10-29 00:20:45 +0000775 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700776 }
777 }
778
Robert Carrd5c7dd62017-03-08 10:39:30 -0800779 private void onDrawFinished() {
780 if (DEBUG) {
781 Log.i(TAG, System.identityHashCode(this) + " "
782 + "finishedDrawing");
783 }
Robert Carr3bc95b52017-03-20 21:57:23 -0700784
785 if (mDeferredDestroySurfaceControl != null) {
786 mDeferredDestroySurfaceControl.destroy();
787 mDeferredDestroySurfaceControl = null;
788 }
789
John Reck79925002017-05-26 13:57:14 -0700790 runOnUiThread(() -> {
Robert Carrb53670a2017-05-25 18:20:49 -0700791 performDrawFinished();
John Reck79925002017-05-26 13:57:14 -0700792 });
Robert Carrd5c7dd62017-03-08 10:39:30 -0800793 }
794
Robert Carr27a800a2018-03-16 13:33:45 -0700795 /**
796 * A place to over-ride for applying child-surface transactions.
797 * These can be synchronized with the viewroot surface using deferTransaction.
798 *
799 * Called from RenderWorker while UI thread is paused.
800 * @hide
801 */
802 protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
803 Surface viewRootSurface, long nextViewRootFrameNumber) {
804 }
805
Robert Carr386fd702018-03-23 13:46:39 -0700806 private void applySurfaceTransforms(SurfaceControl surface, Rect position, long frameNumber) {
Robert Carr27a800a2018-03-16 13:33:45 -0700807 if (frameNumber > 0) {
Robert Carr386fd702018-03-23 13:46:39 -0700808 final ViewRootImpl viewRoot = getViewRootImpl();
809
810 mRtTransaction.deferTransactionUntilSurface(surface, viewRoot.mSurface,
Robert Carr27a800a2018-03-16 13:33:45 -0700811 frameNumber);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800812 }
Robert Carr386fd702018-03-23 13:46:39 -0700813
814 mRtTransaction.setPosition(surface, position.left, position.top);
815 mRtTransaction.setMatrix(surface,
Robert Carr27a800a2018-03-16 13:33:45 -0700816 position.width() / (float) mSurfaceWidth,
817 0.0f, 0.0f,
818 position.height() / (float) mSurfaceHeight);
Robert Carr386fd702018-03-23 13:46:39 -0700819 }
820
821 private void setParentSpaceRectangle(Rect position, long frameNumber) {
822 final ViewRootImpl viewRoot = getViewRootImpl();
823
824 applySurfaceTransforms(mSurfaceControl, position, frameNumber);
825 applySurfaceTransforms(mSurfaceControl.mBackgroundControl, position, frameNumber);
Robert Carr27a800a2018-03-16 13:33:45 -0700826
827 applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface,
828 frameNumber);
829
830 mRtTransaction.apply();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800831 }
832
John Reckf6481082016-02-02 15:18:23 -0800833 private Rect mRTLastReportedPosition = new Rect();
834
John Reck6b164402018-09-24 15:25:42 -0700835 private RenderNode.PositionUpdateListener mPositionListener =
836 new RenderNode.PositionUpdateListener() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800837
John Reck6b164402018-09-24 15:25:42 -0700838 @Override
839 public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
840 if (mSurfaceControl == null) {
841 return;
John Reckf6481082016-02-02 15:18:23 -0800842 }
John Reckf6481082016-02-02 15:18:23 -0800843
John Reck6b164402018-09-24 15:25:42 -0700844 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
845 // its 2nd frame if RenderThread is running slowly could potentially see
846 // this as false, enter the branch, get pre-empted, then this comes along
847 // and reports a new position, then the UI thread resumes and reports
848 // its position. This could therefore be de-sync'd in that interval, but
849 // the synchronization would violate the rule that RT must never block
850 // on the UI thread which would open up potential deadlocks. The risk of
851 // a single-frame desync is therefore preferable for now.
852 mRtHandlingPositionUpdates = true;
853 if (mRTLastReportedPosition.left == left
854 && mRTLastReportedPosition.top == top
855 && mRTLastReportedPosition.right == right
856 && mRTLastReportedPosition.bottom == bottom) {
857 return;
858 }
859 try {
860 if (DEBUG) {
861 Log.d(TAG, String.format(
862 "%d updateSurfacePosition RenderWorker, frameNr = %d, "
863 + "postion = [%d, %d, %d, %d]",
864 System.identityHashCode(this), frameNumber,
865 left, top, right, bottom));
866 }
867 mRTLastReportedPosition.set(left, top, right, bottom);
868 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
869 // Now overwrite mRTLastReportedPosition with our values
870 } catch (Exception ex) {
871 Log.e(TAG, "Exception from repositionChild", ex);
872 }
John Reckaa6e84f2016-06-16 15:36:13 -0700873 }
Robert Carrad3a4932017-06-20 14:55:21 -0700874
John Reck6b164402018-09-24 15:25:42 -0700875 @Override
876 public void positionLost(long frameNumber) {
877 if (DEBUG) {
878 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
879 System.identityHashCode(this), frameNumber));
880 }
881 mRTLastReportedPosition.setEmpty();
882
883 if (mSurfaceControl == null) {
884 return;
885 }
886 if (mRtHandlingPositionUpdates) {
887 mRtHandlingPositionUpdates = false;
888 // This callback will happen while the UI thread is blocked, so we can
889 // safely access other member variables at this time.
890 // So do what the UI thread would have done if RT wasn't handling position
891 // updates.
892 if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
893 try {
894 if (DEBUG) {
895 Log.d(TAG, String.format("%d updateSurfacePosition, "
896 + "postion = [%d, %d, %d, %d]",
897 System.identityHashCode(this),
898 mScreenRect.left, mScreenRect.top,
899 mScreenRect.right, mScreenRect.bottom));
900 }
901 setParentSpaceRectangle(mScreenRect, frameNumber);
902 } catch (Exception ex) {
903 Log.e(TAG, "Exception configuring surface", ex);
904 }
John Reckf23a1b82016-06-22 14:23:31 -0700905 }
906 }
John Reckf23a1b82016-06-22 14:23:31 -0700907 }
John Reck6b164402018-09-24 15:25:42 -0700908 };
John Reckaa6e84f2016-06-16 15:36:13 -0700909
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800910 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
911 SurfaceHolder.Callback callbacks[];
912 synchronized (mCallbacks) {
913 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
914 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700915 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800916 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700917 }
918
John Reck79925002017-05-26 13:57:14 -0700919 private void runOnUiThread(Runnable runnable) {
920 Handler handler = getHandler();
921 if (handler != null && handler.getLooper() != Looper.myLooper()) {
922 handler.post(runnable);
923 } else {
924 runnable.run();
925 }
926 }
927
Yohei Yukawa3b5011a2017-03-16 15:34:12 -0700928 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -0400929 * Check to see if the surface has fixed size dimensions or if the surface's
930 * dimensions are dimensions are dependent on its current layout.
931 *
932 * @return true if the surface has dimensions that are fixed in size
933 * @hide
934 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100935 @UnsupportedAppUsage
Derek Sollenberger7179b812010-03-22 13:41:20 -0400936 public boolean isFixedSize() {
937 return (mRequestedWidth != -1 || mRequestedHeight != -1);
938 }
939
Robert Carrd5c7dd62017-03-08 10:39:30 -0800940 private boolean isAboveParent() {
941 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700942 }
943
Andrii Kuliancf8f6832018-01-23 19:43:30 -0800944 /**
945 * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
946 * and size of the content hasn't updated yet. This color will fill the expanded area when the
947 * view becomes larger.
948 * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
949 * @hide
950 */
951 public void setResizeBackgroundColor(int bgColor) {
952 mSurfaceControl.setBackgroundColor(bgColor);
953 }
954
Mathew Inwooda570dee2018-08-17 14:56:00 +0100955 @UnsupportedAppUsage
Igor Murashkina86ab6402013-08-30 12:58:36 -0700956 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700957 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -0700958
959 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700960 public boolean isCreating() {
961 return mIsCreating;
962 }
963
Igor Murashkina86ab6402013-08-30 12:58:36 -0700964 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700965 public void addCallback(Callback callback) {
966 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700967 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700968 // have only a couple callbacks, so it doesn't matter.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700969 if (mCallbacks.contains(callback) == false) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700970 mCallbacks.add(callback);
971 }
972 }
973 }
974
Igor Murashkina86ab6402013-08-30 12:58:36 -0700975 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700976 public void removeCallback(Callback callback) {
977 synchronized (mCallbacks) {
978 mCallbacks.remove(callback);
979 }
980 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700981
982 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700983 public void setFixedSize(int width, int height) {
984 if (mRequestedWidth != width || mRequestedHeight != height) {
985 mRequestedWidth = width;
986 mRequestedHeight = height;
987 requestLayout();
988 }
989 }
990
Igor Murashkina86ab6402013-08-30 12:58:36 -0700991 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700992 public void setSizeFromLayout() {
993 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
994 mRequestedWidth = mRequestedHeight = -1;
995 requestLayout();
996 }
997 }
998
Igor Murashkina86ab6402013-08-30 12:58:36 -0700999 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001000 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -07001001 // for backward compatibility reason, OPAQUE always
1002 // means 565 for SurfaceView
1003 if (format == PixelFormat.OPAQUE)
1004 format = PixelFormat.RGB_565;
1005
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001006 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001007 if (mSurfaceControl != null) {
1008 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001009 }
1010 }
1011
Mathias Agopiand2112302010-12-07 19:38:17 -08001012 /**
1013 * @deprecated setType is now ignored.
1014 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001015 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -08001016 @Deprecated
1017 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001018
Igor Murashkina86ab6402013-08-30 12:58:36 -07001019 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001020 public void setKeepScreenOn(boolean screenOn) {
John Reck79925002017-05-26 13:57:14 -07001021 runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001022 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001023
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001024 /**
1025 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1026 *
1027 * After drawing into the provided {@link Canvas}, the caller must
1028 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1029 *
1030 * The caller must redraw the entire surface.
1031 * @return A canvas for drawing into the surface.
1032 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001033 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001034 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -07001035 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001036 }
1037
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001038 /**
1039 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1040 *
1041 * After drawing into the provided {@link Canvas}, the caller must
1042 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1043 *
1044 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1045 * to redraw. This function may choose to expand the dirty rectangle if for example
1046 * the surface has been resized or if the previous contents of the surface were
1047 * not available. The caller must redraw the entire dirty region as represented
1048 * by the contents of the inOutDirty rectangle upon return from this function.
1049 * The caller may also pass <code>null</code> instead, in the case where the
1050 * entire surface should be redrawn.
1051 * @return A canvas for drawing into the surface.
1052 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001053 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001054 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -07001055 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001056 }
1057
John Reck6bc70142016-10-26 16:49:17 -07001058 @Override
1059 public Canvas lockHardwareCanvas() {
1060 return internalLockCanvas(null, true);
1061 }
1062
1063 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001064 mSurfaceLock.lock();
1065
John Reckaa6e84f2016-06-16 15:36:13 -07001066 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001067 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001068
1069 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001070 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001071 try {
John Reck6bc70142016-10-26 16:49:17 -07001072 if (hardware) {
1073 c = mSurface.lockHardwareCanvas();
1074 } else {
1075 c = mSurface.lockCanvas(dirty);
1076 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001077 } catch (Exception e) {
1078 Log.e(LOG_TAG, "Exception locking surface", e);
1079 }
1080 }
1081
John Reckaa6e84f2016-06-16 15:36:13 -07001082 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001083 if (c != null) {
1084 mLastLockTime = SystemClock.uptimeMillis();
1085 return c;
1086 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001087
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001088 // If the Surface is not ready to be drawn, then return null,
1089 // but throttle calls to this function so it isn't called more
1090 // than every 100ms.
1091 long now = SystemClock.uptimeMillis();
1092 long nextTime = mLastLockTime + 100;
1093 if (nextTime > now) {
1094 try {
1095 Thread.sleep(nextTime-now);
1096 } catch (InterruptedException e) {
1097 }
1098 now = SystemClock.uptimeMillis();
1099 }
1100 mLastLockTime = now;
1101 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001102
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001103 return null;
1104 }
1105
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001106 /**
1107 * Posts the new contents of the {@link Canvas} to the surface and
1108 * releases the {@link Canvas}.
1109 *
1110 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1111 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001112 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001113 public void unlockCanvasAndPost(Canvas canvas) {
1114 mSurface.unlockCanvasAndPost(canvas);
1115 mSurfaceLock.unlock();
1116 }
1117
Igor Murashkina86ab6402013-08-30 12:58:36 -07001118 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001119 public Surface getSurface() {
1120 return mSurface;
1121 }
1122
Igor Murashkina86ab6402013-08-30 12:58:36 -07001123 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001124 public Rect getSurfaceFrame() {
1125 return mSurfaceFrame;
1126 }
1127 };
Robert Carr55235552017-06-02 14:21:03 -07001128
chaviwff2e7d82018-11-02 11:11:27 -07001129 /**
1130 * @hide
1131 */
1132 public SurfaceControl getSurfaceControl() {
1133 return mSurfaceControl;
1134 }
1135
Robert Carr55235552017-06-02 14:21:03 -07001136 class SurfaceControlWithBackground extends SurfaceControl {
Robert Carr386fd702018-03-23 13:46:39 -07001137 SurfaceControl mBackgroundControl;
Robert Carr55235552017-06-02 14:21:03 -07001138 private boolean mOpaque = true;
1139 public boolean mVisible = false;
1140
Robert Carre625fcf2017-09-01 12:36:28 -07001141 public SurfaceControlWithBackground(String name, boolean opaque, SurfaceControl.Builder b)
Robert Carr55235552017-06-02 14:21:03 -07001142 throws Exception {
Robert Carre625fcf2017-09-01 12:36:28 -07001143 super(b.setName(name).build());
1144
1145 mBackgroundControl = b.setName("Background for -" + name)
1146 .setFormat(OPAQUE)
Vishnu Naire86bd982018-11-28 13:23:17 -08001147 // Unset the buffer size of the background color layer.
1148 .setBufferSize(0, 0)
Robert Carre625fcf2017-09-01 12:36:28 -07001149 .setColorLayer(true)
1150 .build();
1151 mOpaque = opaque;
Robert Carr55235552017-06-02 14:21:03 -07001152 }
1153
1154 @Override
1155 public void setAlpha(float alpha) {
1156 super.setAlpha(alpha);
1157 mBackgroundControl.setAlpha(alpha);
1158 }
1159
1160 @Override
1161 public void setLayer(int zorder) {
1162 super.setLayer(zorder);
1163 // -3 is below all other child layers as SurfaceView never goes below -2
1164 mBackgroundControl.setLayer(-3);
1165 }
1166
1167 @Override
1168 public void setPosition(float x, float y) {
1169 super.setPosition(x, y);
1170 mBackgroundControl.setPosition(x, y);
1171 }
1172
1173 @Override
Vishnu Naire86bd982018-11-28 13:23:17 -08001174 public void setBufferSize(int w, int h) {
1175 super.setBufferSize(w, h);
1176 // The background surface is a color layer so we do not set a size.
Robert Carr55235552017-06-02 14:21:03 -07001177 }
1178
1179 @Override
1180 public void setWindowCrop(Rect crop) {
1181 super.setWindowCrop(crop);
1182 mBackgroundControl.setWindowCrop(crop);
1183 }
1184
1185 @Override
Vishnu Naird454442d2018-11-13 13:51:01 -08001186 public void setWindowCrop(int width, int height) {
1187 super.setWindowCrop(width, height);
1188 mBackgroundControl.setWindowCrop(width, height);
1189 }
1190
1191 @Override
Robert Carr55235552017-06-02 14:21:03 -07001192 public void setLayerStack(int layerStack) {
1193 super.setLayerStack(layerStack);
1194 mBackgroundControl.setLayerStack(layerStack);
1195 }
1196
1197 @Override
1198 public void setOpaque(boolean isOpaque) {
1199 super.setOpaque(isOpaque);
1200 mOpaque = isOpaque;
1201 updateBackgroundVisibility();
1202 }
1203
1204 @Override
1205 public void setSecure(boolean isSecure) {
1206 super.setSecure(isSecure);
1207 }
1208
1209 @Override
1210 public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
1211 super.setMatrix(dsdx, dtdx, dsdy, dtdy);
1212 mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
1213 }
1214
1215 @Override
1216 public void hide() {
1217 super.hide();
1218 mVisible = false;
1219 updateBackgroundVisibility();
1220 }
1221
1222 @Override
1223 public void show() {
1224 super.show();
1225 mVisible = true;
1226 updateBackgroundVisibility();
1227 }
1228
1229 @Override
1230 public void destroy() {
1231 super.destroy();
1232 mBackgroundControl.destroy();
1233 }
1234
1235 @Override
1236 public void release() {
1237 super.release();
1238 mBackgroundControl.release();
1239 }
1240
1241 @Override
1242 public void setTransparentRegionHint(Region region) {
1243 super.setTransparentRegionHint(region);
1244 mBackgroundControl.setTransparentRegionHint(region);
1245 }
1246
1247 @Override
1248 public void deferTransactionUntil(IBinder handle, long frame) {
1249 super.deferTransactionUntil(handle, frame);
1250 mBackgroundControl.deferTransactionUntil(handle, frame);
1251 }
1252
Robert Carr552da0e2017-06-12 11:43:51 -07001253 @Override
1254 public void deferTransactionUntil(Surface barrier, long frame) {
1255 super.deferTransactionUntil(barrier, frame);
1256 mBackgroundControl.deferTransactionUntil(barrier, frame);
1257 }
1258
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001259 /** Set the color to fill the background with. */
1260 private void setBackgroundColor(int bgColor) {
1261 final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
1262 Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
1263
1264 SurfaceControl.openTransaction();
1265 try {
1266 mBackgroundControl.setColor(colorComponents);
1267 } finally {
1268 SurfaceControl.closeTransaction();
1269 }
1270 }
1271
Robert Carr55235552017-06-02 14:21:03 -07001272 void updateBackgroundVisibility() {
1273 if (mOpaque && mVisible) {
1274 mBackgroundControl.show();
1275 } else {
1276 mBackgroundControl.hide();
1277 }
1278 }
1279 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001280}