blob: 6d320ef32b0daf1057921f9bf38783652bcf1411 [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
Robert Carrd5c7dd62017-03-08 10:39:30 -080019import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
20import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
21import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
22
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070023import android.content.Context;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070024import android.content.res.CompatibilityInfo.Translator;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070025import android.content.res.Configuration;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070026import android.graphics.Canvas;
27import android.graphics.PixelFormat;
28import android.graphics.PorterDuff;
29import android.graphics.Rect;
30import android.graphics.Region;
31import android.os.Handler;
32import android.os.Message;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070033import android.os.SystemClock;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070034import android.util.AttributeSet;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070035import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070036
Robert Carr25cfa132016-11-16 13:24:09 -080037import com.android.internal.view.SurfaceCallbackHelper;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070038
Jon Larimer9bdf5762009-01-02 18:55:15 -050039import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070040import java.util.concurrent.locks.ReentrantLock;
41
42/**
43 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
44 * You can control the format of this surface and, if you like, its size; the
45 * SurfaceView takes care of placing the surface at the correct location on the
46 * screen
Igor Murashkina86ab6402013-08-30 12:58:36 -070047 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070048 * <p>The surface is Z ordered so that it is behind the window holding its
49 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070050 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070051 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070052 * 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 -070053 * buttons on top of the Surface, though note however that it can have an
54 * impact on performance since a full alpha-blended composite will be performed
55 * each time the Surface changes.
Igor Murashkina86ab6402013-08-30 12:58:36 -070056 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070057 * <p> The transparent region that makes the surface visible is based on the
58 * layout positions in the view hierarchy. If the post-layout transform
59 * properties are used to draw a sibling view on top of the SurfaceView, the
60 * view may not be properly composited with the surface.
61 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070062 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
63 * which can be retrieved by calling {@link #getHolder}.
Igor Murashkina86ab6402013-08-30 12:58:36 -070064 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070065 * <p>The Surface will be created for you while the SurfaceView's window is
66 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
67 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
68 * Surface is created and destroyed as the window is shown and hidden.
Igor Murashkina86ab6402013-08-30 12:58:36 -070069 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070070 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070071 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070072 * this way, you need to be aware of some threading semantics:
Igor Murashkina86ab6402013-08-30 12:58:36 -070073 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070074 * <ul>
75 * <li> All SurfaceView and
76 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
77 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070078 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070079 * state that is also touched by the drawing thread.
80 * <li> You must ensure that the drawing thread only touches the underlying
81 * Surface while it is valid -- between
82 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
83 * and
84 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
85 * </ul>
Chris Craik6ee192f2016-05-17 14:29:10 -070086 *
87 * <p class="note"><strong>Note:</strong> Starting in platform version
88 * {@link android.os.Build.VERSION_CODES#N}, SurfaceView's window position is
89 * updated synchronously with other View rendering. This means that translating
90 * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
91 * artifacts may occur on previous versions of the platform when its window is
92 * positioned asynchronously.</p>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070093 */
94public class SurfaceView extends View {
Robert Carrd5c7dd62017-03-08 10:39:30 -080095 private static final String TAG = "SurfaceView";
96 private static final boolean DEBUG = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070097
98 final ArrayList<SurfaceHolder.Callback> mCallbacks
99 = new ArrayList<SurfaceHolder.Callback>();
100
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800101 final int[] mLocation = new int[2];
Igor Murashkina86ab6402013-08-30 12:58:36 -0700102
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700103 final ReentrantLock mSurfaceLock = new ReentrantLock();
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800104 final Surface mSurface = new Surface(); // Current surface in use
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700105 boolean mDrawingStopped = true;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800106 // We use this to track if the application has produced a frame
107 // in to the Surface. Up until that point, we should be careful not to punch
108 // holes.
109 boolean mDrawFinished = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700110
Robert Carrd5c7dd62017-03-08 10:39:30 -0800111 final Rect mScreenRect = new Rect();
112 SurfaceSession mSurfaceSession;
113
114 SurfaceControl mSurfaceControl;
Robert Carr33879132016-09-06 14:41:40 -0700115 final Rect mTmpRect = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700116 final Configuration mConfiguration = new Configuration();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700117
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700118 static final int KEEP_SCREEN_ON_MSG = 1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800119 static final int DRAW_FINISHED_MSG = 2;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700120
Robert Carrd5c7dd62017-03-08 10:39:30 -0800121 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700122
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700123 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700124 private volatile boolean mRtHandlingPositionUpdates = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700125
126 final Handler mHandler = new Handler() {
127 @Override
128 public void handleMessage(Message msg) {
129 switch (msg.what) {
130 case KEEP_SCREEN_ON_MSG: {
131 setKeepScreenOn(msg.arg1 != 0);
132 } break;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800133 case DRAW_FINISHED_MSG: {
134 mDrawFinished = true;
135 invalidate();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700136 } break;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700137 }
138 }
139 };
Igor Murashkina86ab6402013-08-30 12:58:36 -0700140
John Reckf6481082016-02-02 15:18:23 -0800141 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700142 = new ViewTreeObserver.OnScrollChangedListener() {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700143 @Override
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700144 public void onScrollChanged() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800145 updateSurface();
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700146 }
147 };
Igor Murashkina86ab6402013-08-30 12:58:36 -0700148
John Reckf6481082016-02-02 15:18:23 -0800149 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
150 new ViewTreeObserver.OnPreDrawListener() {
151 @Override
152 public boolean onPreDraw() {
153 // reposition ourselves where the surface is
154 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800155 updateSurface();
John Reckf6481082016-02-02 15:18:23 -0800156 return true;
157 }
158 };
159
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700160 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700161 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800162 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700163 boolean mViewVisibility = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700164 int mRequestedWidth = -1;
165 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700166 /* Set SurfaceView's format to 565 by default to maintain backward
167 * compatibility with applications assuming this format.
168 */
169 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700170
171 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800172 boolean mSurfaceCreated = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700173 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700174
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700175 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800176 int mWindowSpaceLeft = -1;
177 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800178 int mSurfaceWidth = -1;
179 int mSurfaceHeight = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700180 int mFormat = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700181 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700182 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700183 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800184
Romain Guy01d5edc2011-01-28 11:28:53 -0800185 private boolean mGlobalListenersAdded;
Romain Guyf2499fa2011-01-26 18:31:23 -0800186
Robert Carrd5c7dd62017-03-08 10:39:30 -0800187 private int mSurfaceFlags = SurfaceControl.HIDDEN;
188
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700189 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400190 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700191 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700192
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700193 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400194 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700195 }
196
Alan Viverette617feb92013-09-09 18:09:13 -0700197 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400198 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700199 }
200
201 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
202 super(context, attrs, defStyleAttr, defStyleRes);
John Reck3acf03822016-11-02 11:14:47 -0700203 mRenderNode.requestPositionUpdates(this);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700204
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700205 setWillNotDraw(true);
206 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700207
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700208 /**
209 * Return the SurfaceHolder providing access and control over this
210 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700211 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700212 * @return SurfaceHolder The holder of the surface.
213 */
214 public SurfaceHolder getHolder() {
215 return mSurfaceHolder;
216 }
217
218 @Override
219 protected void onAttachedToWindow() {
220 super.onAttachedToWindow();
221 mParent.requestTransparentRegion(this);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700222 mViewVisibility = getVisibility() == VISIBLE;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800223 mRequestedVisible = mViewVisibility && mWindowVisibility;
Romain Guy01d5edc2011-01-28 11:28:53 -0800224
225 if (!mGlobalListenersAdded) {
226 ViewTreeObserver observer = getViewTreeObserver();
227 observer.addOnScrollChangedListener(mScrollChangedListener);
228 observer.addOnPreDrawListener(mDrawListener);
229 mGlobalListenersAdded = true;
230 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700231 }
232
233 @Override
234 protected void onWindowVisibilityChanged(int visibility) {
235 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700236 mWindowVisibility = visibility == VISIBLE;
237 mRequestedVisible = mWindowVisibility && mViewVisibility;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800238 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700239 }
240
241 @Override
242 public void setVisibility(int visibility) {
243 super.setVisibility(visibility);
244 mViewVisibility = visibility == VISIBLE;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700245 boolean newRequestedVisible = mWindowVisibility && mViewVisibility;
246 if (newRequestedVisible != mRequestedVisible) {
247 // our base class (View) invalidates the layout only when
248 // we go from/to the GONE state. However, SurfaceView needs
249 // to request a re-layout when the visibility changes at all.
250 // This is needed because the transparent region is computed
251 // as part of the layout phase, and it changes (obviously) when
252 // the visibility changes.
253 requestLayout();
254 }
255 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800256 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700257 }
Romain Guyafc3e112010-06-07 17:04:33 -0700258
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700259 @Override
John Reck77e4a522014-10-01 10:38:07 -0700260 protected void onDetachedFromWindow() {
Romain Guy01d5edc2011-01-28 11:28:53 -0800261 if (mGlobalListenersAdded) {
262 ViewTreeObserver observer = getViewTreeObserver();
263 observer.removeOnScrollChangedListener(mScrollChangedListener);
264 observer.removeOnPreDrawListener(mDrawListener);
265 mGlobalListenersAdded = false;
266 }
267
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700268 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800269
Robert Carrd5c7dd62017-03-08 10:39:30 -0800270 updateSurface();
271 if (mSurfaceControl != null) {
272 mSurfaceControl.destroy();
273 }
274 mSurfaceControl = null;
275
276 mHaveFrame = false;
John Reck77e4a522014-10-01 10:38:07 -0700277 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700278 }
279
280 @Override
281 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800282 int width = mRequestedWidth >= 0
283 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
284 : getDefaultSize(0, widthMeasureSpec);
285 int height = mRequestedHeight >= 0
286 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
287 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700288 setMeasuredDimension(width, height);
289 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700290
Mathias Agopianef115302010-10-04 20:15:08 -0700291 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700292 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700293 protected boolean setFrame(int left, int top, int right, int bottom) {
294 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800295 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700296 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700297 }
298
299 @Override
300 public boolean gatherTransparentRegion(Region region) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800301 if (isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700302 return super.gatherTransparentRegion(region);
303 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700304
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700305 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700306 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700307 // this view draws, remove it from the transparent region
308 opaque = super.gatherTransparentRegion(region);
309 } else if (region != null) {
310 int w = getWidth();
311 int h = getHeight();
312 if (w>0 && h>0) {
313 getLocationInWindow(mLocation);
314 // otherwise, punch a hole in the whole hierarchy
315 int l = mLocation[0];
316 int t = mLocation[1];
317 region.op(l, t, l+w, t+h, Region.Op.UNION);
318 }
319 }
320 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
321 opaque = false;
322 }
323 return opaque;
324 }
325
326 @Override
327 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800328 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700329 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700330 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700331 // punch a whole in the view-hierarchy below us
332 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
333 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700334 }
335 super.draw(canvas);
336 }
337
338 @Override
339 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800340 if (mDrawFinished && !isAboveParent()) {
341 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700342 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700343 // punch a whole in the view-hierarchy below us
344 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
345 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700346 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700347 super.dispatchDraw(canvas);
348 }
349
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700350 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700351 * Control whether the surface view's surface is placed on top of another
352 * regular surface view in the window (but still behind the window itself).
353 * This is typically used to place overlays on top of an underlying media
354 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700355 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700356 * <p>Note that this must be set before the surface view's containing
357 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700358 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700359 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
360 */
361 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800362 mSubLayer = isMediaOverlay
363 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700364 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700365
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700366 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700367 * Control whether the surface view's surface is placed on top of its
368 * window. Normally it is placed behind the window, to allow it to
369 * (for the most part) appear to composite with the views in the
370 * hierarchy. By setting this, you cause it to be placed above the
371 * window. This means that none of the contents of the window this
372 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700373 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700374 * <p>Note that this must be set before the surface view's containing
375 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700376 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700377 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700378 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700379 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500380 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800381 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500382 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800383 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500384 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700385 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700386
387 /**
388 * Control whether the surface view's content should be treated as secure,
389 * preventing it from appearing in screenshots or from being viewed on
390 * non-secure displays.
391 *
392 * <p>Note that this must be set before the surface view's containing
393 * window is attached to the window manager.
394 *
395 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
396 *
397 * @param isSecure True if the surface view is secure.
398 */
399 public void setSecure(boolean isSecure) {
400 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800401 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700402 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800403 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700404 }
405 }
406
Robert Carrd5c7dd62017-03-08 10:39:30 -0800407 private Rect getParentSurfaceInsets() {
408 final ViewRootImpl root = getViewRootImpl();
409 if (root == null) {
410 return null;
411 } else {
412 return root.mWindowAttributes.surfaceInsets;
413 }
Jeff Tinker3896db12017-03-03 00:20:22 +0000414 }
415
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900416 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800417 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700418 if (!mHaveFrame) {
419 return;
420 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800421 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800422 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
423 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700424 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700425
Robert Carrd5c7dd62017-03-08 10:39:30 -0800426 mTranslator = viewRoot.mTranslator;
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700427 if (mTranslator != null) {
428 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700429 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700430
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700431 int myWidth = mRequestedWidth;
432 if (myWidth <= 0) myWidth = getWidth();
433 int myHeight = mRequestedHeight;
434 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700435
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700436 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800437 final boolean creating = (mSurfaceControl == null || formatChanged)
438 && mRequestedVisible;
439 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800440 final boolean visibleChanged = mVisible != mRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800441 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700442 boolean redrawNeeded = false;
443
Robert Carrd5c7dd62017-03-08 10:39:30 -0800444 if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800445 getLocationInWindow(mLocation);
446
John Reckaa6e84f2016-06-16 15:36:13 -0700447 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
448 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700449 + " format=" + formatChanged + " size=" + sizeChanged
450 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800451 + " left=" + (mWindowSpaceLeft != mLocation[0])
452 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700453
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700454 try {
455 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800456 mWindowSpaceLeft = mLocation[0];
457 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800458 mSurfaceWidth = myWidth;
459 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700460 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800461 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700462
Robert Carrd5c7dd62017-03-08 10:39:30 -0800463 mScreenRect.left = mWindowSpaceLeft;
464 mScreenRect.top = mWindowSpaceTop;
465 mScreenRect.right = mWindowSpaceLeft + getWidth();
466 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700467 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800468 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700469 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700470
Robert Carrd5c7dd62017-03-08 10:39:30 -0800471 final Rect surfaceInsets = getParentSurfaceInsets();
472 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
473
474 if (creating) {
475 mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
476 mSurfaceControl = new SurfaceControl(mSurfaceSession,
477 "SurfaceView - " + viewRoot.getTitle().toString(),
478 mSurfaceWidth, mSurfaceHeight, mFormat,
479 mSurfaceFlags);
Robert Carr64aadd02015-11-06 13:54:20 -0800480 }
481
Robert Carrd5c7dd62017-03-08 10:39:30 -0800482 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800483
Dianne Hackborn726426e2010-03-31 22:04:36 -0700484 mSurfaceLock.lock();
485 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700486 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700487
John Reckaa6e84f2016-06-16 15:36:13 -0700488 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
489 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800490
Robert Carrd5c7dd62017-03-08 10:39:30 -0800491 SurfaceControl.openTransaction();
492 try {
493 mSurfaceControl.setLayer(mSubLayer);
494 if (mViewVisibility) {
495 mSurfaceControl.show();
496 } else {
497 mSurfaceControl.hide();
498 }
499
500 // While creating the surface, we will set it's initial
501 // geometry. Outside of that though, we should generally
502 // leave it to the RenderThread.
Robert Carr511719f2017-03-13 15:27:15 -0700503 //
504 // There is one more case when the buffer size changes we aren't yet
505 // prepared to sync (as even following the transaction applying
506 // we still need to latch a buffer).
507 // b/28866173
508 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800509 mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
510 mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
511 0.0f, 0.0f,
512 mScreenRect.height() / (float) mSurfaceHeight);
513 }
514 if (sizeChanged) {
515 mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
516 }
517 } finally {
518 SurfaceControl.closeTransaction();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700519 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800520
Robert Carrd5c7dd62017-03-08 10:39:30 -0800521 if (sizeChanged || creating) {
522 redrawNeeded = true;
523 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800524
Dianne Hackborn726426e2010-03-31 22:04:36 -0700525 mSurfaceFrame.left = 0;
526 mSurfaceFrame.top = 0;
527 if (mTranslator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800528 mSurfaceFrame.right = mSurfaceWidth;
529 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700530 } else {
531 float appInvertedScale = mTranslator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800532 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
533 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700534 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700535
Dianne Hackborn726426e2010-03-31 22:04:36 -0700536 final int surfaceWidth = mSurfaceFrame.right;
537 final int surfaceHeight = mSurfaceFrame.bottom;
538 realSizeChanged = mLastSurfaceWidth != surfaceWidth
539 || mLastSurfaceHeight != surfaceHeight;
540 mLastSurfaceWidth = surfaceWidth;
541 mLastSurfaceHeight = surfaceHeight;
542 } finally {
543 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700544 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700545
546 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800547 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700548
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800549 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700550
Robert Carrd5c7dd62017-03-08 10:39:30 -0800551 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800552 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
553 mSurfaceCreated = false;
554 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700555 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
556 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800557 callbacks = getSurfaceCallbacks();
558 for (SurfaceHolder.Callback c : callbacks) {
559 c.surfaceDestroyed(mSurfaceHolder);
560 }
Robert Carr387838b2016-09-07 14:12:44 -0700561 // Since Android N the same surface may be reused and given to us
562 // again by the system server at a later point. However
563 // as we didn't do this in previous releases, clients weren't
564 // necessarily required to clean up properly in
565 // surfaceDestroyed. This leads to problems for example when
566 // clients don't destroy their EGL context, and try
567 // and create a new one on the same surface following reuse.
568 // Since there is no valid use of the surface in-between
569 // surfaceDestroyed and surfaceCreated, we force a disconnect,
570 // so the next connect will always work if we end up reusing
571 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700572 if (mSurface.isValid()) {
573 mSurface.forceScopedDisconnect();
574 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700575 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800576 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700577
Robert Carrd5c7dd62017-03-08 10:39:30 -0800578 if (creating) {
579 mSurface.copyFrom(mSurfaceControl);
580 }
581
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200582 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800583 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
584 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700585 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700586 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
587 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800588 if (callbacks == null) {
589 callbacks = getSurfaceCallbacks();
590 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700591 for (SurfaceHolder.Callback c : callbacks) {
592 c.surfaceCreated(mSurfaceHolder);
593 }
594 }
595 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700596 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700597 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
598 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800599 + " w=" + myWidth + " h=" + myHeight);
600 if (callbacks == null) {
601 callbacks = getSurfaceCallbacks();
602 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700603 for (SurfaceHolder.Callback c : callbacks) {
604 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
605 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700606 }
607 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -0700608 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
609 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800610 if (callbacks == null) {
611 callbacks = getSurfaceCallbacks();
612 }
Robert Carr25cfa132016-11-16 13:24:09 -0800613 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -0800614 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -0800615 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700616 }
617 }
618 } finally {
619 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800620 if (mSurfaceControl != null && !mSurfaceCreated) {
621 mSurfaceControl.destroy();
622 mSurfaceControl = null;
623 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700624 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800625 } catch (Exception ex) {
Rob Carr64e516f2015-10-29 00:20:45 +0000626 Log.e(TAG, "Exception from relayout", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700627 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800628 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -0800629 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
630 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
631 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -0700632 } else {
633 // Calculate the window position in case RT loses the window
634 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -0800635 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -0800636 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
637 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800638 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
639 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -0800640 if (positionChanged || layoutSizeChanged) { // Only the position has changed
641 mWindowSpaceLeft = mLocation[0];
642 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800643 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -0800644 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800645 mLocation[0] = getWidth();
646 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -0800647
Robert Carrd5c7dd62017-03-08 10:39:30 -0800648 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
John Reckf057fb52016-04-15 13:46:29 -0700649 mLocation[0], mLocation[1]);
650
651 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800652 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -0700653 }
654
John Reckf23a1b82016-06-22 14:23:31 -0700655 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
656 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800657 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
John Reckf23a1b82016-06-22 14:23:31 -0700658 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800659 mScreenRect.left, mScreenRect.top,
660 mScreenRect.right, mScreenRect.bottom));
661 setParentSpaceRectangle(mScreenRect, -1);
662 } catch (Exception ex) {
John Reckf23a1b82016-06-22 14:23:31 -0700663 Log.e(TAG, "Exception from relayout", ex);
664 }
John Reckf6481082016-02-02 15:18:23 -0800665 }
Rob Carr64e516f2015-10-29 00:20:45 +0000666 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700667 }
668 }
669
Robert Carrd5c7dd62017-03-08 10:39:30 -0800670 private void onDrawFinished() {
671 if (DEBUG) {
672 Log.i(TAG, System.identityHashCode(this) + " "
673 + "finishedDrawing");
674 }
675 mHandler.sendEmptyMessage(DRAW_FINISHED_MSG);
676 }
677
678 private void setParentSpaceRectangle(Rect position, long frameNumber) {
679 ViewRootImpl viewRoot = getViewRootImpl();
680
681 SurfaceControl.openTransaction();
682 try {
683 if (frameNumber > 0) {
684 mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber);
685 }
686 mSurfaceControl.setPosition(position.left, position.top);
687 mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth,
688 0.0f, 0.0f,
689 position.height() / (float) mSurfaceHeight);
690 } finally {
691 SurfaceControl.closeTransaction();
692 }
693 }
694
John Reckf6481082016-02-02 15:18:23 -0800695 private Rect mRTLastReportedPosition = new Rect();
696
697 /**
Robert Carr33879132016-09-06 14:41:40 -0700698 * Called by native by a Rendering Worker thread to update the window position
John Reckf6481082016-02-02 15:18:23 -0800699 * @hide
700 */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800701 public final void updateSurfacePosition_renderWorker(long frameNumber,
John Reckf6481082016-02-02 15:18:23 -0800702 int left, int top, int right, int bottom) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800703 if (mSurfaceControl == null) {
John Reckf6481082016-02-02 15:18:23 -0800704 return;
705 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800706
John Reckf23a1b82016-06-22 14:23:31 -0700707 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
708 // its 2nd frame if RenderThread is running slowly could potentially see
709 // this as false, enter the branch, get pre-empted, then this comes along
710 // and reports a new position, then the UI thread resumes and reports
711 // its position. This could therefore be de-sync'd in that interval, but
712 // the synchronization would violate the rule that RT must never block
713 // on the UI thread which would open up potential deadlocks. The risk of
714 // a single-frame desync is therefore preferable for now.
715 mRtHandlingPositionUpdates = true;
John Reckf6481082016-02-02 15:18:23 -0800716 if (mRTLastReportedPosition.left == left
717 && mRTLastReportedPosition.top == top
718 && mRTLastReportedPosition.right == right
719 && mRTLastReportedPosition.bottom == bottom) {
720 return;
721 }
722 try {
723 if (DEBUG) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800724 Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
John Reckaa6e84f2016-06-16 15:36:13 -0700725 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
726 frameNumber, left, top, right, bottom));
John Reckf6481082016-02-02 15:18:23 -0800727 }
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800728 mRTLastReportedPosition.set(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800729 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
730 // Now overwrite mRTLastReportedPosition with our values
731 } catch (Exception ex) {
John Reckf6481082016-02-02 15:18:23 -0800732 Log.e(TAG, "Exception from repositionChild", ex);
733 }
734 }
735
John Reckaa6e84f2016-06-16 15:36:13 -0700736 /**
Robert Carrd5c7dd62017-03-08 10:39:30 -0800737 * Called by native on RenderThread to notify that the view is no longer in the
Robert Carr33879132016-09-06 14:41:40 -0700738 * draw tree. UI thread is blocked at this point.
John Reckaa6e84f2016-06-16 15:36:13 -0700739 * @hide
740 */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800741 public final void surfacePositionLost_uiRtSync(long frameNumber) {
John Reckaa6e84f2016-06-16 15:36:13 -0700742 if (DEBUG) {
Robert Carr33879132016-09-06 14:41:40 -0700743 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
John Reckaa6e84f2016-06-16 15:36:13 -0700744 System.identityHashCode(this), frameNumber));
745 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800746 if (mSurfaceControl == null) {
John Reck474659c2016-06-27 07:56:37 -0700747 return;
748 }
John Reckf23a1b82016-06-22 14:23:31 -0700749 if (mRtHandlingPositionUpdates) {
750 mRtHandlingPositionUpdates = false;
751 // This callback will happen while the UI thread is blocked, so we can
752 // safely access other member variables at this time.
753 // So do what the UI thread would have done if RT wasn't handling position
754 // updates.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800755 if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
John Reckf23a1b82016-06-22 14:23:31 -0700756 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800757 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
John Reckf23a1b82016-06-22 14:23:31 -0700758 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800759 mScreenRect.left, mScreenRect.top,
760 mScreenRect.right, mScreenRect.bottom));
761 setParentSpaceRectangle(mScreenRect, frameNumber);
762 } catch (Exception ex) {
John Reckf23a1b82016-06-22 14:23:31 -0700763 Log.e(TAG, "Exception from relayout", ex);
764 }
765 }
766 mRTLastReportedPosition.setEmpty();
767 }
John Reckaa6e84f2016-06-16 15:36:13 -0700768 }
769
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800770 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
771 SurfaceHolder.Callback callbacks[];
772 synchronized (mCallbacks) {
773 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
774 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700775 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800776 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700777 }
778
Derek Sollenberger7179b812010-03-22 13:41:20 -0400779 /**
780 * Check to see if the surface has fixed size dimensions or if the surface's
781 * dimensions are dimensions are dependent on its current layout.
782 *
783 * @return true if the surface has dimensions that are fixed in size
784 * @hide
785 */
786 public boolean isFixedSize() {
787 return (mRequestedWidth != -1 || mRequestedHeight != -1);
788 }
789
Robert Carrd5c7dd62017-03-08 10:39:30 -0800790 private boolean isAboveParent() {
791 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700792 }
793
Igor Murashkina86ab6402013-08-30 12:58:36 -0700794 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700795 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -0700796
797 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700798 public boolean isCreating() {
799 return mIsCreating;
800 }
801
Igor Murashkina86ab6402013-08-30 12:58:36 -0700802 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700803 public void addCallback(Callback callback) {
804 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700805 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700806 // have only a couple callbacks, so it doesn't matter.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700807 if (mCallbacks.contains(callback) == false) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700808 mCallbacks.add(callback);
809 }
810 }
811 }
812
Igor Murashkina86ab6402013-08-30 12:58:36 -0700813 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700814 public void removeCallback(Callback callback) {
815 synchronized (mCallbacks) {
816 mCallbacks.remove(callback);
817 }
818 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700819
820 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700821 public void setFixedSize(int width, int height) {
822 if (mRequestedWidth != width || mRequestedHeight != height) {
823 mRequestedWidth = width;
824 mRequestedHeight = height;
825 requestLayout();
826 }
827 }
828
Igor Murashkina86ab6402013-08-30 12:58:36 -0700829 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700830 public void setSizeFromLayout() {
831 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
832 mRequestedWidth = mRequestedHeight = -1;
833 requestLayout();
834 }
835 }
836
Igor Murashkina86ab6402013-08-30 12:58:36 -0700837 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700838 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700839 // for backward compatibility reason, OPAQUE always
840 // means 565 for SurfaceView
841 if (format == PixelFormat.OPAQUE)
842 format = PixelFormat.RGB_565;
843
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700844 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800845 if (mSurfaceControl != null) {
846 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700847 }
848 }
849
Mathias Agopiand2112302010-12-07 19:38:17 -0800850 /**
851 * @deprecated setType is now ignored.
852 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700853 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -0800854 @Deprecated
855 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700856
Igor Murashkina86ab6402013-08-30 12:58:36 -0700857 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700858 public void setKeepScreenOn(boolean screenOn) {
859 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
860 msg.arg1 = screenOn ? 1 : 0;
861 mHandler.sendMessage(msg);
862 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700863
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700864 /**
865 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
866 *
867 * After drawing into the provided {@link Canvas}, the caller must
868 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
869 *
870 * The caller must redraw the entire surface.
871 * @return A canvas for drawing into the surface.
872 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700873 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700874 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -0700875 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700876 }
877
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700878 /**
879 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
880 *
881 * After drawing into the provided {@link Canvas}, the caller must
882 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
883 *
884 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
885 * to redraw. This function may choose to expand the dirty rectangle if for example
886 * the surface has been resized or if the previous contents of the surface were
887 * not available. The caller must redraw the entire dirty region as represented
888 * by the contents of the inOutDirty rectangle upon return from this function.
889 * The caller may also pass <code>null</code> instead, in the case where the
890 * entire surface should be redrawn.
891 * @return A canvas for drawing into the surface.
892 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700893 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700894 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -0700895 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700896 }
897
John Reck6bc70142016-10-26 16:49:17 -0700898 @Override
899 public Canvas lockHardwareCanvas() {
900 return internalLockCanvas(null, true);
901 }
902
903 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700904 mSurfaceLock.lock();
905
John Reckaa6e84f2016-06-16 15:36:13 -0700906 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -0800907 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700908
909 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800910 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700911 try {
John Reck6bc70142016-10-26 16:49:17 -0700912 if (hardware) {
913 c = mSurface.lockHardwareCanvas();
914 } else {
915 c = mSurface.lockCanvas(dirty);
916 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700917 } catch (Exception e) {
918 Log.e(LOG_TAG, "Exception locking surface", e);
919 }
920 }
921
John Reckaa6e84f2016-06-16 15:36:13 -0700922 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700923 if (c != null) {
924 mLastLockTime = SystemClock.uptimeMillis();
925 return c;
926 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700927
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700928 // If the Surface is not ready to be drawn, then return null,
929 // but throttle calls to this function so it isn't called more
930 // than every 100ms.
931 long now = SystemClock.uptimeMillis();
932 long nextTime = mLastLockTime + 100;
933 if (nextTime > now) {
934 try {
935 Thread.sleep(nextTime-now);
936 } catch (InterruptedException e) {
937 }
938 now = SystemClock.uptimeMillis();
939 }
940 mLastLockTime = now;
941 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700942
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700943 return null;
944 }
945
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700946 /**
947 * Posts the new contents of the {@link Canvas} to the surface and
948 * releases the {@link Canvas}.
949 *
950 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
951 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700952 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700953 public void unlockCanvasAndPost(Canvas canvas) {
954 mSurface.unlockCanvasAndPost(canvas);
955 mSurfaceLock.unlock();
956 }
957
Igor Murashkina86ab6402013-08-30 12:58:36 -0700958 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700959 public Surface getSurface() {
960 return mSurface;
961 }
962
Igor Murashkina86ab6402013-08-30 12:58:36 -0700963 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700964 public Rect getSurfaceFrame() {
965 return mSurfaceFrame;
966 }
967 };
968}