blob: 076b33cc9d6a00d0575d7717d2db08b205aa185f [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 */
96public class SurfaceView extends View {
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;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700172 int mRequestedWidth = -1;
173 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700174 /* Set SurfaceView's format to 565 by default to maintain backward
175 * compatibility with applications assuming this format.
176 */
177 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700178
179 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800180 boolean mSurfaceCreated = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700181 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700182
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700183 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800184 int mWindowSpaceLeft = -1;
185 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800186 int mSurfaceWidth = -1;
187 int mSurfaceHeight = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700188 int mFormat = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700189 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700190 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700191 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800192
Romain Guy01d5edc2011-01-28 11:28:53 -0800193 private boolean mGlobalListenersAdded;
Robert Carr8508bb22017-03-27 15:46:27 -0700194 private boolean mAttachedToWindow;
Romain Guyf2499fa2011-01-26 18:31:23 -0800195
Robert Carrd5c7dd62017-03-08 10:39:30 -0800196 private int mSurfaceFlags = SurfaceControl.HIDDEN;
197
Robert Carr8508bb22017-03-27 15:46:27 -0700198 private int mPendingReportDraws;
199
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700200 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400201 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700202 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700203
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700204 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400205 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700206 }
207
Alan Viverette617feb92013-09-09 18:09:13 -0700208 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400209 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700210 }
211
212 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
213 super(context, attrs, defStyleAttr, defStyleRes);
John Reck3acf03822016-11-02 11:14:47 -0700214 mRenderNode.requestPositionUpdates(this);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700215
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700216 setWillNotDraw(true);
217 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700218
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700219 /**
220 * Return the SurfaceHolder providing access and control over this
221 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700222 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700223 * @return SurfaceHolder The holder of the surface.
224 */
225 public SurfaceHolder getHolder() {
226 return mSurfaceHolder;
227 }
228
229 @Override
230 protected void onAttachedToWindow() {
231 super.onAttachedToWindow();
232 mParent.requestTransparentRegion(this);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700233 mViewVisibility = getVisibility() == VISIBLE;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800234 mRequestedVisible = mViewVisibility && mWindowVisibility;
Romain Guy01d5edc2011-01-28 11:28:53 -0800235
Robert Carr8508bb22017-03-27 15:46:27 -0700236 mAttachedToWindow = true;
Romain Guy01d5edc2011-01-28 11:28:53 -0800237 if (!mGlobalListenersAdded) {
238 ViewTreeObserver observer = getViewTreeObserver();
239 observer.addOnScrollChangedListener(mScrollChangedListener);
240 observer.addOnPreDrawListener(mDrawListener);
241 mGlobalListenersAdded = true;
242 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700243 }
244
245 @Override
246 protected void onWindowVisibilityChanged(int visibility) {
247 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700248 mWindowVisibility = visibility == VISIBLE;
249 mRequestedVisible = mWindowVisibility && mViewVisibility;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800250 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700251 }
252
253 @Override
254 public void setVisibility(int visibility) {
255 super.setVisibility(visibility);
256 mViewVisibility = visibility == VISIBLE;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700257 boolean newRequestedVisible = mWindowVisibility && mViewVisibility;
258 if (newRequestedVisible != mRequestedVisible) {
259 // our base class (View) invalidates the layout only when
260 // we go from/to the GONE state. However, SurfaceView needs
261 // to request a re-layout when the visibility changes at all.
262 // This is needed because the transparent region is computed
263 // as part of the layout phase, and it changes (obviously) when
264 // the visibility changes.
265 requestLayout();
266 }
267 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800268 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700269 }
Romain Guyafc3e112010-06-07 17:04:33 -0700270
Robert Carr8508bb22017-03-27 15:46:27 -0700271 void notifyDrawFinished() {
272 ViewRootImpl viewRoot = getViewRootImpl();
273 if (viewRoot != null) {
274 viewRoot.pendingDrawFinished();
275 }
276 mPendingReportDraws--;
277 }
278
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700279 @Override
John Reck77e4a522014-10-01 10:38:07 -0700280 protected void onDetachedFromWindow() {
Robert Carr8508bb22017-03-27 15:46:27 -0700281 mAttachedToWindow = false;
Romain Guy01d5edc2011-01-28 11:28:53 -0800282 if (mGlobalListenersAdded) {
283 ViewTreeObserver observer = getViewTreeObserver();
284 observer.removeOnScrollChangedListener(mScrollChangedListener);
285 observer.removeOnPreDrawListener(mDrawListener);
286 mGlobalListenersAdded = false;
287 }
288
Robert Carr8508bb22017-03-27 15:46:27 -0700289 while (mPendingReportDraws > 0) {
290 notifyDrawFinished();
291 }
292
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700293 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800294
Robert Carrd5c7dd62017-03-08 10:39:30 -0800295 updateSurface();
296 if (mSurfaceControl != null) {
297 mSurfaceControl.destroy();
298 }
299 mSurfaceControl = null;
300
301 mHaveFrame = false;
John Reck77e4a522014-10-01 10:38:07 -0700302 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700303 }
304
305 @Override
306 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800307 int width = mRequestedWidth >= 0
308 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
309 : getDefaultSize(0, widthMeasureSpec);
310 int height = mRequestedHeight >= 0
311 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
312 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700313 setMeasuredDimension(width, height);
314 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700315
Mathias Agopianef115302010-10-04 20:15:08 -0700316 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700317 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700318 protected boolean setFrame(int left, int top, int right, int bottom) {
319 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800320 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700321 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700322 }
323
324 @Override
325 public boolean gatherTransparentRegion(Region region) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800326 if (isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700327 return super.gatherTransparentRegion(region);
328 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700329
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700330 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700331 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700332 // this view draws, remove it from the transparent region
333 opaque = super.gatherTransparentRegion(region);
334 } else if (region != null) {
335 int w = getWidth();
336 int h = getHeight();
337 if (w>0 && h>0) {
338 getLocationInWindow(mLocation);
339 // otherwise, punch a hole in the whole hierarchy
340 int l = mLocation[0];
341 int t = mLocation[1];
342 region.op(l, t, l+w, t+h, Region.Op.UNION);
343 }
344 }
345 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
346 opaque = false;
347 }
348 return opaque;
349 }
350
351 @Override
352 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800353 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700354 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700355 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700356 // punch a whole in the view-hierarchy below us
357 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
358 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700359 }
360 super.draw(canvas);
361 }
362
363 @Override
364 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800365 if (mDrawFinished && !isAboveParent()) {
366 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700367 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700368 // punch a whole in the view-hierarchy below us
369 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
370 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700371 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700372 super.dispatchDraw(canvas);
373 }
374
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700375 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700376 * Control whether the surface view's surface is placed on top of another
377 * regular surface view in the window (but still behind the window itself).
378 * This is typically used to place overlays on top of an underlying media
379 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700380 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700381 * <p>Note that this must be set before the surface view's containing
382 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700383 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700384 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
385 */
386 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800387 mSubLayer = isMediaOverlay
388 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700389 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700390
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700391 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700392 * Control whether the surface view's surface is placed on top of its
393 * window. Normally it is placed behind the window, to allow it to
394 * (for the most part) appear to composite with the views in the
395 * hierarchy. By setting this, you cause it to be placed above the
396 * window. This means that none of the contents of the window this
397 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700398 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700399 * <p>Note that this must be set before the surface view's containing
400 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700401 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700402 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700403 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700404 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500405 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800406 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500407 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800408 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500409 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700410 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700411
412 /**
413 * Control whether the surface view's content should be treated as secure,
414 * preventing it from appearing in screenshots or from being viewed on
415 * non-secure displays.
416 *
417 * <p>Note that this must be set before the surface view's containing
418 * window is attached to the window manager.
419 *
420 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
421 *
422 * @param isSecure True if the surface view is secure.
423 */
424 public void setSecure(boolean isSecure) {
425 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800426 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700427 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800428 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700429 }
430 }
431
Robert Carrd5c7dd62017-03-08 10:39:30 -0800432 private Rect getParentSurfaceInsets() {
433 final ViewRootImpl root = getViewRootImpl();
434 if (root == null) {
435 return null;
436 } else {
437 return root.mWindowAttributes.surfaceInsets;
438 }
Jeff Tinker3896db12017-03-03 00:20:22 +0000439 }
440
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900441 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800442 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700443 if (!mHaveFrame) {
444 return;
445 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800446 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800447 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
448 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700449 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700450
Robert Carrd5c7dd62017-03-08 10:39:30 -0800451 mTranslator = viewRoot.mTranslator;
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700452 if (mTranslator != null) {
453 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700454 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700455
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700456 int myWidth = mRequestedWidth;
457 if (myWidth <= 0) myWidth = getWidth();
458 int myHeight = mRequestedHeight;
459 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700460
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700461 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800462 final boolean creating = (mSurfaceControl == null || formatChanged)
463 && mRequestedVisible;
464 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800465 final boolean visibleChanged = mVisible != mRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800466 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700467 boolean redrawNeeded = false;
468
Robert Carrd5c7dd62017-03-08 10:39:30 -0800469 if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800470 getLocationInWindow(mLocation);
471
John Reckaa6e84f2016-06-16 15:36:13 -0700472 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
473 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700474 + " format=" + formatChanged + " size=" + sizeChanged
475 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800476 + " left=" + (mWindowSpaceLeft != mLocation[0])
477 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700478
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700479 try {
480 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800481 mWindowSpaceLeft = mLocation[0];
482 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800483 mSurfaceWidth = myWidth;
484 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700485 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800486 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700487
Robert Carrd5c7dd62017-03-08 10:39:30 -0800488 mScreenRect.left = mWindowSpaceLeft;
489 mScreenRect.top = mWindowSpaceTop;
490 mScreenRect.right = mWindowSpaceLeft + getWidth();
491 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700492 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800493 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700494 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700495
Robert Carrd5c7dd62017-03-08 10:39:30 -0800496 final Rect surfaceInsets = getParentSurfaceInsets();
497 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
498
499 if (creating) {
500 mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
Robert Carr3bc95b52017-03-20 21:57:23 -0700501 mDeferredDestroySurfaceControl = mSurfaceControl;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800502 mSurfaceControl = new SurfaceControl(mSurfaceSession,
503 "SurfaceView - " + viewRoot.getTitle().toString(),
504 mSurfaceWidth, mSurfaceHeight, mFormat,
505 mSurfaceFlags);
Robert Carr44ab5752017-03-20 21:47:11 -0700506 } else if (mSurfaceControl == null) {
507 return;
Robert Carr64aadd02015-11-06 13:54:20 -0800508 }
509
Robert Carrd5c7dd62017-03-08 10:39:30 -0800510 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800511
Dianne Hackborn726426e2010-03-31 22:04:36 -0700512 mSurfaceLock.lock();
513 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700514 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700515
John Reckaa6e84f2016-06-16 15:36:13 -0700516 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
517 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800518
Robert Carrd5c7dd62017-03-08 10:39:30 -0800519 SurfaceControl.openTransaction();
520 try {
521 mSurfaceControl.setLayer(mSubLayer);
522 if (mViewVisibility) {
523 mSurfaceControl.show();
524 } else {
525 mSurfaceControl.hide();
526 }
527
528 // While creating the surface, we will set it's initial
529 // geometry. Outside of that though, we should generally
530 // leave it to the RenderThread.
Robert Carr511719f2017-03-13 15:27:15 -0700531 //
532 // There is one more case when the buffer size changes we aren't yet
533 // prepared to sync (as even following the transaction applying
534 // we still need to latch a buffer).
535 // b/28866173
536 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800537 mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
538 mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
539 0.0f, 0.0f,
540 mScreenRect.height() / (float) mSurfaceHeight);
541 }
542 if (sizeChanged) {
543 mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
544 }
545 } finally {
546 SurfaceControl.closeTransaction();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700547 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800548
Robert Carrd5c7dd62017-03-08 10:39:30 -0800549 if (sizeChanged || creating) {
550 redrawNeeded = true;
551 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800552
Dianne Hackborn726426e2010-03-31 22:04:36 -0700553 mSurfaceFrame.left = 0;
554 mSurfaceFrame.top = 0;
555 if (mTranslator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800556 mSurfaceFrame.right = mSurfaceWidth;
557 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700558 } else {
559 float appInvertedScale = mTranslator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800560 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
561 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700562 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700563
Dianne Hackborn726426e2010-03-31 22:04:36 -0700564 final int surfaceWidth = mSurfaceFrame.right;
565 final int surfaceHeight = mSurfaceFrame.bottom;
566 realSizeChanged = mLastSurfaceWidth != surfaceWidth
567 || mLastSurfaceHeight != surfaceHeight;
568 mLastSurfaceWidth = surfaceWidth;
569 mLastSurfaceHeight = surfaceHeight;
570 } finally {
571 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700572 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700573
574 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800575 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700576
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800577 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700578
Robert Carrd5c7dd62017-03-08 10:39:30 -0800579 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800580 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
581 mSurfaceCreated = false;
582 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700583 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
584 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800585 callbacks = getSurfaceCallbacks();
586 for (SurfaceHolder.Callback c : callbacks) {
587 c.surfaceDestroyed(mSurfaceHolder);
588 }
Robert Carr387838b2016-09-07 14:12:44 -0700589 // Since Android N the same surface may be reused and given to us
590 // again by the system server at a later point. However
591 // as we didn't do this in previous releases, clients weren't
592 // necessarily required to clean up properly in
593 // surfaceDestroyed. This leads to problems for example when
594 // clients don't destroy their EGL context, and try
595 // and create a new one on the same surface following reuse.
596 // Since there is no valid use of the surface in-between
597 // surfaceDestroyed and surfaceCreated, we force a disconnect,
598 // so the next connect will always work if we end up reusing
599 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700600 if (mSurface.isValid()) {
601 mSurface.forceScopedDisconnect();
602 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700603 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800604 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700605
Robert Carrd5c7dd62017-03-08 10:39:30 -0800606 if (creating) {
607 mSurface.copyFrom(mSurfaceControl);
608 }
609
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200610 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800611 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
612 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700613 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700614 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
615 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800616 if (callbacks == null) {
617 callbacks = getSurfaceCallbacks();
618 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700619 for (SurfaceHolder.Callback c : callbacks) {
620 c.surfaceCreated(mSurfaceHolder);
621 }
622 }
623 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700624 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700625 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
626 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800627 + " w=" + myWidth + " h=" + myHeight);
628 if (callbacks == null) {
629 callbacks = getSurfaceCallbacks();
630 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700631 for (SurfaceHolder.Callback c : callbacks) {
632 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
633 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700634 }
635 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -0700636 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
637 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800638 if (callbacks == null) {
639 callbacks = getSurfaceCallbacks();
640 }
Robert Carr8508bb22017-03-27 15:46:27 -0700641
642 mPendingReportDraws++;
643 viewRoot.drawPending();
Robert Carr25cfa132016-11-16 13:24:09 -0800644 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -0800645 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -0800646 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700647 }
648 }
649 } finally {
650 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800651 if (mSurfaceControl != null && !mSurfaceCreated) {
652 mSurfaceControl.destroy();
653 mSurfaceControl = null;
654 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700655 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800656 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700657 Log.e(TAG, "Exception configuring surface", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700658 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800659 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -0800660 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
661 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
662 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -0700663 } else {
664 // Calculate the window position in case RT loses the window
665 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -0800666 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -0800667 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
668 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800669 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
670 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -0800671 if (positionChanged || layoutSizeChanged) { // Only the position has changed
672 mWindowSpaceLeft = mLocation[0];
673 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800674 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -0800675 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800676 mLocation[0] = getWidth();
677 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -0800678
Robert Carrd5c7dd62017-03-08 10:39:30 -0800679 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
John Reckf057fb52016-04-15 13:46:29 -0700680 mLocation[0], mLocation[1]);
681
682 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800683 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -0700684 }
685
John Reckf23a1b82016-06-22 14:23:31 -0700686 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
687 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800688 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
John Reckf23a1b82016-06-22 14:23:31 -0700689 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800690 mScreenRect.left, mScreenRect.top,
691 mScreenRect.right, mScreenRect.bottom));
692 setParentSpaceRectangle(mScreenRect, -1);
693 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700694 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -0700695 }
John Reckf6481082016-02-02 15:18:23 -0800696 }
Rob Carr64e516f2015-10-29 00:20:45 +0000697 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700698 }
699 }
700
Robert Carrd5c7dd62017-03-08 10:39:30 -0800701 private void onDrawFinished() {
702 if (DEBUG) {
703 Log.i(TAG, System.identityHashCode(this) + " "
704 + "finishedDrawing");
705 }
Robert Carr3bc95b52017-03-20 21:57:23 -0700706
707 if (mDeferredDestroySurfaceControl != null) {
708 mDeferredDestroySurfaceControl.destroy();
709 mDeferredDestroySurfaceControl = null;
710 }
711
Robert Carrd5c7dd62017-03-08 10:39:30 -0800712 mHandler.sendEmptyMessage(DRAW_FINISHED_MSG);
713 }
714
715 private void setParentSpaceRectangle(Rect position, long frameNumber) {
716 ViewRootImpl viewRoot = getViewRootImpl();
717
718 SurfaceControl.openTransaction();
719 try {
720 if (frameNumber > 0) {
721 mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber);
722 }
723 mSurfaceControl.setPosition(position.left, position.top);
724 mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth,
725 0.0f, 0.0f,
726 position.height() / (float) mSurfaceHeight);
727 } finally {
728 SurfaceControl.closeTransaction();
729 }
730 }
731
John Reckf6481082016-02-02 15:18:23 -0800732 private Rect mRTLastReportedPosition = new Rect();
733
734 /**
Robert Carr33879132016-09-06 14:41:40 -0700735 * Called by native by a Rendering Worker thread to update the window position
John Reckf6481082016-02-02 15:18:23 -0800736 * @hide
737 */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800738 public final void updateSurfacePosition_renderWorker(long frameNumber,
John Reckf6481082016-02-02 15:18:23 -0800739 int left, int top, int right, int bottom) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800740 if (mSurfaceControl == null) {
John Reckf6481082016-02-02 15:18:23 -0800741 return;
742 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800743
John Reckf23a1b82016-06-22 14:23:31 -0700744 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
745 // its 2nd frame if RenderThread is running slowly could potentially see
746 // this as false, enter the branch, get pre-empted, then this comes along
747 // and reports a new position, then the UI thread resumes and reports
748 // its position. This could therefore be de-sync'd in that interval, but
749 // the synchronization would violate the rule that RT must never block
750 // on the UI thread which would open up potential deadlocks. The risk of
751 // a single-frame desync is therefore preferable for now.
752 mRtHandlingPositionUpdates = true;
John Reckf6481082016-02-02 15:18:23 -0800753 if (mRTLastReportedPosition.left == left
754 && mRTLastReportedPosition.top == top
755 && mRTLastReportedPosition.right == right
756 && mRTLastReportedPosition.bottom == bottom) {
757 return;
758 }
759 try {
760 if (DEBUG) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800761 Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
John Reckaa6e84f2016-06-16 15:36:13 -0700762 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
763 frameNumber, left, top, right, bottom));
John Reckf6481082016-02-02 15:18:23 -0800764 }
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800765 mRTLastReportedPosition.set(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800766 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
767 // Now overwrite mRTLastReportedPosition with our values
768 } catch (Exception ex) {
John Reckf6481082016-02-02 15:18:23 -0800769 Log.e(TAG, "Exception from repositionChild", ex);
770 }
771 }
772
John Reckaa6e84f2016-06-16 15:36:13 -0700773 /**
Robert Carrd5c7dd62017-03-08 10:39:30 -0800774 * Called by native on RenderThread to notify that the view is no longer in the
Robert Carr33879132016-09-06 14:41:40 -0700775 * draw tree. UI thread is blocked at this point.
John Reckaa6e84f2016-06-16 15:36:13 -0700776 * @hide
777 */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800778 public final void surfacePositionLost_uiRtSync(long frameNumber) {
John Reckaa6e84f2016-06-16 15:36:13 -0700779 if (DEBUG) {
Robert Carr33879132016-09-06 14:41:40 -0700780 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
John Reckaa6e84f2016-06-16 15:36:13 -0700781 System.identityHashCode(this), frameNumber));
782 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800783 if (mSurfaceControl == null) {
John Reck474659c2016-06-27 07:56:37 -0700784 return;
785 }
John Reckf23a1b82016-06-22 14:23:31 -0700786 if (mRtHandlingPositionUpdates) {
787 mRtHandlingPositionUpdates = false;
788 // This callback will happen while the UI thread is blocked, so we can
789 // safely access other member variables at this time.
790 // So do what the UI thread would have done if RT wasn't handling position
791 // updates.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800792 if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
John Reckf23a1b82016-06-22 14:23:31 -0700793 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800794 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
John Reckf23a1b82016-06-22 14:23:31 -0700795 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800796 mScreenRect.left, mScreenRect.top,
797 mScreenRect.right, mScreenRect.bottom));
798 setParentSpaceRectangle(mScreenRect, frameNumber);
799 } catch (Exception ex) {
Robert Carr44ab5752017-03-20 21:47:11 -0700800 Log.e(TAG, "Exception configuring surface", ex);
John Reckf23a1b82016-06-22 14:23:31 -0700801 }
802 }
803 mRTLastReportedPosition.setEmpty();
804 }
John Reckaa6e84f2016-06-16 15:36:13 -0700805 }
806
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800807 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
808 SurfaceHolder.Callback callbacks[];
809 synchronized (mCallbacks) {
810 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
811 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700812 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800813 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700814 }
815
Derek Sollenberger7179b812010-03-22 13:41:20 -0400816 /**
Yohei Yukawa3b5011a2017-03-16 15:34:12 -0700817 * This method still exists only for compatibility reasons because some applications have relied
818 * on this method via reflection. See Issue 36345857 for details.
819 *
820 * @deprecated No platform code is using this method anymore.
821 * @hide
822 */
823 @Deprecated
824 public void setWindowType(int type) {
825 if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1) {
826 throw new UnsupportedOperationException(
827 "SurfaceView#setWindowType() has never been a public API.");
828 }
829
830 if (type == TYPE_APPLICATION_PANEL) {
831 Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
832 + "just to make the SurfaceView to be placed on top of its window, you must "
833 + "call setZOrderOnTop(true) instead.", new Throwable());
834 setZOrderOnTop(true);
835 return;
836 }
837 Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
838 + "type=" + type, new Throwable());
839 }
840
841 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -0400842 * Check to see if the surface has fixed size dimensions or if the surface's
843 * dimensions are dimensions are dependent on its current layout.
844 *
845 * @return true if the surface has dimensions that are fixed in size
846 * @hide
847 */
848 public boolean isFixedSize() {
849 return (mRequestedWidth != -1 || mRequestedHeight != -1);
850 }
851
Robert Carrd5c7dd62017-03-08 10:39:30 -0800852 private boolean isAboveParent() {
853 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700854 }
855
Igor Murashkina86ab6402013-08-30 12:58:36 -0700856 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700857 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -0700858
859 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700860 public boolean isCreating() {
861 return mIsCreating;
862 }
863
Igor Murashkina86ab6402013-08-30 12:58:36 -0700864 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700865 public void addCallback(Callback callback) {
866 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700867 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700868 // have only a couple callbacks, so it doesn't matter.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700869 if (mCallbacks.contains(callback) == false) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700870 mCallbacks.add(callback);
871 }
872 }
873 }
874
Igor Murashkina86ab6402013-08-30 12:58:36 -0700875 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700876 public void removeCallback(Callback callback) {
877 synchronized (mCallbacks) {
878 mCallbacks.remove(callback);
879 }
880 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700881
882 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700883 public void setFixedSize(int width, int height) {
884 if (mRequestedWidth != width || mRequestedHeight != height) {
885 mRequestedWidth = width;
886 mRequestedHeight = height;
887 requestLayout();
888 }
889 }
890
Igor Murashkina86ab6402013-08-30 12:58:36 -0700891 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700892 public void setSizeFromLayout() {
893 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
894 mRequestedWidth = mRequestedHeight = -1;
895 requestLayout();
896 }
897 }
898
Igor Murashkina86ab6402013-08-30 12:58:36 -0700899 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700900 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700901 // for backward compatibility reason, OPAQUE always
902 // means 565 for SurfaceView
903 if (format == PixelFormat.OPAQUE)
904 format = PixelFormat.RGB_565;
905
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700906 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800907 if (mSurfaceControl != null) {
908 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700909 }
910 }
911
Mathias Agopiand2112302010-12-07 19:38:17 -0800912 /**
913 * @deprecated setType is now ignored.
914 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700915 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -0800916 @Deprecated
917 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700918
Igor Murashkina86ab6402013-08-30 12:58:36 -0700919 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700920 public void setKeepScreenOn(boolean screenOn) {
921 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
922 msg.arg1 = screenOn ? 1 : 0;
923 mHandler.sendMessage(msg);
924 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700925
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700926 /**
927 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
928 *
929 * After drawing into the provided {@link Canvas}, the caller must
930 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
931 *
932 * The caller must redraw the entire surface.
933 * @return A canvas for drawing into the surface.
934 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700935 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700936 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -0700937 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700938 }
939
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700940 /**
941 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
942 *
943 * After drawing into the provided {@link Canvas}, the caller must
944 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
945 *
946 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
947 * to redraw. This function may choose to expand the dirty rectangle if for example
948 * the surface has been resized or if the previous contents of the surface were
949 * not available. The caller must redraw the entire dirty region as represented
950 * by the contents of the inOutDirty rectangle upon return from this function.
951 * The caller may also pass <code>null</code> instead, in the case where the
952 * entire surface should be redrawn.
953 * @return A canvas for drawing into the surface.
954 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700955 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700956 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -0700957 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700958 }
959
John Reck6bc70142016-10-26 16:49:17 -0700960 @Override
961 public Canvas lockHardwareCanvas() {
962 return internalLockCanvas(null, true);
963 }
964
965 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700966 mSurfaceLock.lock();
967
John Reckaa6e84f2016-06-16 15:36:13 -0700968 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -0800969 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700970
971 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800972 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700973 try {
John Reck6bc70142016-10-26 16:49:17 -0700974 if (hardware) {
975 c = mSurface.lockHardwareCanvas();
976 } else {
977 c = mSurface.lockCanvas(dirty);
978 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700979 } catch (Exception e) {
980 Log.e(LOG_TAG, "Exception locking surface", e);
981 }
982 }
983
John Reckaa6e84f2016-06-16 15:36:13 -0700984 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700985 if (c != null) {
986 mLastLockTime = SystemClock.uptimeMillis();
987 return c;
988 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700989
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700990 // If the Surface is not ready to be drawn, then return null,
991 // but throttle calls to this function so it isn't called more
992 // than every 100ms.
993 long now = SystemClock.uptimeMillis();
994 long nextTime = mLastLockTime + 100;
995 if (nextTime > now) {
996 try {
997 Thread.sleep(nextTime-now);
998 } catch (InterruptedException e) {
999 }
1000 now = SystemClock.uptimeMillis();
1001 }
1002 mLastLockTime = now;
1003 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -07001004
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001005 return null;
1006 }
1007
Mathias Agopian9ddf32a2013-04-17 15:04:47 -07001008 /**
1009 * Posts the new contents of the {@link Canvas} to the surface and
1010 * releases the {@link Canvas}.
1011 *
1012 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
1013 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07001014 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001015 public void unlockCanvasAndPost(Canvas canvas) {
1016 mSurface.unlockCanvasAndPost(canvas);
1017 mSurfaceLock.unlock();
1018 }
1019
Igor Murashkina86ab6402013-08-30 12:58:36 -07001020 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001021 public Surface getSurface() {
1022 return mSurface;
1023 }
1024
Igor Murashkina86ab6402013-08-30 12:58:36 -07001025 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001026 public Rect getSurfaceFrame() {
1027 return mSurfaceFrame;
1028 }
1029 };
1030}