blob: f53975239e4afa3b360ce971013be142626734bd [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
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070019import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
Robert Carrd5c7dd62017-03-08 10:39:30 -080020import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070021import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
Robert Carrd5c7dd62017-03-08 10:39:30 -080022import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
23
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;
28import android.graphics.PixelFormat;
29import android.graphics.PorterDuff;
30import android.graphics.Rect;
31import android.graphics.Region;
Yohei Yukawa3b5011a2017-03-16 15:34:12 -070032import android.os.Build;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070033import android.os.Handler;
34import android.os.Message;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070035import android.os.SystemClock;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070036import android.util.AttributeSet;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070037import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070038
Robert Carr25cfa132016-11-16 13:24:09 -080039import com.android.internal.view.SurfaceCallbackHelper;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070040
Jon Larimer9bdf5762009-01-02 18:55:15 -050041import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070042import java.util.concurrent.locks.ReentrantLock;
43
44/**
45 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
46 * You can control the format of this surface and, if you like, its size; the
47 * SurfaceView takes care of placing the surface at the correct location on the
48 * screen
Igor Murashkina86ab6402013-08-30 12:58:36 -070049 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070050 * <p>The surface is Z ordered so that it is behind the window holding its
51 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070052 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070053 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070054 * 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 -070055 * buttons on top of the Surface, though note however that it can have an
56 * impact on performance since a full alpha-blended composite will be performed
57 * each time the Surface changes.
Igor Murashkina86ab6402013-08-30 12:58:36 -070058 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070059 * <p> The transparent region that makes the surface visible is based on the
60 * layout positions in the view hierarchy. If the post-layout transform
61 * properties are used to draw a sibling view on top of the SurfaceView, the
62 * view may not be properly composited with the surface.
63 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070064 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
65 * which can be retrieved by calling {@link #getHolder}.
Igor Murashkina86ab6402013-08-30 12:58:36 -070066 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070067 * <p>The Surface will be created for you while the SurfaceView's window is
68 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
69 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
70 * Surface is created and destroyed as the window is shown and hidden.
Igor Murashkina86ab6402013-08-30 12:58:36 -070071 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070072 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070073 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070074 * this way, you need to be aware of some threading semantics:
Igor Murashkina86ab6402013-08-30 12:58:36 -070075 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070076 * <ul>
77 * <li> All SurfaceView and
78 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
79 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070080 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070081 * state that is also touched by the drawing thread.
82 * <li> You must ensure that the drawing thread only touches the underlying
83 * Surface while it is valid -- between
84 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
85 * and
86 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
87 * </ul>
Chris Craik6ee192f2016-05-17 14:29:10 -070088 *
89 * <p class="note"><strong>Note:</strong> Starting in platform version
90 * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
91 * updated synchronously with other View rendering. This means that translating
92 * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
93 * artifacts may occur on previous versions of the platform when its window is
94 * positioned asynchronously.</p>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070095 */
Robert Carr414ebc62017-04-12 12:01:00 -070096public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback {
Robert Carrd5c7dd62017-03-08 10:39:30 -080097 private static final String TAG = "SurfaceView";
98 private static final boolean DEBUG = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070099
100 final ArrayList<SurfaceHolder.Callback> mCallbacks
101 = new ArrayList<SurfaceHolder.Callback>();
102
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800103 final int[] mLocation = new int[2];
Igor Murashkina86ab6402013-08-30 12:58:36 -0700104
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700105 final ReentrantLock mSurfaceLock = new ReentrantLock();
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800106 final Surface mSurface = new Surface(); // Current surface in use
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700107 boolean mDrawingStopped = true;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800108 // We use this to track if the application has produced a frame
109 // in to the Surface. Up until that point, we should be careful not to punch
110 // holes.
111 boolean mDrawFinished = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700112
Robert Carrd5c7dd62017-03-08 10:39:30 -0800113 final Rect mScreenRect = new Rect();
114 SurfaceSession mSurfaceSession;
115
116 SurfaceControl mSurfaceControl;
Robert Carr3bc95b52017-03-20 21:57:23 -0700117 // In the case of format changes we switch out the surface in-place
118 // we need to preserve the old one until the new one has drawn.
119 SurfaceControl mDeferredDestroySurfaceControl;
Robert Carr33879132016-09-06 14:41:40 -0700120 final Rect mTmpRect = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700121 final Configuration mConfiguration = new Configuration();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700122
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700123 static final int KEEP_SCREEN_ON_MSG = 1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800124 static final int DRAW_FINISHED_MSG = 2;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700125
Robert Carrd5c7dd62017-03-08 10:39:30 -0800126 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700127
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700128 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700129 private volatile boolean mRtHandlingPositionUpdates = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700130
131 final Handler mHandler = new Handler() {
132 @Override
133 public void handleMessage(Message msg) {
134 switch (msg.what) {
135 case KEEP_SCREEN_ON_MSG: {
136 setKeepScreenOn(msg.arg1 != 0);
137 } break;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800138 case DRAW_FINISHED_MSG: {
139 mDrawFinished = true;
Robert Carr8508bb22017-03-27 15:46:27 -0700140 if (mAttachedToWindow) {
141 notifyDrawFinished();
142 invalidate();
143 }
Dianne Hackborn726426e2010-03-31 22:04:36 -0700144 } break;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700145 }
146 }
147 };
Igor Murashkina86ab6402013-08-30 12:58:36 -0700148
John Reckf6481082016-02-02 15:18:23 -0800149 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700150 = new ViewTreeObserver.OnScrollChangedListener() {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700151 @Override
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700152 public void onScrollChanged() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800153 updateSurface();
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700154 }
155 };
Igor Murashkina86ab6402013-08-30 12:58:36 -0700156
John Reckf6481082016-02-02 15:18:23 -0800157 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
158 new ViewTreeObserver.OnPreDrawListener() {
159 @Override
160 public boolean onPreDraw() {
161 // reposition ourselves where the surface is
162 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800163 updateSurface();
John Reckf6481082016-02-02 15:18:23 -0800164 return true;
165 }
166 };
167
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700168 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700169 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800170 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700171 boolean mViewVisibility = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700172 boolean mWindowStopped = false;
173
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700174 int mRequestedWidth = -1;
175 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700176 /* Set SurfaceView's format to 565 by default to maintain backward
177 * compatibility with applications assuming this format.
178 */
179 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700180
181 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800182 boolean mSurfaceCreated = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700183 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700184
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700185 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800186 int mWindowSpaceLeft = -1;
187 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800188 int mSurfaceWidth = -1;
189 int mSurfaceHeight = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700190 int mFormat = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700191 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700192 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700193 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800194
Romain Guy01d5edc2011-01-28 11:28:53 -0800195 private boolean mGlobalListenersAdded;
Robert Carr8508bb22017-03-27 15:46:27 -0700196 private boolean mAttachedToWindow;
Romain Guyf2499fa2011-01-26 18:31:23 -0800197
Robert Carrd5c7dd62017-03-08 10:39:30 -0800198 private int mSurfaceFlags = SurfaceControl.HIDDEN;
199
Robert Carr8508bb22017-03-27 15:46:27 -0700200 private int mPendingReportDraws;
201
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700202 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400203 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700204 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700205
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700206 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400207 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700208 }
209
Alan Viverette617feb92013-09-09 18:09:13 -0700210 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400211 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700212 }
213
214 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
215 super(context, attrs, defStyleAttr, defStyleRes);
John Reck3acf03822016-11-02 11:14:47 -0700216 mRenderNode.requestPositionUpdates(this);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700217
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700218 setWillNotDraw(true);
219 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700220
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700221 /**
222 * Return the SurfaceHolder providing access and control over this
223 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700224 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700225 * @return SurfaceHolder The holder of the surface.
226 */
227 public SurfaceHolder getHolder() {
228 return mSurfaceHolder;
229 }
230
Robert Carr414ebc62017-04-12 12:01:00 -0700231 private void updateRequestedVisibility() {
232 mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
233 }
234
235 /** @hide */
236 @Override
237 public void windowStopped(boolean stopped) {
238 mWindowStopped = stopped;
239 updateRequestedVisibility();
240 updateSurface();
241 }
242
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700243 @Override
244 protected void onAttachedToWindow() {
245 super.onAttachedToWindow();
Robert Carr414ebc62017-04-12 12:01:00 -0700246
247 getViewRootImpl().addWindowStoppedCallback(this);
248
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700249 mParent.requestTransparentRegion(this);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700250 mViewVisibility = getVisibility() == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700251 updateRequestedVisibility();
Romain Guy01d5edc2011-01-28 11:28:53 -0800252
Robert Carr8508bb22017-03-27 15:46:27 -0700253 mAttachedToWindow = true;
Romain Guy01d5edc2011-01-28 11:28:53 -0800254 if (!mGlobalListenersAdded) {
255 ViewTreeObserver observer = getViewTreeObserver();
256 observer.addOnScrollChangedListener(mScrollChangedListener);
257 observer.addOnPreDrawListener(mDrawListener);
258 mGlobalListenersAdded = true;
259 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700260 }
261
262 @Override
263 protected void onWindowVisibilityChanged(int visibility) {
264 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700265 mWindowVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700266 updateRequestedVisibility();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800267 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700268 }
269
270 @Override
271 public void setVisibility(int visibility) {
272 super.setVisibility(visibility);
273 mViewVisibility = visibility == VISIBLE;
Robert Carr414ebc62017-04-12 12:01:00 -0700274 boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700275 if (newRequestedVisible != mRequestedVisible) {
276 // our base class (View) invalidates the layout only when
277 // we go from/to the GONE state. However, SurfaceView needs
278 // to request a re-layout when the visibility changes at all.
279 // This is needed because the transparent region is computed
280 // as part of the layout phase, and it changes (obviously) when
281 // the visibility changes.
282 requestLayout();
283 }
284 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800285 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700286 }
Romain Guyafc3e112010-06-07 17:04:33 -0700287
Robert Carr8508bb22017-03-27 15:46:27 -0700288 void notifyDrawFinished() {
289 ViewRootImpl viewRoot = getViewRootImpl();
290 if (viewRoot != null) {
291 viewRoot.pendingDrawFinished();
292 }
293 mPendingReportDraws--;
294 }
295
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700296 @Override
John Reck77e4a522014-10-01 10:38:07 -0700297 protected void onDetachedFromWindow() {
Lucas Dupin0c207342017-04-14 19:47:23 -0700298 ViewRootImpl viewRoot = getViewRootImpl();
299 // It's possible to create a SurfaceView using the default constructor and never
300 // attach it to a view hierarchy, this is a common use case when dealing with
301 // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage
302 // the lifecycle. Instead of attaching it to a view, he/she can just pass
303 // the SurfaceHolder forward, most live wallpapers do it.
304 if (viewRoot != null) {
305 viewRoot.removeWindowStoppedCallback(this);
306 }
Robert Carr414ebc62017-04-12 12:01:00 -0700307
Robert Carr8508bb22017-03-27 15:46:27 -0700308 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800309 if (mGlobalListenersAdded) {
310 ViewTreeObserver observer = getViewTreeObserver();
311 observer.removeOnScrollChangedListener(mScrollChangedListener);
312 observer.removeOnPreDrawListener(mDrawListener);
313 mGlobalListenersAdded = false;
314 }
315
Robert Carr8508bb22017-03-27 15:46:27 -0700316 while (mPendingReportDraws > 0) {
317 notifyDrawFinished();
318 }
319
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700320 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800321
Robert Carrd5c7dd62017-03-08 10:39:30 -0800322 updateSurface();
323 if (mSurfaceControl != null) {
324 mSurfaceControl.destroy();
325 }
326 mSurfaceControl = null;
327
328 mHaveFrame = false;
Robert Carr414ebc62017-04-12 12:01:00 -0700329
John Reck77e4a522014-10-01 10:38:07 -0700330 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700331 }
332
333 @Override
334 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800335 int width = mRequestedWidth >= 0
336 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
337 : getDefaultSize(0, widthMeasureSpec);
338 int height = mRequestedHeight >= 0
339 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
340 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700341 setMeasuredDimension(width, height);
342 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700343
Mathias Agopianef115302010-10-04 20:15:08 -0700344 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700345 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700346 protected boolean setFrame(int left, int top, int right, int bottom) {
347 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800348 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700349 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700350 }
351
352 @Override
353 public boolean gatherTransparentRegion(Region region) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800354 if (isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700355 return super.gatherTransparentRegion(region);
356 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700357
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700358 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700359 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700360 // this view draws, remove it from the transparent region
361 opaque = super.gatherTransparentRegion(region);
362 } else if (region != null) {
363 int w = getWidth();
364 int h = getHeight();
365 if (w>0 && h>0) {
366 getLocationInWindow(mLocation);
367 // otherwise, punch a hole in the whole hierarchy
368 int l = mLocation[0];
369 int t = mLocation[1];
370 region.op(l, t, l+w, t+h, Region.Op.UNION);
371 }
372 }
373 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
374 opaque = false;
375 }
376 return opaque;
377 }
378
379 @Override
380 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800381 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700382 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700383 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700384 // punch a whole in the view-hierarchy below us
385 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
386 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700387 }
388 super.draw(canvas);
389 }
390
391 @Override
392 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800393 if (mDrawFinished && !isAboveParent()) {
394 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700395 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700396 // punch a whole in the view-hierarchy below us
397 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
398 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700399 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700400 super.dispatchDraw(canvas);
401 }
402
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700403 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700404 * Control whether the surface view's surface is placed on top of another
405 * regular surface view in the window (but still behind the window itself).
406 * This is typically used to place overlays on top of an underlying media
407 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700408 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700409 * <p>Note that this must be set before the surface view's containing
410 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700411 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700412 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
413 */
414 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800415 mSubLayer = isMediaOverlay
416 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700417 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700418
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700419 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700420 * Control whether the surface view's surface is placed on top of its
421 * window. Normally it is placed behind the window, to allow it to
422 * (for the most part) appear to composite with the views in the
423 * hierarchy. By setting this, you cause it to be placed above the
424 * window. This means that none of the contents of the window this
425 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700426 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700427 * <p>Note that this must be set before the surface view's containing
428 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700429 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700430 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700431 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700432 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500433 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800434 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500435 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800436 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500437 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700438 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700439
440 /**
441 * Control whether the surface view's content should be treated as secure,
442 * preventing it from appearing in screenshots or from being viewed on
443 * non-secure displays.
444 *
445 * <p>Note that this must be set before the surface view's containing
446 * window is attached to the window manager.
447 *
448 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
449 *
450 * @param isSecure True if the surface view is secure.
451 */
452 public void setSecure(boolean isSecure) {
453 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800454 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700455 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800456 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700457 }
458 }
459
Robert Carrd5c7dd62017-03-08 10:39:30 -0800460 private Rect getParentSurfaceInsets() {
461 final ViewRootImpl root = getViewRootImpl();
462 if (root == null) {
463 return null;
464 } else {
465 return root.mWindowAttributes.surfaceInsets;
466 }
Jeff Tinker3896db12017-03-03 00:20:22 +0000467 }
468
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900469 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800470 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700471 if (!mHaveFrame) {
472 return;
473 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800474 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800475 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
476 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700477 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700478
Robert Carrd5c7dd62017-03-08 10:39:30 -0800479 mTranslator = viewRoot.mTranslator;
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700480 if (mTranslator != null) {
481 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700482 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700483
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700484 int myWidth = mRequestedWidth;
485 if (myWidth <= 0) myWidth = getWidth();
486 int myHeight = mRequestedHeight;
487 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700488
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700489 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800490 final boolean creating = (mSurfaceControl == null || formatChanged)
491 && mRequestedVisible;
492 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800493 final boolean visibleChanged = mVisible != mRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800494 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700495 boolean redrawNeeded = false;
496
Robert Carrd5c7dd62017-03-08 10:39:30 -0800497 if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800498 getLocationInWindow(mLocation);
499
John Reckaa6e84f2016-06-16 15:36:13 -0700500 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
501 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700502 + " format=" + formatChanged + " size=" + sizeChanged
503 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800504 + " left=" + (mWindowSpaceLeft != mLocation[0])
505 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700506
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700507 try {
508 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800509 mWindowSpaceLeft = mLocation[0];
510 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800511 mSurfaceWidth = myWidth;
512 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700513 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800514 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700515
Robert Carrd5c7dd62017-03-08 10:39:30 -0800516 mScreenRect.left = mWindowSpaceLeft;
517 mScreenRect.top = mWindowSpaceTop;
518 mScreenRect.right = mWindowSpaceLeft + getWidth();
519 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700520 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800521 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700522 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700523
Robert Carrd5c7dd62017-03-08 10:39:30 -0800524 final Rect surfaceInsets = getParentSurfaceInsets();
525 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
526
527 if (creating) {
528 mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
Robert Carr3bc95b52017-03-20 21:57:23 -0700529 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800530 mSurfaceControl = new SurfaceControl(mSurfaceSession,
531 "SurfaceView - " + viewRoot.getTitle().toString(),
532 mSurfaceWidth, mSurfaceHeight, mFormat,
533 mSurfaceFlags);
Robert Carr44ab5752017-03-20 21:47:11 -0700534 } else if (mSurfaceControl == null) {
535 return;
Robert Carr64aadd02015-11-06 13:54:20 -0800536 }
537
Robert Carrd5c7dd62017-03-08 10:39:30 -0800538 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800539
Dianne Hackborn726426e2010-03-31 22:04:36 -0700540 mSurfaceLock.lock();
541 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700542 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700543
John Reckaa6e84f2016-06-16 15:36:13 -0700544 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
545 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800546
Robert Carrd5c7dd62017-03-08 10:39:30 -0800547 SurfaceControl.openTransaction();
548 try {
549 mSurfaceControl.setLayer(mSubLayer);
550 if (mViewVisibility) {
551 mSurfaceControl.show();
552 } else {
553 mSurfaceControl.hide();
554 }
555
556 // While creating the surface, we will set it's initial
557 // geometry. Outside of that though, we should generally
558 // leave it to the RenderThread.
Robert Carr511719f2017-03-13 15:27:15 -0700559 //
560 // There is one more case when the buffer size changes we aren't yet
561 // prepared to sync (as even following the transaction applying
562 // we still need to latch a buffer).
563 // b/28866173
564 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800565 mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
566 mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
567 0.0f, 0.0f,
568 mScreenRect.height() / (float) mSurfaceHeight);
569 }
570 if (sizeChanged) {
571 mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
572 }
573 } finally {
574 SurfaceControl.closeTransaction();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700575 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800576
Robert Carrd5c7dd62017-03-08 10:39:30 -0800577 if (sizeChanged || creating) {
578 redrawNeeded = true;
579 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800580
Dianne Hackborn726426e2010-03-31 22:04:36 -0700581 mSurfaceFrame.left = 0;
582 mSurfaceFrame.top = 0;
583 if (mTranslator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800584 mSurfaceFrame.right = mSurfaceWidth;
585 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700586 } else {
587 float appInvertedScale = mTranslator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800588 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
589 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700590 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700591
Dianne Hackborn726426e2010-03-31 22:04:36 -0700592 final int surfaceWidth = mSurfaceFrame.right;
593 final int surfaceHeight = mSurfaceFrame.bottom;
594 realSizeChanged = mLastSurfaceWidth != surfaceWidth
595 || mLastSurfaceHeight != surfaceHeight;
596 mLastSurfaceWidth = surfaceWidth;
597 mLastSurfaceHeight = surfaceHeight;
598 } finally {
599 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700600 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700601
602 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800603 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700604
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800605 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700606
Robert Carrd5c7dd62017-03-08 10:39:30 -0800607 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800608 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
609 mSurfaceCreated = false;
610 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700611 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
612 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800613 callbacks = getSurfaceCallbacks();
614 for (SurfaceHolder.Callback c : callbacks) {
615 c.surfaceDestroyed(mSurfaceHolder);
616 }
Robert Carr387838b2016-09-07 14:12:44 -0700617 // Since Android N the same surface may be reused and given to us
618 // again by the system server at a later point. However
619 // as we didn't do this in previous releases, clients weren't
620 // necessarily required to clean up properly in
621 // surfaceDestroyed. This leads to problems for example when
622 // clients don't destroy their EGL context, and try
623 // and create a new one on the same surface following reuse.
624 // Since there is no valid use of the surface in-between
625 // surfaceDestroyed and surfaceCreated, we force a disconnect,
626 // so the next connect will always work if we end up reusing
627 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700628 if (mSurface.isValid()) {
629 mSurface.forceScopedDisconnect();
630 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700631 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800632 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700633
Robert Carrd5c7dd62017-03-08 10:39:30 -0800634 if (creating) {
635 mSurface.copyFrom(mSurfaceControl);
636 }
637
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200638 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800639 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
640 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700641 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700642 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
643 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800644 if (callbacks == null) {
645 callbacks = getSurfaceCallbacks();
646 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700647 for (SurfaceHolder.Callback c : callbacks) {
648 c.surfaceCreated(mSurfaceHolder);
649 }
650 }
651 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700652 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700653 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
654 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800655 + " w=" + myWidth + " h=" + myHeight);
656 if (callbacks == null) {
657 callbacks = getSurfaceCallbacks();
658 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700659 for (SurfaceHolder.Callback c : callbacks) {
660 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
661 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700662 }
663 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -0700664 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
665 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800666 if (callbacks == null) {
667 callbacks = getSurfaceCallbacks();
668 }
Robert Carr8508bb22017-03-27 15:46:27 -0700669
670 mPendingReportDraws++;
671 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -0800672 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -0800673 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -0800674 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700675 }
676 }
677 } finally {
678 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800679 if (mSurfaceControl != null && !mSurfaceCreated) {
680 mSurfaceControl.destroy();
681 mSurfaceControl = null;
682 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700683 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800684 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700685 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700686 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800687 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -0800688 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
689 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
690 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -0700691 } else {
692 // Calculate the window position in case RT loses the window
693 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -0800694 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -0800695 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
696 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800697 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
698 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -0800699 if (positionChanged || layoutSizeChanged) { // Only the position has changed
700 mWindowSpaceLeft = mLocation[0];
701 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800702 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -0800703 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800704 mLocation[0] = getWidth();
705 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -0800706
Robert Carrd5c7dd62017-03-08 10:39:30 -0800707 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
John Reckf057fb52016-04-15 13:46:29 -0700708 mLocation[0], mLocation[1]);
709
710 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800711 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -0700712 }
713
Robert Carr3651ab82017-04-25 12:05:34 -0700714 if (mSurfaceControl == null) {
715 return;
716 }
717
Bryce Lee16e50892017-04-11 01:59:37 +0000718 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
John Reckf23a1b82016-06-22 14:23:31 -0700719 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800720 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
John Reckf23a1b82016-06-22 14:23:31 -0700721 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800722 mScreenRect.left, mScreenRect.top,
723 mScreenRect.right, mScreenRect.bottom));
724 setParentSpaceRectangle(mScreenRect, -1);
725 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700726 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -0700727 }
John Reckf6481082016-02-02 15:18:23 -0800728 }
Rob Carr64e516f2015-10-29 00:20:45 +0000729 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700730 }
731 }
732
Robert Carrd5c7dd62017-03-08 10:39:30 -0800733 private void onDrawFinished() {
734 if (DEBUG) {
735 Log.i(TAG, System.identityHashCode(this) + " "
736 + "finishedDrawing");
737 }
Robert Carr3bc95b52017-03-20 21:57:23 -0700738
739 if (mDeferredDestroySurfaceControl != null) {
740 mDeferredDestroySurfaceControl.destroy();
741 mDeferredDestroySurfaceControl = null;
742 }
743
Robert Carrd5c7dd62017-03-08 10:39:30 -0800744 mHandler.sendEmptyMessage(DRAW_FINISHED_MSG);
745 }
746
747 private void setParentSpaceRectangle(Rect position, long frameNumber) {
748 ViewRootImpl viewRoot = getViewRootImpl();
749
750 SurfaceControl.openTransaction();
751 try {
752 if (frameNumber > 0) {
753 mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber);
754 }
755 mSurfaceControl.setPosition(position.left, position.top);
756 mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth,
757 0.0f, 0.0f,
758 position.height() / (float) mSurfaceHeight);
759 } finally {
760 SurfaceControl.closeTransaction();
761 }
762 }
763
John Reckf6481082016-02-02 15:18:23 -0800764 private Rect mRTLastReportedPosition = new Rect();
765
766 /**
Robert Carr33879132016-09-06 14:41:40 -0700767 * Called by native by a Rendering Worker thread to update the window position
John Reckf6481082016-02-02 15:18:23 -0800768 * @hide
769 */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800770 public final void updateSurfacePosition_renderWorker(long frameNumber,
John Reckf6481082016-02-02 15:18:23 -0800771 int left, int top, int right, int bottom) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800772 if (mSurfaceControl == null) {
John Reckf6481082016-02-02 15:18:23 -0800773 return;
774 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800775
John Reckf23a1b82016-06-22 14:23:31 -0700776 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
777 // its 2nd frame if RenderThread is running slowly could potentially see
778 // this as false, enter the branch, get pre-empted, then this comes along
779 // and reports a new position, then the UI thread resumes and reports
780 // its position. This could therefore be de-sync'd in that interval, but
781 // the synchronization would violate the rule that RT must never block
782 // on the UI thread which would open up potential deadlocks. The risk of
783 // a single-frame desync is therefore preferable for now.
784 mRtHandlingPositionUpdates = true;
John Reckf6481082016-02-02 15:18:23 -0800785 if (mRTLastReportedPosition.left == left
786 && mRTLastReportedPosition.top == top
787 && mRTLastReportedPosition.right == right
788 && mRTLastReportedPosition.bottom == bottom) {
789 return;
790 }
791 try {
792 if (DEBUG) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800793 Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
John Reckaa6e84f2016-06-16 15:36:13 -0700794 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
795 frameNumber, left, top, right, bottom));
John Reckf6481082016-02-02 15:18:23 -0800796 }
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800797 mRTLastReportedPosition.set(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800798 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
799 // Now overwrite mRTLastReportedPosition with our values
800 } catch (Exception ex) {
John Reckf6481082016-02-02 15:18:23 -0800801 Log.e(TAG, "Exception from repositionChild", ex);
802 }
803 }
804
John Reckaa6e84f2016-06-16 15:36:13 -0700805 /**
Robert Carrd5c7dd62017-03-08 10:39:30 -0800806 * Called by native on RenderThread to notify that the view is no longer in the
Robert Carr33879132016-09-06 14:41:40 -0700807 * draw tree. UI thread is blocked at this point.
John Reckaa6e84f2016-06-16 15:36:13 -0700808 * @hide
809 */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800810 public final void surfacePositionLost_uiRtSync(long frameNumber) {
John Reckaa6e84f2016-06-16 15:36:13 -0700811 if (DEBUG) {
Robert Carr33879132016-09-06 14:41:40 -0700812 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
John Reckaa6e84f2016-06-16 15:36:13 -0700813 System.identityHashCode(this), frameNumber));
814 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800815 if (mSurfaceControl == null) {
John Reck474659c2016-06-27 07:56:37 -0700816 return;
817 }
John Reckf23a1b82016-06-22 14:23:31 -0700818 if (mRtHandlingPositionUpdates) {
819 mRtHandlingPositionUpdates = false;
820 // This callback will happen while the UI thread is blocked, so we can
821 // safely access other member variables at this time.
822 // So do what the UI thread would have done if RT wasn't handling position
823 // updates.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800824 if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
John Reckf23a1b82016-06-22 14:23:31 -0700825 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800826 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
John Reckf23a1b82016-06-22 14:23:31 -0700827 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800828 mScreenRect.left, mScreenRect.top,
829 mScreenRect.right, mScreenRect.bottom));
830 setParentSpaceRectangle(mScreenRect, frameNumber);
831 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700832 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -0700833 }
834 }
835 mRTLastReportedPosition.setEmpty();
836 }
John Reckaa6e84f2016-06-16 15:36:13 -0700837 }
838
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800839 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
840 SurfaceHolder.Callback callbacks[];
841 synchronized (mCallbacks) {
842 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
843 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700844 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800845 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700846 }
847
Derek Sollenberger7179b812010-03-22 13:41:20 -0400848 /**
Yohei Yukawa3b5011a2017-03-16 15:34:12 -0700849 * This method still exists only for compatibility reasons because some applications have relied
850 * on this method via reflection. See Issue 36345857 for details.
851 *
852 * @deprecated No platform code is using this method anymore.
853 * @hide
854 */
855 @Deprecated
856 public void setWindowType(int type) {
857 if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1) {
858 throw new UnsupportedOperationException(
859 "SurfaceView#setWindowType() has never been a public API.");
860 }
861
862 if (type == TYPE_APPLICATION_PANEL) {
863 Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
864 + "just to make the SurfaceView to be placed on top of its window, you must "
865 + "call setZOrderOnTop(true) instead.", new Throwable());
866 setZOrderOnTop(true);
867 return;
868 }
869 Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
870 + "type=" + type, new Throwable());
871 }
872
873 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -0400874 * Check to see if the surface has fixed size dimensions or if the surface's
875 * dimensions are dimensions are dependent on its current layout.
876 *
877 * @return true if the surface has dimensions that are fixed in size
878 * @hide
879 */
880 public boolean isFixedSize() {
881 return (mRequestedWidth != -1 || mRequestedHeight != -1);
882 }
883
Robert Carrd5c7dd62017-03-08 10:39:30 -0800884 private boolean isAboveParent() {
885 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700886 }
887
Igor Murashkina86ab6402013-08-30 12:58:36 -0700888 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700889 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -0700890
891 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700892 public boolean isCreating() {
893 return mIsCreating;
894 }
895
Igor Murashkina86ab6402013-08-30 12:58:36 -0700896 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700897 public void addCallback(Callback callback) {
898 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700899 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700900 // have only a couple callbacks, so it doesn't matter.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700901 if (mCallbacks.contains(callback) == false) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700902 mCallbacks.add(callback);
903 }
904 }
905 }
906
Igor Murashkina86ab6402013-08-30 12:58:36 -0700907 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700908 public void removeCallback(Callback callback) {
909 synchronized (mCallbacks) {
910 mCallbacks.remove(callback);
911 }
912 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700913
914 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700915 public void setFixedSize(int width, int height) {
916 if (mRequestedWidth != width || mRequestedHeight != height) {
917 mRequestedWidth = width;
918 mRequestedHeight = height;
919 requestLayout();
920 }
921 }
922
Igor Murashkina86ab6402013-08-30 12:58:36 -0700923 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700924 public void setSizeFromLayout() {
925 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
926 mRequestedWidth = mRequestedHeight = -1;
927 requestLayout();
928 }
929 }
930
Igor Murashkina86ab6402013-08-30 12:58:36 -0700931 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700932 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700933 // for backward compatibility reason, OPAQUE always
934 // means 565 for SurfaceView
935 if (format == PixelFormat.OPAQUE)
936 format = PixelFormat.RGB_565;
937
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700938 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800939 if (mSurfaceControl != null) {
940 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700941 }
942 }
943
Mathias Agopiand2112302010-12-07 19:38:17 -0800944 /**
945 * @deprecated setType is now ignored.
946 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700947 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -0800948 @Deprecated
949 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700950
Igor Murashkina86ab6402013-08-30 12:58:36 -0700951 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700952 public void setKeepScreenOn(boolean screenOn) {
953 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
954 msg.arg1 = screenOn ? 1 : 0;
955 mHandler.sendMessage(msg);
956 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700957
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700958 /**
959 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
960 *
961 * After drawing into the provided {@link Canvas}, the caller must
962 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
963 *
964 * The caller must redraw the entire surface.
965 * @return A canvas for drawing into the surface.
966 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700967 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700968 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -0700969 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700970 }
971
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700972 /**
973 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
974 *
975 * After drawing into the provided {@link Canvas}, the caller must
976 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
977 *
978 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
979 * to redraw. This function may choose to expand the dirty rectangle if for example
980 * the surface has been resized or if the previous contents of the surface were
981 * not available. The caller must redraw the entire dirty region as represented
982 * by the contents of the inOutDirty rectangle upon return from this function.
983 * The caller may also pass <code>null</code> instead, in the case where the
984 * entire surface should be redrawn.
985 * @return A canvas for drawing into the surface.
986 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700987 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700988 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -0700989 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700990 }
991
John Reck6bc70142016-10-26 16:49:17 -0700992 @Override
993 public Canvas lockHardwareCanvas() {
994 return internalLockCanvas(null, true);
995 }
996
997 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700998 mSurfaceLock.lock();
999
John Reckaa6e84f2016-06-16 15:36:13 -07001000 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -08001001 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001002
1003 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -08001004 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001005 try {
John Reck6bc70142016-10-26 16:49:17 -07001006 if (hardware) {
1007 c = mSurface.lockHardwareCanvas();
1008 } else {
1009 c = mSurface.lockCanvas(dirty);
1010 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001011 } catch (Exception e) {
1012 Log.e(LOG_TAG, "Exception locking surface", e);
1013 }
1014 }
1015
John Reckaa6e84f2016-06-16 15:36:13 -07001016 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001017 if (c != null) {
1018 mLastLockTime = SystemClock.uptimeMillis();
1019 return c;
1020 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001021
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001022 // If the Surface is not ready to be drawn, then return null,
1023 // but throttle calls to this function so it isn't called more
1024 // than every 100ms.
1025 long now = SystemClock.uptimeMillis();
1026 long nextTime = mLastLockTime + 100;
1027 if (nextTime > now) {
1028 try {
1029 Thread.sleep(nextTime-now);
1030 } catch (InterruptedException e) {
1031 }
1032 now = SystemClock.uptimeMillis();
1033 }
1034 mLastLockTime = now;
1035 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001036
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001037 return null;
1038 }
1039
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001040 /**
1041 * Posts the new contents of the {@link Canvas} to the surface and
1042 * releases the {@link Canvas}.
1043 *
1044 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1045 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001046 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001047 public void unlockCanvasAndPost(Canvas canvas) {
1048 mSurface.unlockCanvasAndPost(canvas);
1049 mSurfaceLock.unlock();
1050 }
1051
Igor Murashkina86ab6402013-08-30 12:58:36 -07001052 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001053 public Surface getSurface() {
1054 return mSurface;
1055 }
1056
Igor Murashkina86ab6402013-08-30 12:58:36 -07001057 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001058 public Rect getSurfaceFrame() {
1059 return mSurfaceFrame;
1060 }
1061 };
1062}