blob: 67f9399e678ae78e6ce2016eaa6f7a7acecb32a6 [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 Inwooda570dee2018-08-17 14:56:00 +0100113 @UnsupportedAppUsage
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 Inwooda570dee2018-08-17 14:56:00 +0100132 @UnsupportedAppUsage
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 Inwooda570dee2018-08-17 14:56:00 +0100162 @UnsupportedAppUsage
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700163 int mRequestedWidth = -1;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100164 @UnsupportedAppUsage
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 Inwooda570dee2018-08-17 14:56:00 +0100175 @UnsupportedAppUsage
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 Inwooda570dee2018-08-17 14:56:00 +0100185 @UnsupportedAppUsage
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)
560 .setSize(mSurfaceWidth, mSurfaceHeight)
561 .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);
598 }
youngmin0822.lee4dde7d12018-07-09 14:25:32 +0900599 if (sizeChanged && !creating) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800600 mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
601 }
602 } finally {
603 SurfaceControl.closeTransaction();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700604 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800605
Robert Carrd5c7dd62017-03-08 10:39:30 -0800606 if (sizeChanged || creating) {
607 redrawNeeded = true;
608 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800609
Dianne Hackborn726426e2010-03-31 22:04:36 -0700610 mSurfaceFrame.left = 0;
611 mSurfaceFrame.top = 0;
612 if (mTranslator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800613 mSurfaceFrame.right = mSurfaceWidth;
614 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700615 } else {
616 float appInvertedScale = mTranslator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800617 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
618 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700619 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700620
Dianne Hackborn726426e2010-03-31 22:04:36 -0700621 final int surfaceWidth = mSurfaceFrame.right;
622 final int surfaceHeight = mSurfaceFrame.bottom;
623 realSizeChanged = mLastSurfaceWidth != surfaceWidth
624 || mLastSurfaceHeight != surfaceHeight;
625 mLastSurfaceWidth = surfaceWidth;
626 mLastSurfaceHeight = surfaceHeight;
627 } finally {
628 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700629 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700630
631 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800632 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700633
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800634 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700635
Robert Carrd5c7dd62017-03-08 10:39:30 -0800636 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800637 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
638 mSurfaceCreated = false;
639 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700640 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
641 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800642 callbacks = getSurfaceCallbacks();
643 for (SurfaceHolder.Callback c : callbacks) {
644 c.surfaceDestroyed(mSurfaceHolder);
645 }
Robert Carr387838b2016-09-07 14:12:44 -0700646 // Since Android N the same surface may be reused and given to us
647 // again by the system server at a later point. However
648 // as we didn't do this in previous releases, clients weren't
649 // necessarily required to clean up properly in
650 // surfaceDestroyed. This leads to problems for example when
651 // clients don't destroy their EGL context, and try
652 // and create a new one on the same surface following reuse.
653 // Since there is no valid use of the surface in-between
654 // surfaceDestroyed and surfaceCreated, we force a disconnect,
655 // so the next connect will always work if we end up reusing
656 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700657 if (mSurface.isValid()) {
658 mSurface.forceScopedDisconnect();
659 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700660 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800661 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700662
Robert Carrd5c7dd62017-03-08 10:39:30 -0800663 if (creating) {
664 mSurface.copyFrom(mSurfaceControl);
665 }
666
Bryce Lee453fc362017-06-20 10:47:55 -0700667 if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
Bryce Lee02949f12017-06-16 07:20:34 -0700668 < Build.VERSION_CODES.O) {
669 // Some legacy applications use the underlying native {@link Surface} object
670 // as a key to whether anything has changed. In these cases, updates to the
671 // existing {@link Surface} will be ignored when the size changes.
672 // Therefore, we must explicitly recreate the {@link Surface} in these
673 // cases.
674 mSurface.createFrom(mSurfaceControl);
675 }
676
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200677 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800678 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
679 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700680 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700681 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
682 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800683 if (callbacks == null) {
684 callbacks = getSurfaceCallbacks();
685 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700686 for (SurfaceHolder.Callback c : callbacks) {
687 c.surfaceCreated(mSurfaceHolder);
688 }
689 }
690 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700691 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700692 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
693 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800694 + " w=" + myWidth + " h=" + myHeight);
695 if (callbacks == null) {
696 callbacks = getSurfaceCallbacks();
697 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700698 for (SurfaceHolder.Callback c : callbacks) {
699 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
700 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700701 }
702 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -0700703 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
704 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800705 if (callbacks == null) {
706 callbacks = getSurfaceCallbacks();
707 }
Robert Carr8508bb22017-03-27 15:46:27 -0700708
709 mPendingReportDraws++;
710 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -0800711 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -0800712 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -0800713 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700714 }
715 }
716 } finally {
717 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800718 if (mSurfaceControl != null && !mSurfaceCreated) {
Robert Carrde844432017-05-04 13:45:45 -0700719 mSurface.release();
Robert Carr29daa922018-04-27 11:56:48 -0700720
721 mSurfaceControl.destroy();
722 mSurfaceControl = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800723 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700724 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800725 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700726 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700727 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800728 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -0800729 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
730 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
731 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -0700732 } else {
733 // Calculate the window position in case RT loses the window
734 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -0800735 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -0800736 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
737 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800738 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
739 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -0800740 if (positionChanged || layoutSizeChanged) { // Only the position has changed
741 mWindowSpaceLeft = mLocation[0];
742 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800743 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -0800744 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800745 mLocation[0] = getWidth();
746 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -0800747
Robert Carrd5c7dd62017-03-08 10:39:30 -0800748 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
Robert Carrc90e5f82017-07-18 13:10:02 -0700749 mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
John Reckf057fb52016-04-15 13:46:29 -0700750
751 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800752 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -0700753 }
754
Robert Carr3651ab82017-04-25 12:05:34 -0700755 if (mSurfaceControl == null) {
756 return;
757 }
758
Bryce Lee16e50892017-04-11 01:59:37 +0000759 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
John Reckf23a1b82016-06-22 14:23:31 -0700760 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800761 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
John Reckf23a1b82016-06-22 14:23:31 -0700762 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800763 mScreenRect.left, mScreenRect.top,
764 mScreenRect.right, mScreenRect.bottom));
765 setParentSpaceRectangle(mScreenRect, -1);
766 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700767 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -0700768 }
John Reckf6481082016-02-02 15:18:23 -0800769 }
Rob Carr64e516f2015-10-29 00:20:45 +0000770 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700771 }
772 }
773
Robert Carrd5c7dd62017-03-08 10:39:30 -0800774 private void onDrawFinished() {
775 if (DEBUG) {
776 Log.i(TAG, System.identityHashCode(this) + " "
777 + "finishedDrawing");
778 }
Robert Carr3bc95b52017-03-20 21:57:23 -0700779
780 if (mDeferredDestroySurfaceControl != null) {
781 mDeferredDestroySurfaceControl.destroy();
782 mDeferredDestroySurfaceControl = null;
783 }
784
John Reck79925002017-05-26 13:57:14 -0700785 runOnUiThread(() -> {
Robert Carrb53670a2017-05-25 18:20:49 -0700786 performDrawFinished();
John Reck79925002017-05-26 13:57:14 -0700787 });
Robert Carrd5c7dd62017-03-08 10:39:30 -0800788 }
789
Robert Carr27a800a2018-03-16 13:33:45 -0700790 /**
791 * A place to over-ride for applying child-surface transactions.
792 * These can be synchronized with the viewroot surface using deferTransaction.
793 *
794 * Called from RenderWorker while UI thread is paused.
795 * @hide
796 */
797 protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t,
798 Surface viewRootSurface, long nextViewRootFrameNumber) {
799 }
800
Robert Carr386fd702018-03-23 13:46:39 -0700801 private void applySurfaceTransforms(SurfaceControl surface, Rect position, long frameNumber) {
Robert Carr27a800a2018-03-16 13:33:45 -0700802 if (frameNumber > 0) {
Robert Carr386fd702018-03-23 13:46:39 -0700803 final ViewRootImpl viewRoot = getViewRootImpl();
804
805 mRtTransaction.deferTransactionUntilSurface(surface, viewRoot.mSurface,
Robert Carr27a800a2018-03-16 13:33:45 -0700806 frameNumber);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800807 }
Robert Carr386fd702018-03-23 13:46:39 -0700808
809 mRtTransaction.setPosition(surface, position.left, position.top);
810 mRtTransaction.setMatrix(surface,
Robert Carr27a800a2018-03-16 13:33:45 -0700811 position.width() / (float) mSurfaceWidth,
812 0.0f, 0.0f,
813 position.height() / (float) mSurfaceHeight);
Robert Carr386fd702018-03-23 13:46:39 -0700814 }
815
816 private void setParentSpaceRectangle(Rect position, long frameNumber) {
817 final ViewRootImpl viewRoot = getViewRootImpl();
818
819 applySurfaceTransforms(mSurfaceControl, position, frameNumber);
820 applySurfaceTransforms(mSurfaceControl.mBackgroundControl, position, frameNumber);
Robert Carr27a800a2018-03-16 13:33:45 -0700821
822 applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface,
823 frameNumber);
824
825 mRtTransaction.apply();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800826 }
827
John Reckf6481082016-02-02 15:18:23 -0800828 private Rect mRTLastReportedPosition = new Rect();
829
John Reck6b164402018-09-24 15:25:42 -0700830 private RenderNode.PositionUpdateListener mPositionListener =
831 new RenderNode.PositionUpdateListener() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800832
John Reck6b164402018-09-24 15:25:42 -0700833 @Override
834 public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
835 if (mSurfaceControl == null) {
836 return;
John Reckf6481082016-02-02 15:18:23 -0800837 }
John Reckf6481082016-02-02 15:18:23 -0800838
John Reck6b164402018-09-24 15:25:42 -0700839 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
840 // its 2nd frame if RenderThread is running slowly could potentially see
841 // this as false, enter the branch, get pre-empted, then this comes along
842 // and reports a new position, then the UI thread resumes and reports
843 // its position. This could therefore be de-sync'd in that interval, but
844 // the synchronization would violate the rule that RT must never block
845 // on the UI thread which would open up potential deadlocks. The risk of
846 // a single-frame desync is therefore preferable for now.
847 mRtHandlingPositionUpdates = true;
848 if (mRTLastReportedPosition.left == left
849 && mRTLastReportedPosition.top == top
850 && mRTLastReportedPosition.right == right
851 && mRTLastReportedPosition.bottom == bottom) {
852 return;
853 }
854 try {
855 if (DEBUG) {
856 Log.d(TAG, String.format(
857 "%d updateSurfacePosition RenderWorker, frameNr = %d, "
858 + "postion = [%d, %d, %d, %d]",
859 System.identityHashCode(this), frameNumber,
860 left, top, right, bottom));
861 }
862 mRTLastReportedPosition.set(left, top, right, bottom);
863 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
864 // Now overwrite mRTLastReportedPosition with our values
865 } catch (Exception ex) {
866 Log.e(TAG, "Exception from repositionChild", ex);
867 }
John Reckaa6e84f2016-06-16 15:36:13 -0700868 }
Robert Carrad3a4932017-06-20 14:55:21 -0700869
John Reck6b164402018-09-24 15:25:42 -0700870 @Override
871 public void positionLost(long frameNumber) {
872 if (DEBUG) {
873 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
874 System.identityHashCode(this), frameNumber));
875 }
876 mRTLastReportedPosition.setEmpty();
877
878 if (mSurfaceControl == null) {
879 return;
880 }
881 if (mRtHandlingPositionUpdates) {
882 mRtHandlingPositionUpdates = false;
883 // This callback will happen while the UI thread is blocked, so we can
884 // safely access other member variables at this time.
885 // So do what the UI thread would have done if RT wasn't handling position
886 // updates.
887 if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
888 try {
889 if (DEBUG) {
890 Log.d(TAG, String.format("%d updateSurfacePosition, "
891 + "postion = [%d, %d, %d, %d]",
892 System.identityHashCode(this),
893 mScreenRect.left, mScreenRect.top,
894 mScreenRect.right, mScreenRect.bottom));
895 }
896 setParentSpaceRectangle(mScreenRect, frameNumber);
897 } catch (Exception ex) {
898 Log.e(TAG, "Exception configuring surface", ex);
899 }
John Reckf23a1b82016-06-22 14:23:31 -0700900 }
901 }
John Reckf23a1b82016-06-22 14:23:31 -0700902 }
John Reck6b164402018-09-24 15:25:42 -0700903 };
John Reckaa6e84f2016-06-16 15:36:13 -0700904
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800905 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
906 SurfaceHolder.Callback callbacks[];
907 synchronized (mCallbacks) {
908 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
909 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700910 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800911 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700912 }
913
John Reck79925002017-05-26 13:57:14 -0700914 private void runOnUiThread(Runnable runnable) {
915 Handler handler = getHandler();
916 if (handler != null && handler.getLooper() != Looper.myLooper()) {
917 handler.post(runnable);
918 } else {
919 runnable.run();
920 }
921 }
922
Yohei Yukawa3b5011a2017-03-16 15:34:12 -0700923 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -0400924 * Check to see if the surface has fixed size dimensions or if the surface's
925 * dimensions are dimensions are dependent on its current layout.
926 *
927 * @return true if the surface has dimensions that are fixed in size
928 * @hide
929 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100930 @UnsupportedAppUsage
Derek Sollenberger7179b812010-03-22 13:41:20 -0400931 public boolean isFixedSize() {
932 return (mRequestedWidth != -1 || mRequestedHeight != -1);
933 }
934
Robert Carrd5c7dd62017-03-08 10:39:30 -0800935 private boolean isAboveParent() {
936 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700937 }
938
Andrii Kuliancf8f6832018-01-23 19:43:30 -0800939 /**
940 * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
941 * and size of the content hasn't updated yet. This color will fill the expanded area when the
942 * view becomes larger.
943 * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
944 * @hide
945 */
946 public void setResizeBackgroundColor(int bgColor) {
947 mSurfaceControl.setBackgroundColor(bgColor);
948 }
949
Mathew Inwooda570dee2018-08-17 14:56:00 +0100950 @UnsupportedAppUsage
Igor Murashkina86ab6402013-08-30 12:58:36 -0700951 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700952 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -0700953
954 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700955 public boolean isCreating() {
956 return mIsCreating;
957 }
958
Igor Murashkina86ab6402013-08-30 12:58:36 -0700959 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700960 public void addCallback(Callback callback) {
961 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700962 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700963 // have only a couple callbacks, so it doesn't matter.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700964 if (mCallbacks.contains(callback) == false) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700965 mCallbacks.add(callback);
966 }
967 }
968 }
969
Igor Murashkina86ab6402013-08-30 12:58:36 -0700970 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700971 public void removeCallback(Callback callback) {
972 synchronized (mCallbacks) {
973 mCallbacks.remove(callback);
974 }
975 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700976
977 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700978 public void setFixedSize(int width, int height) {
979 if (mRequestedWidth != width || mRequestedHeight != height) {
980 mRequestedWidth = width;
981 mRequestedHeight = height;
982 requestLayout();
983 }
984 }
985
Igor Murashkina86ab6402013-08-30 12:58:36 -0700986 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700987 public void setSizeFromLayout() {
988 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
989 mRequestedWidth = mRequestedHeight = -1;
990 requestLayout();
991 }
992 }
993
Igor Murashkina86ab6402013-08-30 12:58:36 -0700994 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700995 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700996 // for backward compatibility reason, OPAQUE always
997 // means 565 for SurfaceView
998 if (format == PixelFormat.OPAQUE)
999 format = PixelFormat.RGB_565;
1000
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001001 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001002 if (mSurfaceControl != null) {
1003 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001004 }
1005 }
1006
Mathias Agopiand2112302010-12-07 19:38:17 -08001007 /**
1008 * @deprecated setType is now ignored.
1009 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001010 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -08001011 @Deprecated
1012 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001013
Igor Murashkina86ab6402013-08-30 12:58:36 -07001014 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001015 public void setKeepScreenOn(boolean screenOn) {
John Reck79925002017-05-26 13:57:14 -07001016 runOnUiThread(() -> SurfaceView.this.setKeepScreenOn(screenOn));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001017 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001018
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001019 /**
1020 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1021 *
1022 * After drawing into the provided {@link Canvas}, the caller must
1023 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1024 *
1025 * The caller must redraw the entire surface.
1026 * @return A canvas for drawing into the surface.
1027 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001028 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001029 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -07001030 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001031 }
1032
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001033 /**
1034 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1035 *
1036 * After drawing into the provided {@link Canvas}, the caller must
1037 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1038 *
1039 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1040 * to redraw. This function may choose to expand the dirty rectangle if for example
1041 * the surface has been resized or if the previous contents of the surface were
1042 * not available. The caller must redraw the entire dirty region as represented
1043 * by the contents of the inOutDirty rectangle upon return from this function.
1044 * The caller may also pass <code>null</code> instead, in the case where the
1045 * entire surface should be redrawn.
1046 * @return A canvas for drawing into the surface.
1047 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001048 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001049 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -07001050 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001051 }
1052
John Reck6bc70142016-10-26 16:49:17 -07001053 @Override
1054 public Canvas lockHardwareCanvas() {
1055 return internalLockCanvas(null, true);
1056 }
1057
1058 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001059 mSurfaceLock.lock();
1060
John Reckaa6e84f2016-06-16 15:36:13 -07001061 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001062 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001063
1064 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001065 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001066 try {
John Reck6bc70142016-10-26 16:49:17 -07001067 if (hardware) {
1068 c = mSurface.lockHardwareCanvas();
1069 } else {
1070 c = mSurface.lockCanvas(dirty);
1071 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001072 } catch (Exception e) {
1073 Log.e(LOG_TAG, "Exception locking surface", e);
1074 }
1075 }
1076
John Reckaa6e84f2016-06-16 15:36:13 -07001077 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001078 if (c != null) {
1079 mLastLockTime = SystemClock.uptimeMillis();
1080 return c;
1081 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001082
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001083 // If the Surface is not ready to be drawn, then return null,
1084 // but throttle calls to this function so it isn't called more
1085 // than every 100ms.
1086 long now = SystemClock.uptimeMillis();
1087 long nextTime = mLastLockTime + 100;
1088 if (nextTime > now) {
1089 try {
1090 Thread.sleep(nextTime-now);
1091 } catch (InterruptedException e) {
1092 }
1093 now = SystemClock.uptimeMillis();
1094 }
1095 mLastLockTime = now;
1096 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001097
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001098 return null;
1099 }
1100
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001101 /**
1102 * Posts the new contents of the {@link Canvas} to the surface and
1103 * releases the {@link Canvas}.
1104 *
1105 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1106 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001107 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001108 public void unlockCanvasAndPost(Canvas canvas) {
1109 mSurface.unlockCanvasAndPost(canvas);
1110 mSurfaceLock.unlock();
1111 }
1112
Igor Murashkina86ab6402013-08-30 12:58:36 -07001113 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001114 public Surface getSurface() {
1115 return mSurface;
1116 }
1117
Igor Murashkina86ab6402013-08-30 12:58:36 -07001118 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001119 public Rect getSurfaceFrame() {
1120 return mSurfaceFrame;
1121 }
1122 };
Robert Carr55235552017-06-02 14:21:03 -07001123
1124 class SurfaceControlWithBackground extends SurfaceControl {
Robert Carr386fd702018-03-23 13:46:39 -07001125 SurfaceControl mBackgroundControl;
Robert Carr55235552017-06-02 14:21:03 -07001126 private boolean mOpaque = true;
1127 public boolean mVisible = false;
1128
Robert Carre625fcf2017-09-01 12:36:28 -07001129 public SurfaceControlWithBackground(String name, boolean opaque, SurfaceControl.Builder b)
Robert Carr55235552017-06-02 14:21:03 -07001130 throws Exception {
Robert Carre625fcf2017-09-01 12:36:28 -07001131 super(b.setName(name).build());
1132
1133 mBackgroundControl = b.setName("Background for -" + name)
1134 .setFormat(OPAQUE)
1135 .setColorLayer(true)
1136 .build();
1137 mOpaque = opaque;
Robert Carr55235552017-06-02 14:21:03 -07001138 }
1139
1140 @Override
1141 public void setAlpha(float alpha) {
1142 super.setAlpha(alpha);
1143 mBackgroundControl.setAlpha(alpha);
1144 }
1145
1146 @Override
1147 public void setLayer(int zorder) {
1148 super.setLayer(zorder);
1149 // -3 is below all other child layers as SurfaceView never goes below -2
1150 mBackgroundControl.setLayer(-3);
1151 }
1152
1153 @Override
1154 public void setPosition(float x, float y) {
1155 super.setPosition(x, y);
1156 mBackgroundControl.setPosition(x, y);
1157 }
1158
1159 @Override
1160 public void setSize(int w, int h) {
1161 super.setSize(w, h);
1162 mBackgroundControl.setSize(w, h);
1163 }
1164
1165 @Override
1166 public void setWindowCrop(Rect crop) {
1167 super.setWindowCrop(crop);
1168 mBackgroundControl.setWindowCrop(crop);
1169 }
1170
1171 @Override
Robert Carr55235552017-06-02 14:21:03 -07001172 public void setLayerStack(int layerStack) {
1173 super.setLayerStack(layerStack);
1174 mBackgroundControl.setLayerStack(layerStack);
1175 }
1176
1177 @Override
1178 public void setOpaque(boolean isOpaque) {
1179 super.setOpaque(isOpaque);
1180 mOpaque = isOpaque;
1181 updateBackgroundVisibility();
1182 }
1183
1184 @Override
1185 public void setSecure(boolean isSecure) {
1186 super.setSecure(isSecure);
1187 }
1188
1189 @Override
1190 public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
1191 super.setMatrix(dsdx, dtdx, dsdy, dtdy);
1192 mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
1193 }
1194
1195 @Override
1196 public void hide() {
1197 super.hide();
1198 mVisible = false;
1199 updateBackgroundVisibility();
1200 }
1201
1202 @Override
1203 public void show() {
1204 super.show();
1205 mVisible = true;
1206 updateBackgroundVisibility();
1207 }
1208
1209 @Override
1210 public void destroy() {
1211 super.destroy();
1212 mBackgroundControl.destroy();
1213 }
1214
1215 @Override
1216 public void release() {
1217 super.release();
1218 mBackgroundControl.release();
1219 }
1220
1221 @Override
1222 public void setTransparentRegionHint(Region region) {
1223 super.setTransparentRegionHint(region);
1224 mBackgroundControl.setTransparentRegionHint(region);
1225 }
1226
1227 @Override
1228 public void deferTransactionUntil(IBinder handle, long frame) {
1229 super.deferTransactionUntil(handle, frame);
1230 mBackgroundControl.deferTransactionUntil(handle, frame);
1231 }
1232
Robert Carr552da0e2017-06-12 11:43:51 -07001233 @Override
1234 public void deferTransactionUntil(Surface barrier, long frame) {
1235 super.deferTransactionUntil(barrier, frame);
1236 mBackgroundControl.deferTransactionUntil(barrier, frame);
1237 }
1238
Andrii Kuliancf8f6832018-01-23 19:43:30 -08001239 /** Set the color to fill the background with. */
1240 private void setBackgroundColor(int bgColor) {
1241 final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
1242 Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
1243
1244 SurfaceControl.openTransaction();
1245 try {
1246 mBackgroundControl.setColor(colorComponents);
1247 } finally {
1248 SurfaceControl.closeTransaction();
1249 }
1250 }
1251
Robert Carr55235552017-06-02 14:21:03 -07001252 void updateBackgroundVisibility() {
1253 if (mOpaque && mVisible) {
1254 mBackgroundControl.show();
1255 } else {
1256 mBackgroundControl.hide();
1257 }
1258 }
1259 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001260}