blob: 8b2b556d052441791ec3f6972c0383042c2f188b [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
Dianne Hackborn72c82ab2009-08-11 21:13:54 -070019import com.android.internal.view.BaseIWindow;
20
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070021import android.content.Context;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080022import android.content.res.Configuration;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070023import android.content.res.CompatibilityInfo.Translator;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070024import android.graphics.Canvas;
25import android.graphics.PixelFormat;
26import android.graphics.PorterDuff;
27import android.graphics.Rect;
28import android.graphics.Region;
29import android.os.Handler;
30import android.os.Message;
31import android.os.RemoteException;
32import android.os.SystemClock;
33import android.os.ParcelFileDescriptor;
34import 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
Jon Larimer9bdf5762009-01-02 18:55:15 -050037import java.lang.ref.WeakReference;
38import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070039import java.util.concurrent.locks.ReentrantLock;
40
41/**
42 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
43 * You can control the format of this surface and, if you like, its size; the
44 * SurfaceView takes care of placing the surface at the correct location on the
45 * screen
46 *
47 * <p>The surface is Z ordered so that it is behind the window holding its
48 * SurfaceView; the SurfaceView punches a hole in its window to allow its
Jesse Hallc9f345f2012-09-26 11:55:16 -070049 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070050 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070051 * 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 -070052 * buttons on top of the Surface, though note however that it can have an
53 * impact on performance since a full alpha-blended composite will be performed
54 * each time the Surface changes.
55 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070056 * <p> The transparent region that makes the surface visible is based on the
57 * layout positions in the view hierarchy. If the post-layout transform
58 * properties are used to draw a sibling view on top of the SurfaceView, the
59 * view may not be properly composited with the surface.
60 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070061 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
62 * which can be retrieved by calling {@link #getHolder}.
63 *
64 * <p>The Surface will be created for you while the SurfaceView's window is
65 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
66 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
67 * Surface is created and destroyed as the window is shown and hidden.
68 *
69 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070070 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070071 * this way, you need to be aware of some threading semantics:
72 *
73 * <ul>
74 * <li> All SurfaceView and
75 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
76 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070077 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070078 * state that is also touched by the drawing thread.
79 * <li> You must ensure that the drawing thread only touches the underlying
80 * Surface while it is valid -- between
81 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
82 * and
83 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
84 * </ul>
85 */
86public class SurfaceView extends View {
87 static private final String TAG = "SurfaceView";
88 static private final boolean DEBUG = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070089
90 final ArrayList<SurfaceHolder.Callback> mCallbacks
91 = new ArrayList<SurfaceHolder.Callback>();
92
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080093 final int[] mLocation = new int[2];
94
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070095 final ReentrantLock mSurfaceLock = new ReentrantLock();
Dianne Hackborn61566cc2011-12-02 23:31:52 -080096 final Surface mSurface = new Surface(); // Current surface in use
97 final Surface mNewSurface = new Surface(); // New surface we are switching to
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070098 boolean mDrawingStopped = true;
99
100 final WindowManager.LayoutParams mLayout
101 = new WindowManager.LayoutParams();
102 IWindowSession mSession;
103 MyWindow mWindow;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800104 final Rect mVisibleInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700105 final Rect mWinFrame = new Rect();
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800106 final Rect mOverscanInsets = new Rect();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800107 final Rect mContentInsets = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700108 final Configuration mConfiguration = new Configuration();
109
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700110 static final int KEEP_SCREEN_ON_MSG = 1;
111 static final int GET_NEW_SURFACE_MSG = 2;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700112 static final int UPDATE_WINDOW_MSG = 3;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700113
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700114 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
115
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700116 boolean mIsCreating = false;
117
118 final Handler mHandler = new Handler() {
119 @Override
120 public void handleMessage(Message msg) {
121 switch (msg.what) {
122 case KEEP_SCREEN_ON_MSG: {
123 setKeepScreenOn(msg.arg1 != 0);
124 } break;
125 case GET_NEW_SURFACE_MSG: {
126 handleGetNewSurface();
127 } break;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700128 case UPDATE_WINDOW_MSG: {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700129 updateWindow(false, false);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700130 } break;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700131 }
132 }
133 };
134
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700135 final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
136 = new ViewTreeObserver.OnScrollChangedListener() {
137 public void onScrollChanged() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700138 updateWindow(false, false);
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700139 }
140 };
141
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700142 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700143 boolean mWindowVisibility = false;
144 boolean mViewVisibility = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700145 int mRequestedWidth = -1;
146 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700147 /* Set SurfaceView's format to 565 by default to maintain backward
148 * compatibility with applications assuming this format.
149 */
150 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700151
152 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800153 boolean mSurfaceCreated = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700154 long mLastLockTime = 0;
155
156 boolean mVisible = false;
157 int mLeft = -1;
158 int mTop = -1;
159 int mWidth = -1;
160 int mHeight = -1;
161 int mFormat = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700162 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700163 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
164 boolean mUpdateWindowNeeded;
165 boolean mReportDrawNeeded;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700166 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800167
168 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
169 new ViewTreeObserver.OnPreDrawListener() {
170 @Override
171 public boolean onPreDraw() {
172 // reposition ourselves where the surface is
Romain Guy0c756222011-01-26 18:45:28 -0800173 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Romain Guyf2499fa2011-01-26 18:31:23 -0800174 updateWindow(false, false);
175 return true;
176 }
177 };
Romain Guy01d5edc2011-01-28 11:28:53 -0800178 private boolean mGlobalListenersAdded;
Romain Guyf2499fa2011-01-26 18:31:23 -0800179
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700180 public SurfaceView(Context context) {
181 super(context);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700182 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700183 }
184
185 public SurfaceView(Context context, AttributeSet attrs) {
186 super(context, attrs);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700187 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700188 }
189
190 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
191 super(context, attrs, defStyle);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700192 init();
193 }
194
195 private void init() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700196 setWillNotDraw(true);
197 }
198
199 /**
200 * Return the SurfaceHolder providing access and control over this
201 * SurfaceView's underlying surface.
202 *
203 * @return SurfaceHolder The holder of the surface.
204 */
205 public SurfaceHolder getHolder() {
206 return mSurfaceHolder;
207 }
208
209 @Override
210 protected void onAttachedToWindow() {
211 super.onAttachedToWindow();
212 mParent.requestTransparentRegion(this);
213 mSession = getWindowSession();
214 mLayout.token = getWindowToken();
215 mLayout.setTitle("SurfaceView");
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700216 mViewVisibility = getVisibility() == VISIBLE;
Romain Guy01d5edc2011-01-28 11:28:53 -0800217
218 if (!mGlobalListenersAdded) {
219 ViewTreeObserver observer = getViewTreeObserver();
220 observer.addOnScrollChangedListener(mScrollChangedListener);
221 observer.addOnPreDrawListener(mDrawListener);
222 mGlobalListenersAdded = true;
223 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700224 }
225
226 @Override
227 protected void onWindowVisibilityChanged(int visibility) {
228 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700229 mWindowVisibility = visibility == VISIBLE;
230 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700231 updateWindow(false, false);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700232 }
233
234 @Override
235 public void setVisibility(int visibility) {
236 super.setVisibility(visibility);
237 mViewVisibility = visibility == VISIBLE;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700238 boolean newRequestedVisible = mWindowVisibility && mViewVisibility;
239 if (newRequestedVisible != mRequestedVisible) {
240 // our base class (View) invalidates the layout only when
241 // we go from/to the GONE state. However, SurfaceView needs
242 // to request a re-layout when the visibility changes at all.
243 // This is needed because the transparent region is computed
244 // as part of the layout phase, and it changes (obviously) when
245 // the visibility changes.
246 requestLayout();
247 }
248 mRequestedVisible = newRequestedVisible;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700249 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700250 }
Romain Guyafc3e112010-06-07 17:04:33 -0700251
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700252 @Override
253 protected void onDetachedFromWindow() {
Romain Guy01d5edc2011-01-28 11:28:53 -0800254 if (mGlobalListenersAdded) {
255 ViewTreeObserver observer = getViewTreeObserver();
256 observer.removeOnScrollChangedListener(mScrollChangedListener);
257 observer.removeOnPreDrawListener(mDrawListener);
258 mGlobalListenersAdded = false;
259 }
260
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700261 mRequestedVisible = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700262 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700263 mHaveFrame = false;
264 if (mWindow != null) {
265 try {
266 mSession.remove(mWindow);
267 } catch (RemoteException ex) {
Romain Guy01d5edc2011-01-28 11:28:53 -0800268 // Not much we can do here...
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700269 }
270 mWindow = null;
271 }
272 mSession = null;
273 mLayout.token = null;
274
275 super.onDetachedFromWindow();
276 }
277
278 @Override
279 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800280 int width = mRequestedWidth >= 0
281 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
282 : getDefaultSize(0, widthMeasureSpec);
283 int height = mRequestedHeight >= 0
284 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
285 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700286 setMeasuredDimension(width, height);
287 }
288
Mathias Agopianef115302010-10-04 20:15:08 -0700289 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700290 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700291 protected boolean setFrame(int left, int top, int right, int bottom) {
292 boolean result = super.setFrame(left, top, right, bottom);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700293 updateWindow(false, false);
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700294 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700295 }
296
297 @Override
298 public boolean gatherTransparentRegion(Region region) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700299 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
300 return super.gatherTransparentRegion(region);
301 }
302
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700303 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700304 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700305 // this view draws, remove it from the transparent region
306 opaque = super.gatherTransparentRegion(region);
307 } else if (region != null) {
308 int w = getWidth();
309 int h = getHeight();
310 if (w>0 && h>0) {
311 getLocationInWindow(mLocation);
312 // otherwise, punch a hole in the whole hierarchy
313 int l = mLocation[0];
314 int t = mLocation[1];
315 region.op(l, t, l+w, t+h, Region.Op.UNION);
316 }
317 }
318 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
319 opaque = false;
320 }
321 return opaque;
322 }
323
324 @Override
325 public void draw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700326 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
327 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700328 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700329 // punch a whole in the view-hierarchy below us
330 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
331 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700332 }
333 super.draw(canvas);
334 }
335
336 @Override
337 protected void dispatchDraw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700338 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
339 // if SKIP_DRAW is cleared, draw() has already punched a hole
Dianne Hackborn4702a852012-08-17 15:18:29 -0700340 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700341 // punch a whole in the view-hierarchy below us
342 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
343 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700344 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700345 super.dispatchDraw(canvas);
346 }
347
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700348 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700349 * Control whether the surface view's surface is placed on top of another
350 * regular surface view in the window (but still behind the window itself).
351 * This is typically used to place overlays on top of an underlying media
352 * surface view.
353 *
354 * <p>Note that this must be set before the surface view's containing
355 * window is attached to the window manager.
356 *
357 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
358 */
359 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
360 mWindowType = isMediaOverlay
361 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
362 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
363 }
364
365 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700366 * Control whether the surface view's surface is placed on top of its
367 * window. Normally it is placed behind the window, to allow it to
368 * (for the most part) appear to composite with the views in the
369 * hierarchy. By setting this, you cause it to be placed above the
370 * window. This means that none of the contents of the window this
371 * SurfaceView is in will be visible on top of its surface.
372 *
373 * <p>Note that this must be set before the surface view's containing
374 * window is attached to the window manager.
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700375 *
376 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700377 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700378 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500379 if (onTop) {
380 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
381 // ensures the surface is placed below the IME
382 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
383 } else {
384 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
385 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
386 }
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) {
403 mLayout.flags |= WindowManager.LayoutParams.FLAG_SECURE;
404 } else {
405 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
406 }
407 }
408
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700409 /**
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700410 * Hack to allow special layering of windows. The type is one of the
411 * types in WindowManager.LayoutParams. This is a hack so:
412 * @hide
413 */
414 public void setWindowType(int type) {
415 mWindowType = type;
416 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700417
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700418 private void updateWindow(boolean force, boolean redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700419 if (!mHaveFrame) {
420 return;
421 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800422 ViewRootImpl viewRoot = getViewRootImpl();
Joe Onorato168173a2009-08-12 21:40:29 -0700423 if (viewRoot != null) {
424 mTranslator = viewRoot.mTranslator;
425 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700426
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700427 if (mTranslator != null) {
428 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700429 }
430
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 getLocationInWindow(mLocation);
437 final boolean creating = mWindow == null;
438 final boolean formatChanged = mFormat != mRequestedFormat;
439 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800440 final boolean visibleChanged = mVisible != mRequestedVisible;
Mathias Agopiand2112302010-12-07 19:38:17 -0800441
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700442 if (force || creating || formatChanged || sizeChanged || visibleChanged
Mathias Agopiand2112302010-12-07 19:38:17 -0800443 || mLeft != mLocation[0] || mTop != mLocation[1]
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700444 || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700445
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800446 if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700447 + " format=" + formatChanged + " size=" + sizeChanged
448 + " visible=" + visibleChanged
449 + " left=" + (mLeft != mLocation[0])
450 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700451
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700452 try {
453 final boolean visible = mVisible = mRequestedVisible;
454 mLeft = mLocation[0];
455 mTop = mLocation[1];
456 mWidth = myWidth;
457 mHeight = myHeight;
458 mFormat = mRequestedFormat;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700459
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700460 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
461
462 // Places the window relative
463 mLayout.x = mLeft;
464 mLayout.y = mTop;
465 mLayout.width = getWidth();
466 mLayout.height = getHeight();
467 if (mTranslator != null) {
468 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
469 }
470
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700471 mLayout.format = mRequestedFormat;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700472 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
473 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
474 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700475 | WindowManager.LayoutParams.FLAG_SCALED
476 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
477 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
478 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700479 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
480 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
481 }
Dianne Hackborn1c5383c2013-04-15 15:07:21 -0700482 mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700483
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700484 if (mWindow == null) {
Jeff Brown8d0243a2012-09-24 15:01:47 -0700485 Display display = getDisplay();
Jon Larimer9bdf5762009-01-02 18:55:15 -0500486 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700487 mLayout.type = mWindowType;
Fabrice Di Meglioaac0d4e2012-07-19 19:21:26 -0700488 mLayout.gravity = Gravity.START|Gravity.TOP;
Craig Mautner6881a102012-07-27 13:04:51 -0700489 mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
Jeff Brown8d0243a2012-09-24 15:01:47 -0700490 mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700491 }
492
Dianne Hackborn726426e2010-03-31 22:04:36 -0700493 boolean realSizeChanged;
494 boolean reportDrawNeeded;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800495
496 int relayoutResult;
497
Dianne Hackborn726426e2010-03-31 22:04:36 -0700498 mSurfaceLock.lock();
499 try {
500 mUpdateWindowNeeded = false;
501 reportDrawNeeded = mReportDrawNeeded;
502 mReportDrawNeeded = false;
503 mDrawingStopped = !visible;
504
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800505 if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
506
507 relayoutResult = mSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700508 mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800509 visible ? VISIBLE : GONE,
Jeff Brown98365d72012-08-19 20:30:52 -0700510 WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800511 mWinFrame, mOverscanInsets, mContentInsets,
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800512 mVisibleInsets, mConfiguration, mNewSurface);
Jeff Brown98365d72012-08-19 20:30:52 -0700513 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700514 mReportDrawNeeded = true;
515 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800516
517 if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
Dianne Hackborn726426e2010-03-31 22:04:36 -0700518 + ", vis=" + visible + ", frame=" + mWinFrame);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800519
Dianne Hackborn726426e2010-03-31 22:04:36 -0700520 mSurfaceFrame.left = 0;
521 mSurfaceFrame.top = 0;
522 if (mTranslator == null) {
523 mSurfaceFrame.right = mWinFrame.width();
524 mSurfaceFrame.bottom = mWinFrame.height();
525 } else {
526 float appInvertedScale = mTranslator.applicationInvertedScale;
527 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
528 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
529 }
530
531 final int surfaceWidth = mSurfaceFrame.right;
532 final int surfaceHeight = mSurfaceFrame.bottom;
533 realSizeChanged = mLastSurfaceWidth != surfaceWidth
534 || mLastSurfaceHeight != surfaceHeight;
535 mLastSurfaceWidth = surfaceWidth;
536 mLastSurfaceHeight = surfaceHeight;
537 } finally {
538 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700539 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700540
541 try {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700542 redrawNeeded |= creating | reportDrawNeeded;
543
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800544 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700545
Jeff Brown98365d72012-08-19 20:30:52 -0700546 final boolean surfaceChanged = (relayoutResult
547 & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800548 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
549 mSurfaceCreated = false;
550 if (mSurface.isValid()) {
551 if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
552 callbacks = getSurfaceCallbacks();
553 for (SurfaceHolder.Callback c : callbacks) {
554 c.surfaceDestroyed(mSurfaceHolder);
555 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700556 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800557 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700558
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800559 mSurface.transferFrom(mNewSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800560
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200561 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800562 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
563 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700564 mIsCreating = true;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800565 if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
566 if (callbacks == null) {
567 callbacks = getSurfaceCallbacks();
568 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700569 for (SurfaceHolder.Callback c : callbacks) {
570 c.surfaceCreated(mSurfaceHolder);
571 }
572 }
573 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700574 || visibleChanged || realSizeChanged) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800575 if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
576 + " w=" + myWidth + " h=" + myHeight);
577 if (callbacks == null) {
578 callbacks = getSurfaceCallbacks();
579 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700580 for (SurfaceHolder.Callback c : callbacks) {
581 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
582 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700583 }
584 if (redrawNeeded) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800585 if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
586 if (callbacks == null) {
587 callbacks = getSurfaceCallbacks();
588 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700589 for (SurfaceHolder.Callback c : callbacks) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700590 if (c instanceof SurfaceHolder.Callback2) {
591 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
592 mSurfaceHolder);
593 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700594 }
595 }
596 }
597 } finally {
598 mIsCreating = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700599 if (redrawNeeded) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800600 if (DEBUG) Log.i(TAG, "finishedDrawing");
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700601 mSession.finishDrawing(mWindow);
602 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800603 mSession.performDeferredDestroy(mWindow);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700604 }
605 } catch (RemoteException ex) {
606 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800607 if (DEBUG) Log.v(
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700608 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
609 " w=" + mLayout.width + " h=" + mLayout.height +
610 ", frame=" + mSurfaceFrame);
611 }
612 }
613
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800614 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
615 SurfaceHolder.Callback callbacks[];
616 synchronized (mCallbacks) {
617 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
618 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700619 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800620 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700621 }
622
623 void handleGetNewSurface() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700624 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700625 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800626
Derek Sollenberger7179b812010-03-22 13:41:20 -0400627 /**
628 * Check to see if the surface has fixed size dimensions or if the surface's
629 * dimensions are dimensions are dependent on its current layout.
630 *
631 * @return true if the surface has dimensions that are fixed in size
632 * @hide
633 */
634 public boolean isFixedSize() {
635 return (mRequestedWidth != -1 || mRequestedHeight != -1);
636 }
637
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700638 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700639 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500640
641 public MyWindow(SurfaceView surfaceView) {
642 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
643 }
644
Craig Mautner656e3af2012-09-06 15:04:22 -0700645 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800646 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800647 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500648 SurfaceView surfaceView = mSurfaceView.get();
649 if (surfaceView != null) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800650 if (DEBUG) Log.v(
Craig Mautner656e3af2012-09-06 15:04:22 -0700651 "SurfaceView", surfaceView + " got resized: w=" + frame.width()
652 + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700653 surfaceView.mSurfaceLock.lock();
654 try {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500655 if (reportDraw) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700656 surfaceView.mUpdateWindowNeeded = true;
657 surfaceView.mReportDrawNeeded = true;
658 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
Craig Mautner656e3af2012-09-06 15:04:22 -0700659 } else if (surfaceView.mWinFrame.width() != frame.width()
660 || surfaceView.mWinFrame.height() != frame.height()) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700661 surfaceView.mUpdateWindowNeeded = true;
662 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700663 }
Dianne Hackborn726426e2010-03-31 22:04:36 -0700664 } finally {
665 surfaceView.mSurfaceLock.unlock();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700666 }
667 }
668 }
669
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700670 public void dispatchAppVisibility(boolean visible) {
671 // The point of SurfaceView is to let the app control the surface.
672 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800673
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700674 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500675 SurfaceView surfaceView = mSurfaceView.get();
676 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800677 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
678 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500679 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700680 }
681
682 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
683 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
684 }
685
686 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
687 }
688
689 int mCurWidth = -1;
690 int mCurHeight = -1;
691 }
692
693 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
694
695 private static final String LOG_TAG = "SurfaceHolder";
696
697 public boolean isCreating() {
698 return mIsCreating;
699 }
700
701 public void addCallback(Callback callback) {
702 synchronized (mCallbacks) {
703 // This is a linear search, but in practice we'll
704 // have only a couple callbacks, so it doesn't matter.
705 if (mCallbacks.contains(callback) == false) {
706 mCallbacks.add(callback);
707 }
708 }
709 }
710
711 public void removeCallback(Callback callback) {
712 synchronized (mCallbacks) {
713 mCallbacks.remove(callback);
714 }
715 }
716
717 public void setFixedSize(int width, int height) {
718 if (mRequestedWidth != width || mRequestedHeight != height) {
719 mRequestedWidth = width;
720 mRequestedHeight = height;
721 requestLayout();
722 }
723 }
724
725 public void setSizeFromLayout() {
726 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
727 mRequestedWidth = mRequestedHeight = -1;
728 requestLayout();
729 }
730 }
731
732 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700733
734 // for backward compatibility reason, OPAQUE always
735 // means 565 for SurfaceView
736 if (format == PixelFormat.OPAQUE)
737 format = PixelFormat.RGB_565;
738
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700739 mRequestedFormat = format;
740 if (mWindow != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700741 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700742 }
743 }
744
Mathias Agopiand2112302010-12-07 19:38:17 -0800745 /**
746 * @deprecated setType is now ignored.
747 */
748 @Deprecated
749 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700750
751 public void setKeepScreenOn(boolean screenOn) {
752 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
753 msg.arg1 = screenOn ? 1 : 0;
754 mHandler.sendMessage(msg);
755 }
756
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700757 /**
758 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
759 *
760 * After drawing into the provided {@link Canvas}, the caller must
761 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
762 *
763 * The caller must redraw the entire surface.
764 * @return A canvas for drawing into the surface.
765 */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700766 public Canvas lockCanvas() {
767 return internalLockCanvas(null);
768 }
769
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700770 /**
771 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
772 *
773 * After drawing into the provided {@link Canvas}, the caller must
774 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
775 *
776 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
777 * to redraw. This function may choose to expand the dirty rectangle if for example
778 * the surface has been resized or if the previous contents of the surface were
779 * not available. The caller must redraw the entire dirty region as represented
780 * by the contents of the inOutDirty rectangle upon return from this function.
781 * The caller may also pass <code>null</code> instead, in the case where the
782 * entire surface should be redrawn.
783 * @return A canvas for drawing into the surface.
784 */
785 public Canvas lockCanvas(Rect inOutDirty) {
786 return internalLockCanvas(inOutDirty);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700787 }
788
789 private final Canvas internalLockCanvas(Rect dirty) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700790 mSurfaceLock.lock();
791
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800792 if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700793 + mDrawingStopped + ", win=" + mWindow);
794
795 Canvas c = null;
796 if (!mDrawingStopped && mWindow != null) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700797 try {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800798 c = mSurface.lockCanvas(dirty);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700799 } catch (Exception e) {
800 Log.e(LOG_TAG, "Exception locking surface", e);
801 }
802 }
803
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800804 if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700805 if (c != null) {
806 mLastLockTime = SystemClock.uptimeMillis();
807 return c;
808 }
809
810 // If the Surface is not ready to be drawn, then return null,
811 // but throttle calls to this function so it isn't called more
812 // than every 100ms.
813 long now = SystemClock.uptimeMillis();
814 long nextTime = mLastLockTime + 100;
815 if (nextTime > now) {
816 try {
817 Thread.sleep(nextTime-now);
818 } catch (InterruptedException e) {
819 }
820 now = SystemClock.uptimeMillis();
821 }
822 mLastLockTime = now;
823 mSurfaceLock.unlock();
824
825 return null;
826 }
827
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700828 /**
829 * Posts the new contents of the {@link Canvas} to the surface and
830 * releases the {@link Canvas}.
831 *
832 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
833 */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700834 public void unlockCanvasAndPost(Canvas canvas) {
835 mSurface.unlockCanvasAndPost(canvas);
836 mSurfaceLock.unlock();
837 }
838
839 public Surface getSurface() {
840 return mSurface;
841 }
842
843 public Rect getSurfaceFrame() {
844 return mSurfaceFrame;
845 }
846 };
847}