blob: 824e035697fccd74c4c0289f2eff1c666bbcb1cd [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 Carr33879132016-09-06 14:41:40 -0700117 final Rect mTmpRect = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700118 final Configuration mConfiguration = new Configuration();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700119
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700120 static final int KEEP_SCREEN_ON_MSG = 1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800121 static final int DRAW_FINISHED_MSG = 2;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700122
Robert Carrd5c7dd62017-03-08 10:39:30 -0800123 int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700124
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700125 boolean mIsCreating = false;
John Reckf23a1b82016-06-22 14:23:31 -0700126 private volatile boolean mRtHandlingPositionUpdates = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700127
128 final Handler mHandler = new Handler() {
129 @Override
130 public void handleMessage(Message msg) {
131 switch (msg.what) {
132 case KEEP_SCREEN_ON_MSG: {
133 setKeepScreenOn(msg.arg1 != 0);
134 } break;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800135 case DRAW_FINISHED_MSG: {
136 mDrawFinished = true;
137 invalidate();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700138 } break;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700139 }
140 }
141 };
Igor Murashkina86ab6402013-08-30 12:58:36 -0700142
John Reckf6481082016-02-02 15:18:23 -0800143 private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700144 = new ViewTreeObserver.OnScrollChangedListener() {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700145 @Override
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700146 public void onScrollChanged() {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800147 updateSurface();
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700148 }
149 };
Igor Murashkina86ab6402013-08-30 12:58:36 -0700150
John Reckf6481082016-02-02 15:18:23 -0800151 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
152 new ViewTreeObserver.OnPreDrawListener() {
153 @Override
154 public boolean onPreDraw() {
155 // reposition ourselves where the surface is
156 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800157 updateSurface();
John Reckf6481082016-02-02 15:18:23 -0800158 return true;
159 }
160 };
161
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700162 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700163 boolean mWindowVisibility = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800164 boolean mLastWindowVisibility = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700165 boolean mViewVisibility = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700166 int mRequestedWidth = -1;
167 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700168 /* Set SurfaceView's format to 565 by default to maintain backward
169 * compatibility with applications assuming this format.
170 */
171 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700172
173 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800174 boolean mSurfaceCreated = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700175 long mLastLockTime = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700176
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700177 boolean mVisible = false;
Robert Carr64aadd02015-11-06 13:54:20 -0800178 int mWindowSpaceLeft = -1;
179 int mWindowSpaceTop = -1;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800180 int mSurfaceWidth = -1;
181 int mSurfaceHeight = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700182 int mFormat = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700183 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700184 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700185 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800186
Romain Guy01d5edc2011-01-28 11:28:53 -0800187 private boolean mGlobalListenersAdded;
Romain Guyf2499fa2011-01-26 18:31:23 -0800188
Robert Carrd5c7dd62017-03-08 10:39:30 -0800189 private int mSurfaceFlags = SurfaceControl.HIDDEN;
190
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700191 public SurfaceView(Context context) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400192 this(context, null);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700193 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700194
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700195 public SurfaceView(Context context, AttributeSet attrs) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400196 this(context, attrs, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700197 }
198
Alan Viverette617feb92013-09-09 18:09:13 -0700199 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viverette768ca7d2016-08-04 09:54:14 -0400200 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700201 }
202
203 public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
204 super(context, attrs, defStyleAttr, defStyleRes);
John Reck3acf03822016-11-02 11:14:47 -0700205 mRenderNode.requestPositionUpdates(this);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700206
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700207 setWillNotDraw(true);
208 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700209
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700210 /**
211 * Return the SurfaceHolder providing access and control over this
212 * SurfaceView's underlying surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700213 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700214 * @return SurfaceHolder The holder of the surface.
215 */
216 public SurfaceHolder getHolder() {
217 return mSurfaceHolder;
218 }
219
220 @Override
221 protected void onAttachedToWindow() {
222 super.onAttachedToWindow();
223 mParent.requestTransparentRegion(this);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700224 mViewVisibility = getVisibility() == VISIBLE;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800225 mRequestedVisible = mViewVisibility && mWindowVisibility;
Romain Guy01d5edc2011-01-28 11:28:53 -0800226
227 if (!mGlobalListenersAdded) {
228 ViewTreeObserver observer = getViewTreeObserver();
229 observer.addOnScrollChangedListener(mScrollChangedListener);
230 observer.addOnPreDrawListener(mDrawListener);
231 mGlobalListenersAdded = true;
232 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700233 }
234
235 @Override
236 protected void onWindowVisibilityChanged(int visibility) {
237 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700238 mWindowVisibility = visibility == VISIBLE;
239 mRequestedVisible = mWindowVisibility && mViewVisibility;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800240 updateSurface();
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700241 }
242
243 @Override
244 public void setVisibility(int visibility) {
245 super.setVisibility(visibility);
246 mViewVisibility = visibility == VISIBLE;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700247 boolean newRequestedVisible = mWindowVisibility && mViewVisibility;
248 if (newRequestedVisible != mRequestedVisible) {
249 // our base class (View) invalidates the layout only when
250 // we go from/to the GONE state. However, SurfaceView needs
251 // to request a re-layout when the visibility changes at all.
252 // This is needed because the transparent region is computed
253 // as part of the layout phase, and it changes (obviously) when
254 // the visibility changes.
255 requestLayout();
256 }
257 mRequestedVisible = newRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800258 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700259 }
Romain Guyafc3e112010-06-07 17:04:33 -0700260
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700261 @Override
John Reck77e4a522014-10-01 10:38:07 -0700262 protected void onDetachedFromWindow() {
Romain Guy01d5edc2011-01-28 11:28:53 -0800263 if (mGlobalListenersAdded) {
264 ViewTreeObserver observer = getViewTreeObserver();
265 observer.removeOnScrollChangedListener(mScrollChangedListener);
266 observer.removeOnPreDrawListener(mDrawListener);
267 mGlobalListenersAdded = false;
268 }
269
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700270 mRequestedVisible = false;
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800271
Robert Carrd5c7dd62017-03-08 10:39:30 -0800272 updateSurface();
273 if (mSurfaceControl != null) {
274 mSurfaceControl.destroy();
275 }
276 mSurfaceControl = null;
277
278 mHaveFrame = false;
John Reck77e4a522014-10-01 10:38:07 -0700279 super.onDetachedFromWindow();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700280 }
281
282 @Override
283 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800284 int width = mRequestedWidth >= 0
285 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
286 : getDefaultSize(0, widthMeasureSpec);
287 int height = mRequestedHeight >= 0
288 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
289 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700290 setMeasuredDimension(width, height);
291 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700292
Mathias Agopianef115302010-10-04 20:15:08 -0700293 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700294 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700295 protected boolean setFrame(int left, int top, int right, int bottom) {
296 boolean result = super.setFrame(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800297 updateSurface();
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700298 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700299 }
300
301 @Override
302 public boolean gatherTransparentRegion(Region region) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800303 if (isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700304 return super.gatherTransparentRegion(region);
305 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700306
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700307 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700308 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700309 // this view draws, remove it from the transparent region
310 opaque = super.gatherTransparentRegion(region);
311 } else if (region != null) {
312 int w = getWidth();
313 int h = getHeight();
314 if (w>0 && h>0) {
315 getLocationInWindow(mLocation);
316 // otherwise, punch a hole in the whole hierarchy
317 int l = mLocation[0];
318 int t = mLocation[1];
319 region.op(l, t, l+w, t+h, Region.Op.UNION);
320 }
321 }
322 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
323 opaque = false;
324 }
325 return opaque;
326 }
327
328 @Override
329 public void draw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800330 if (mDrawFinished && !isAboveParent()) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700331 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700332 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700333 // punch a whole in the view-hierarchy below us
334 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
335 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700336 }
337 super.draw(canvas);
338 }
339
340 @Override
341 protected void dispatchDraw(Canvas canvas) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800342 if (mDrawFinished && !isAboveParent()) {
343 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700344 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700345 // punch a whole in the view-hierarchy below us
346 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
347 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700348 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700349 super.dispatchDraw(canvas);
350 }
351
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700352 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700353 * Control whether the surface view's surface is placed on top of another
354 * regular surface view in the window (but still behind the window itself).
355 * This is typically used to place overlays on top of an underlying media
356 * surface view.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700357 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700358 * <p>Note that this must be set before the surface view's containing
359 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700360 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700361 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
362 */
363 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800364 mSubLayer = isMediaOverlay
365 ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700366 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700367
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700368 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700369 * Control whether the surface view's surface is placed on top of its
370 * window. Normally it is placed behind the window, to allow it to
371 * (for the most part) appear to composite with the views in the
372 * hierarchy. By setting this, you cause it to be placed above the
373 * window. This means that none of the contents of the window this
374 * SurfaceView is in will be visible on top of its surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700375 *
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700376 * <p>Note that this must be set before the surface view's containing
377 * window is attached to the window manager.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700378 *
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700379 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700380 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700381 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500382 if (onTop) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800383 mSubLayer = APPLICATION_PANEL_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500384 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800385 mSubLayer = APPLICATION_MEDIA_SUBLAYER;
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500386 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700387 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700388
389 /**
390 * Control whether the surface view's content should be treated as secure,
391 * preventing it from appearing in screenshots or from being viewed on
392 * non-secure displays.
393 *
394 * <p>Note that this must be set before the surface view's containing
395 * window is attached to the window manager.
396 *
397 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
398 *
399 * @param isSecure True if the surface view is secure.
400 */
401 public void setSecure(boolean isSecure) {
402 if (isSecure) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800403 mSurfaceFlags |= SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700404 } else {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800405 mSurfaceFlags &= ~SurfaceControl.SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700406 }
407 }
408
Robert Carrd5c7dd62017-03-08 10:39:30 -0800409 private Rect getParentSurfaceInsets() {
410 final ViewRootImpl root = getViewRootImpl();
411 if (root == null) {
412 return null;
413 } else {
414 return root.mWindowAttributes.surfaceInsets;
415 }
Jeff Tinker3896db12017-03-03 00:20:22 +0000416 }
417
Youngsang Cho9a22f0f2014-04-09 22:51:54 +0900418 /** @hide */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800419 protected void updateSurface() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700420 if (!mHaveFrame) {
421 return;
422 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800423 ViewRootImpl viewRoot = getViewRootImpl();
Robert Carrd5c7dd62017-03-08 10:39:30 -0800424 if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
425 return;
Joe Onorato168173a2009-08-12 21:40:29 -0700426 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700427
Robert Carrd5c7dd62017-03-08 10:39:30 -0800428 mTranslator = viewRoot.mTranslator;
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700429 if (mTranslator != null) {
430 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700431 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700432
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700433 int myWidth = mRequestedWidth;
434 if (myWidth <= 0) myWidth = getWidth();
435 int myHeight = mRequestedHeight;
436 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700437
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700438 final boolean formatChanged = mFormat != mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800439 final boolean creating = (mSurfaceControl == null || formatChanged)
440 && mRequestedVisible;
441 final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800442 final boolean visibleChanged = mVisible != mRequestedVisible;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800443 final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
Robert Carr49b593e2016-07-11 12:21:18 -0700444 boolean redrawNeeded = false;
445
Robert Carrd5c7dd62017-03-08 10:39:30 -0800446 if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
John Reckf6481082016-02-02 15:18:23 -0800447 getLocationInWindow(mLocation);
448
John Reckaa6e84f2016-06-16 15:36:13 -0700449 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
450 + "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700451 + " format=" + formatChanged + " size=" + sizeChanged
452 + " visible=" + visibleChanged
Robert Carr64aadd02015-11-06 13:54:20 -0800453 + " left=" + (mWindowSpaceLeft != mLocation[0])
454 + " top=" + (mWindowSpaceTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700455
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700456 try {
457 final boolean visible = mVisible = mRequestedVisible;
Robert Carr64aadd02015-11-06 13:54:20 -0800458 mWindowSpaceLeft = mLocation[0];
459 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800460 mSurfaceWidth = myWidth;
461 mSurfaceHeight = myHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700462 mFormat = mRequestedFormat;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800463 mLastWindowVisibility = mWindowVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700464
Robert Carrd5c7dd62017-03-08 10:39:30 -0800465 mScreenRect.left = mWindowSpaceLeft;
466 mScreenRect.top = mWindowSpaceTop;
467 mScreenRect.right = mWindowSpaceLeft + getWidth();
468 mScreenRect.bottom = mWindowSpaceTop + getHeight();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700469 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800470 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700471 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700472
Robert Carrd5c7dd62017-03-08 10:39:30 -0800473 final Rect surfaceInsets = getParentSurfaceInsets();
474 mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
475
476 if (creating) {
477 mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
478 mSurfaceControl = new SurfaceControl(mSurfaceSession,
479 "SurfaceView - " + viewRoot.getTitle().toString(),
480 mSurfaceWidth, mSurfaceHeight, mFormat,
481 mSurfaceFlags);
Robert Carr64aadd02015-11-06 13:54:20 -0800482 }
483
Robert Carrd5c7dd62017-03-08 10:39:30 -0800484 boolean realSizeChanged = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800485
Dianne Hackborn726426e2010-03-31 22:04:36 -0700486 mSurfaceLock.lock();
487 try {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700488 mDrawingStopped = !visible;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700489
John Reckaa6e84f2016-06-16 15:36:13 -0700490 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
491 + "Cur surface: " + mSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800492
Robert Carrd5c7dd62017-03-08 10:39:30 -0800493 SurfaceControl.openTransaction();
494 try {
495 mSurfaceControl.setLayer(mSubLayer);
496 if (mViewVisibility) {
497 mSurfaceControl.show();
498 } else {
499 mSurfaceControl.hide();
500 }
501
502 // While creating the surface, we will set it's initial
503 // geometry. Outside of that though, we should generally
504 // leave it to the RenderThread.
Robert Carr511719f2017-03-13 15:27:15 -0700505 //
506 // There is one more case when the buffer size changes we aren't yet
507 // prepared to sync (as even following the transaction applying
508 // we still need to latch a buffer).
509 // b/28866173
510 if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800511 mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
512 mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
513 0.0f, 0.0f,
514 mScreenRect.height() / (float) mSurfaceHeight);
515 }
516 if (sizeChanged) {
517 mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
518 }
519 } finally {
520 SurfaceControl.closeTransaction();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700521 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800522
Robert Carrd5c7dd62017-03-08 10:39:30 -0800523 if (sizeChanged || creating) {
524 redrawNeeded = true;
525 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800526
Dianne Hackborn726426e2010-03-31 22:04:36 -0700527 mSurfaceFrame.left = 0;
528 mSurfaceFrame.top = 0;
529 if (mTranslator == null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800530 mSurfaceFrame.right = mSurfaceWidth;
531 mSurfaceFrame.bottom = mSurfaceHeight;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700532 } else {
533 float appInvertedScale = mTranslator.applicationInvertedScale;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800534 mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
535 mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700536 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700537
Dianne Hackborn726426e2010-03-31 22:04:36 -0700538 final int surfaceWidth = mSurfaceFrame.right;
539 final int surfaceHeight = mSurfaceFrame.bottom;
540 realSizeChanged = mLastSurfaceWidth != surfaceWidth
541 || mLastSurfaceHeight != surfaceHeight;
542 mLastSurfaceWidth = surfaceWidth;
543 mLastSurfaceHeight = surfaceHeight;
544 } finally {
545 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700546 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700547
548 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800549 redrawNeeded |= visible && !mDrawFinished;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700550
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800551 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700552
Robert Carrd5c7dd62017-03-08 10:39:30 -0800553 final boolean surfaceChanged = creating;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800554 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
555 mSurfaceCreated = false;
556 if (mSurface.isValid()) {
John Reckaa6e84f2016-06-16 15:36:13 -0700557 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
558 + "visibleChanged -- surfaceDestroyed");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800559 callbacks = getSurfaceCallbacks();
560 for (SurfaceHolder.Callback c : callbacks) {
561 c.surfaceDestroyed(mSurfaceHolder);
562 }
Robert Carr387838b2016-09-07 14:12:44 -0700563 // Since Android N the same surface may be reused and given to us
564 // again by the system server at a later point. However
565 // as we didn't do this in previous releases, clients weren't
566 // necessarily required to clean up properly in
567 // surfaceDestroyed. This leads to problems for example when
568 // clients don't destroy their EGL context, and try
569 // and create a new one on the same surface following reuse.
570 // Since there is no valid use of the surface in-between
571 // surfaceDestroyed and surfaceCreated, we force a disconnect,
572 // so the next connect will always work if we end up reusing
573 // the surface.
John Reck6ba466f2016-09-30 14:30:04 -0700574 if (mSurface.isValid()) {
575 mSurface.forceScopedDisconnect();
576 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700577 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800578 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700579
Robert Carrd5c7dd62017-03-08 10:39:30 -0800580 if (creating) {
581 mSurface.copyFrom(mSurfaceControl);
582 }
583
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200584 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800585 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
586 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700587 mIsCreating = true;
John Reckaa6e84f2016-06-16 15:36:13 -0700588 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
589 + "visibleChanged -- surfaceCreated");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800590 if (callbacks == null) {
591 callbacks = getSurfaceCallbacks();
592 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700593 for (SurfaceHolder.Callback c : callbacks) {
594 c.surfaceCreated(mSurfaceHolder);
595 }
596 }
597 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700598 || visibleChanged || realSizeChanged) {
John Reckaa6e84f2016-06-16 15:36:13 -0700599 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
600 + "surfaceChanged -- format=" + mFormat
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800601 + " w=" + myWidth + " h=" + myHeight);
602 if (callbacks == null) {
603 callbacks = getSurfaceCallbacks();
604 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700605 for (SurfaceHolder.Callback c : callbacks) {
606 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
607 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700608 }
609 if (redrawNeeded) {
John Reckaa6e84f2016-06-16 15:36:13 -0700610 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
611 + "surfaceRedrawNeeded");
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800612 if (callbacks == null) {
613 callbacks = getSurfaceCallbacks();
614 }
Robert Carr25cfa132016-11-16 13:24:09 -0800615 SurfaceCallbackHelper sch =
Robert Carrd5c7dd62017-03-08 10:39:30 -0800616 new SurfaceCallbackHelper(this::onDrawFinished);
Robert Carr25cfa132016-11-16 13:24:09 -0800617 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700618 }
619 }
620 } finally {
621 mIsCreating = false;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800622 if (mSurfaceControl != null && !mSurfaceCreated) {
623 mSurfaceControl.destroy();
624 mSurfaceControl = null;
625 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700626 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800627 } catch (Exception ex) {
Rob Carr64e516f2015-10-29 00:20:45 +0000628 Log.e(TAG, "Exception from relayout", ex);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700629 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800630 if (DEBUG) Log.v(
Robert Carrd5c7dd62017-03-08 10:39:30 -0800631 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
632 + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
633 + ", frame=" + mSurfaceFrame);
John Reckf23a1b82016-06-22 14:23:31 -0700634 } else {
635 // Calculate the window position in case RT loses the window
636 // and we need to fallback to a UI-thread driven position update
Robert Carrd5c7dd62017-03-08 10:39:30 -0800637 getLocationInSurface(mLocation);
John Reckf6481082016-02-02 15:18:23 -0800638 final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
639 || mWindowSpaceTop != mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800640 final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
641 || getHeight() != mScreenRect.height();
John Reckf6481082016-02-02 15:18:23 -0800642 if (positionChanged || layoutSizeChanged) { // Only the position has changed
643 mWindowSpaceLeft = mLocation[0];
644 mWindowSpaceTop = mLocation[1];
Robert Carrd5c7dd62017-03-08 10:39:30 -0800645 // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
John Reckf6481082016-02-02 15:18:23 -0800646 // in view local space.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800647 mLocation[0] = getWidth();
648 mLocation[1] = getHeight();
Robert Carr64aadd02015-11-06 13:54:20 -0800649
Robert Carrd5c7dd62017-03-08 10:39:30 -0800650 mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
John Reckf057fb52016-04-15 13:46:29 -0700651 mLocation[0], mLocation[1]);
652
653 if (mTranslator != null) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800654 mTranslator.translateRectInAppWindowToScreen(mScreenRect);
John Reckf057fb52016-04-15 13:46:29 -0700655 }
656
John Reckf23a1b82016-06-22 14:23:31 -0700657 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
658 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800659 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
John Reckf23a1b82016-06-22 14:23:31 -0700660 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800661 mScreenRect.left, mScreenRect.top,
662 mScreenRect.right, mScreenRect.bottom));
663 setParentSpaceRectangle(mScreenRect, -1);
664 } catch (Exception ex) {
John Reckf23a1b82016-06-22 14:23:31 -0700665 Log.e(TAG, "Exception from relayout", ex);
666 }
John Reckf6481082016-02-02 15:18:23 -0800667 }
Rob Carr64e516f2015-10-29 00:20:45 +0000668 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700669 }
670 }
671
Robert Carrd5c7dd62017-03-08 10:39:30 -0800672 private void onDrawFinished() {
673 if (DEBUG) {
674 Log.i(TAG, System.identityHashCode(this) + " "
675 + "finishedDrawing");
676 }
677 mHandler.sendEmptyMessage(DRAW_FINISHED_MSG);
678 }
679
680 private void setParentSpaceRectangle(Rect position, long frameNumber) {
681 ViewRootImpl viewRoot = getViewRootImpl();
682
683 SurfaceControl.openTransaction();
684 try {
685 if (frameNumber > 0) {
686 mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber);
687 }
688 mSurfaceControl.setPosition(position.left, position.top);
689 mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth,
690 0.0f, 0.0f,
691 position.height() / (float) mSurfaceHeight);
692 } finally {
693 SurfaceControl.closeTransaction();
694 }
695 }
696
John Reckf6481082016-02-02 15:18:23 -0800697 private Rect mRTLastReportedPosition = new Rect();
698
699 /**
Robert Carr33879132016-09-06 14:41:40 -0700700 * Called by native by a Rendering Worker thread to update the window position
John Reckf6481082016-02-02 15:18:23 -0800701 * @hide
702 */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800703 public final void updateSurfacePosition_renderWorker(long frameNumber,
John Reckf6481082016-02-02 15:18:23 -0800704 int left, int top, int right, int bottom) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800705 if (mSurfaceControl == null) {
John Reckf6481082016-02-02 15:18:23 -0800706 return;
707 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800708
John Reckf23a1b82016-06-22 14:23:31 -0700709 // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
710 // its 2nd frame if RenderThread is running slowly could potentially see
711 // this as false, enter the branch, get pre-empted, then this comes along
712 // and reports a new position, then the UI thread resumes and reports
713 // its position. This could therefore be de-sync'd in that interval, but
714 // the synchronization would violate the rule that RT must never block
715 // on the UI thread which would open up potential deadlocks. The risk of
716 // a single-frame desync is therefore preferable for now.
717 mRtHandlingPositionUpdates = true;
John Reckf6481082016-02-02 15:18:23 -0800718 if (mRTLastReportedPosition.left == left
719 && mRTLastReportedPosition.top == top
720 && mRTLastReportedPosition.right == right
721 && mRTLastReportedPosition.bottom == bottom) {
722 return;
723 }
724 try {
725 if (DEBUG) {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800726 Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
John Reckaa6e84f2016-06-16 15:36:13 -0700727 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
728 frameNumber, left, top, right, bottom));
John Reckf6481082016-02-02 15:18:23 -0800729 }
Wonsik Kim5aec7b92017-03-07 17:15:50 -0800730 mRTLastReportedPosition.set(left, top, right, bottom);
Robert Carrd5c7dd62017-03-08 10:39:30 -0800731 setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
732 // Now overwrite mRTLastReportedPosition with our values
733 } catch (Exception ex) {
John Reckf6481082016-02-02 15:18:23 -0800734 Log.e(TAG, "Exception from repositionChild", ex);
735 }
736 }
737
John Reckaa6e84f2016-06-16 15:36:13 -0700738 /**
Robert Carrd5c7dd62017-03-08 10:39:30 -0800739 * Called by native on RenderThread to notify that the view is no longer in the
Robert Carr33879132016-09-06 14:41:40 -0700740 * draw tree. UI thread is blocked at this point.
John Reckaa6e84f2016-06-16 15:36:13 -0700741 * @hide
742 */
Robert Carrd5c7dd62017-03-08 10:39:30 -0800743 public final void surfacePositionLost_uiRtSync(long frameNumber) {
John Reckaa6e84f2016-06-16 15:36:13 -0700744 if (DEBUG) {
Robert Carr33879132016-09-06 14:41:40 -0700745 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
John Reckaa6e84f2016-06-16 15:36:13 -0700746 System.identityHashCode(this), frameNumber));
747 }
Robert Carrd5c7dd62017-03-08 10:39:30 -0800748 if (mSurfaceControl == null) {
John Reck474659c2016-06-27 07:56:37 -0700749 return;
750 }
John Reckf23a1b82016-06-22 14:23:31 -0700751 if (mRtHandlingPositionUpdates) {
752 mRtHandlingPositionUpdates = false;
753 // This callback will happen while the UI thread is blocked, so we can
754 // safely access other member variables at this time.
755 // So do what the UI thread would have done if RT wasn't handling position
756 // updates.
Robert Carrd5c7dd62017-03-08 10:39:30 -0800757 if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
John Reckf23a1b82016-06-22 14:23:31 -0700758 try {
Robert Carrd5c7dd62017-03-08 10:39:30 -0800759 if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
John Reckf23a1b82016-06-22 14:23:31 -0700760 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
Robert Carrd5c7dd62017-03-08 10:39:30 -0800761 mScreenRect.left, mScreenRect.top,
762 mScreenRect.right, mScreenRect.bottom));
763 setParentSpaceRectangle(mScreenRect, frameNumber);
764 } catch (Exception ex) {
John Reckf23a1b82016-06-22 14:23:31 -0700765 Log.e(TAG, "Exception from relayout", ex);
766 }
767 }
768 mRTLastReportedPosition.setEmpty();
769 }
John Reckaa6e84f2016-06-16 15:36:13 -0700770 }
771
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800772 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
773 SurfaceHolder.Callback callbacks[];
774 synchronized (mCallbacks) {
775 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
776 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700777 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800778 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700779 }
780
Derek Sollenberger7179b812010-03-22 13:41:20 -0400781 /**
Yohei Yukawa3b5011a2017-03-16 15:34:12 -0700782 * This method still exists only for compatibility reasons because some applications have relied
783 * on this method via reflection. See Issue 36345857 for details.
784 *
785 * @deprecated No platform code is using this method anymore.
786 * @hide
787 */
788 @Deprecated
789 public void setWindowType(int type) {
790 if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1) {
791 throw new UnsupportedOperationException(
792 "SurfaceView#setWindowType() has never been a public API.");
793 }
794
795 if (type == TYPE_APPLICATION_PANEL) {
796 Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
797 + "just to make the SurfaceView to be placed on top of its window, you must "
798 + "call setZOrderOnTop(true) instead.", new Throwable());
799 setZOrderOnTop(true);
800 return;
801 }
802 Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
803 + "type=" + type, new Throwable());
804 }
805
806 /**
Derek Sollenberger7179b812010-03-22 13:41:20 -0400807 * Check to see if the surface has fixed size dimensions or if the surface's
808 * dimensions are dimensions are dependent on its current layout.
809 *
810 * @return true if the surface has dimensions that are fixed in size
811 * @hide
812 */
813 public boolean isFixedSize() {
814 return (mRequestedWidth != -1 || mRequestedHeight != -1);
815 }
816
Robert Carrd5c7dd62017-03-08 10:39:30 -0800817 private boolean isAboveParent() {
818 return mSubLayer >= 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700819 }
820
Igor Murashkina86ab6402013-08-30 12:58:36 -0700821 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700822 private static final String LOG_TAG = "SurfaceHolder";
Igor Murashkina86ab6402013-08-30 12:58:36 -0700823
824 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700825 public boolean isCreating() {
826 return mIsCreating;
827 }
828
Igor Murashkina86ab6402013-08-30 12:58:36 -0700829 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700830 public void addCallback(Callback callback) {
831 synchronized (mCallbacks) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700832 // This is a linear search, but in practice we'll
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700833 // have only a couple callbacks, so it doesn't matter.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700834 if (mCallbacks.contains(callback) == false) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700835 mCallbacks.add(callback);
836 }
837 }
838 }
839
Igor Murashkina86ab6402013-08-30 12:58:36 -0700840 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700841 public void removeCallback(Callback callback) {
842 synchronized (mCallbacks) {
843 mCallbacks.remove(callback);
844 }
845 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700846
847 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700848 public void setFixedSize(int width, int height) {
849 if (mRequestedWidth != width || mRequestedHeight != height) {
850 mRequestedWidth = width;
851 mRequestedHeight = height;
852 requestLayout();
853 }
854 }
855
Igor Murashkina86ab6402013-08-30 12:58:36 -0700856 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700857 public void setSizeFromLayout() {
858 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
859 mRequestedWidth = mRequestedHeight = -1;
860 requestLayout();
861 }
862 }
863
Igor Murashkina86ab6402013-08-30 12:58:36 -0700864 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700865 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700866 // for backward compatibility reason, OPAQUE always
867 // means 565 for SurfaceView
868 if (format == PixelFormat.OPAQUE)
869 format = PixelFormat.RGB_565;
870
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700871 mRequestedFormat = format;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800872 if (mSurfaceControl != null) {
873 updateSurface();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700874 }
875 }
876
Mathias Agopiand2112302010-12-07 19:38:17 -0800877 /**
878 * @deprecated setType is now ignored.
879 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700880 @Override
Mathias Agopiand2112302010-12-07 19:38:17 -0800881 @Deprecated
882 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700883
Igor Murashkina86ab6402013-08-30 12:58:36 -0700884 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700885 public void setKeepScreenOn(boolean screenOn) {
886 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
887 msg.arg1 = screenOn ? 1 : 0;
888 mHandler.sendMessage(msg);
889 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700890
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700891 /**
892 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
893 *
894 * After drawing into the provided {@link Canvas}, the caller must
895 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
896 *
897 * The caller must redraw the entire surface.
898 * @return A canvas for drawing into the surface.
899 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700900 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700901 public Canvas lockCanvas() {
John Reck6bc70142016-10-26 16:49:17 -0700902 return internalLockCanvas(null, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700903 }
904
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700905 /**
906 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
907 *
908 * After drawing into the provided {@link Canvas}, the caller must
909 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
910 *
911 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
912 * to redraw. This function may choose to expand the dirty rectangle if for example
913 * the surface has been resized or if the previous contents of the surface were
914 * not available. The caller must redraw the entire dirty region as represented
915 * by the contents of the inOutDirty rectangle upon return from this function.
916 * The caller may also pass <code>null</code> instead, in the case where the
917 * entire surface should be redrawn.
918 * @return A canvas for drawing into the surface.
919 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700920 @Override
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700921 public Canvas lockCanvas(Rect inOutDirty) {
John Reck6bc70142016-10-26 16:49:17 -0700922 return internalLockCanvas(inOutDirty, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700923 }
924
John Reck6bc70142016-10-26 16:49:17 -0700925 @Override
926 public Canvas lockHardwareCanvas() {
927 return internalLockCanvas(null, true);
928 }
929
930 private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700931 mSurfaceLock.lock();
932
John Reckaa6e84f2016-06-16 15:36:13 -0700933 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
Robert Carrd5c7dd62017-03-08 10:39:30 -0800934 + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700935
936 Canvas c = null;
Robert Carrd5c7dd62017-03-08 10:39:30 -0800937 if (!mDrawingStopped && mSurfaceControl != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700938 try {
John Reck6bc70142016-10-26 16:49:17 -0700939 if (hardware) {
940 c = mSurface.lockHardwareCanvas();
941 } else {
942 c = mSurface.lockCanvas(dirty);
943 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700944 } catch (Exception e) {
945 Log.e(LOG_TAG, "Exception locking surface", e);
946 }
947 }
948
John Reckaa6e84f2016-06-16 15:36:13 -0700949 if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700950 if (c != null) {
951 mLastLockTime = SystemClock.uptimeMillis();
952 return c;
953 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700954
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700955 // If the Surface is not ready to be drawn, then return null,
956 // but throttle calls to this function so it isn't called more
957 // than every 100ms.
958 long now = SystemClock.uptimeMillis();
959 long nextTime = mLastLockTime + 100;
960 if (nextTime > now) {
961 try {
962 Thread.sleep(nextTime-now);
963 } catch (InterruptedException e) {
964 }
965 now = SystemClock.uptimeMillis();
966 }
967 mLastLockTime = now;
968 mSurfaceLock.unlock();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700969
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700970 return null;
971 }
972
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700973 /**
974 * Posts the new contents of the {@link Canvas} to the surface and
975 * releases the {@link Canvas}.
976 *
977 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
978 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700979 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700980 public void unlockCanvasAndPost(Canvas canvas) {
981 mSurface.unlockCanvasAndPost(canvas);
982 mSurfaceLock.unlock();
983 }
984
Igor Murashkina86ab6402013-08-30 12:58:36 -0700985 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700986 public Surface getSurface() {
987 return mSurface;
988 }
989
Igor Murashkina86ab6402013-08-30 12:58:36 -0700990 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700991 public Rect getSurfaceFrame() {
992 return mSurfaceFrame;
993 }
994 };
995}