blob: 71da9cf4172e00f336af084ac801dd232d6d0657 [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
19import android.content.Context;
20import android.graphics.Canvas;
21import android.graphics.PixelFormat;
22import android.graphics.PorterDuff;
23import android.graphics.Rect;
24import android.graphics.Region;
25import android.os.Handler;
26import android.os.Message;
27import android.os.RemoteException;
28import android.os.SystemClock;
29import android.os.ParcelFileDescriptor;
30import android.util.AttributeSet;
31import android.util.Config;
32import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070033
Jon Larimer9bdf5762009-01-02 18:55:15 -050034import java.lang.ref.WeakReference;
35import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070036import java.util.concurrent.locks.ReentrantLock;
The Android Open Source Projectb7986892009-01-09 17:51:23 -080037import java.lang.ref.WeakReference;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070038
39/**
40 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
41 * You can control the format of this surface and, if you like, its size; the
42 * SurfaceView takes care of placing the surface at the correct location on the
43 * screen
44 *
45 * <p>The surface is Z ordered so that it is behind the window holding its
46 * SurfaceView; the SurfaceView punches a hole in its window to allow its
47 * surface to be displayed. The view hierarchy will take care of correctly
48 * compositing with the Surface any siblings of the SurfaceView that would
49 * normally appear on top of it. This can be used to place overlays such as
50 * buttons on top of the Surface, though note however that it can have an
51 * impact on performance since a full alpha-blended composite will be performed
52 * each time the Surface changes.
53 *
54 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
55 * which can be retrieved by calling {@link #getHolder}.
56 *
57 * <p>The Surface will be created for you while the SurfaceView's window is
58 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
59 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
60 * Surface is created and destroyed as the window is shown and hidden.
61 *
62 * <p>One of the purposes of this class is to provide a surface in which a
63 * secondary thread can render in to the screen. If you are going to use it
64 * this way, you need to be aware of some threading semantics:
65 *
66 * <ul>
67 * <li> All SurfaceView and
68 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
69 * from the thread running the SurfaceView's window (typically the main thread
70 * of the application). They thus need to correctly synchronize with any
71 * state that is also touched by the drawing thread.
72 * <li> You must ensure that the drawing thread only touches the underlying
73 * Surface while it is valid -- between
74 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
75 * and
76 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
77 * </ul>
78 */
79public class SurfaceView extends View {
80 static private final String TAG = "SurfaceView";
81 static private final boolean DEBUG = false;
82 static private final boolean localLOGV = DEBUG ? true : Config.LOGV;
83
84 final ArrayList<SurfaceHolder.Callback> mCallbacks
85 = new ArrayList<SurfaceHolder.Callback>();
86
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080087 final int[] mLocation = new int[2];
88
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070089 final ReentrantLock mSurfaceLock = new ReentrantLock();
90 final Surface mSurface = new Surface();
91 boolean mDrawingStopped = true;
92
93 final WindowManager.LayoutParams mLayout
94 = new WindowManager.LayoutParams();
95 IWindowSession mSession;
96 MyWindow mWindow;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080097 final Rect mVisibleInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070098 final Rect mWinFrame = new Rect();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080099 final Rect mContentInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700100
101 static final int KEEP_SCREEN_ON_MSG = 1;
102 static final int GET_NEW_SURFACE_MSG = 2;
103
104 boolean mIsCreating = false;
105
106 final Handler mHandler = new Handler() {
107 @Override
108 public void handleMessage(Message msg) {
109 switch (msg.what) {
110 case KEEP_SCREEN_ON_MSG: {
111 setKeepScreenOn(msg.arg1 != 0);
112 } break;
113 case GET_NEW_SURFACE_MSG: {
114 handleGetNewSurface();
115 } break;
116 }
117 }
118 };
119
120 boolean mRequestedVisible = false;
121 int mRequestedWidth = -1;
122 int mRequestedHeight = -1;
123 int mRequestedFormat = PixelFormat.OPAQUE;
124 int mRequestedType = -1;
125
126 boolean mHaveFrame = false;
127 boolean mDestroyReportNeeded = false;
128 boolean mNewSurfaceNeeded = false;
129 long mLastLockTime = 0;
130
131 boolean mVisible = false;
132 int mLeft = -1;
133 int mTop = -1;
134 int mWidth = -1;
135 int mHeight = -1;
136 int mFormat = -1;
137 int mType = -1;
138 final Rect mSurfaceFrame = new Rect();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700139 private final float mAppScale;
140 private final float mAppScaleInverted;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700141
142 public SurfaceView(Context context) {
143 super(context);
144 setWillNotDraw(true);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700145 mAppScale = context.getApplicationScale();
146 mAppScaleInverted = 1.0f / mAppScale;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700147 }
148
149 public SurfaceView(Context context, AttributeSet attrs) {
150 super(context, attrs);
151 setWillNotDraw(true);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700152 mAppScale = context.getApplicationScale();
153 mAppScaleInverted = 1.0f / mAppScale;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700154 }
155
156 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
157 super(context, attrs, defStyle);
158 setWillNotDraw(true);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700159 mAppScale = context.getApplicationScale();
160 mAppScaleInverted = 1.0f / mAppScale;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700161 }
162
163 /**
164 * Return the SurfaceHolder providing access and control over this
165 * SurfaceView's underlying surface.
166 *
167 * @return SurfaceHolder The holder of the surface.
168 */
169 public SurfaceHolder getHolder() {
170 return mSurfaceHolder;
171 }
172
173 @Override
174 protected void onAttachedToWindow() {
175 super.onAttachedToWindow();
176 mParent.requestTransparentRegion(this);
177 mSession = getWindowSession();
178 mLayout.token = getWindowToken();
179 mLayout.setTitle("SurfaceView");
180 }
181
182 @Override
183 protected void onWindowVisibilityChanged(int visibility) {
184 super.onWindowVisibilityChanged(visibility);
185 mRequestedVisible = visibility == VISIBLE;
186 updateWindow(false);
187 }
188
189 @Override
190 protected void onDetachedFromWindow() {
191 mRequestedVisible = false;
192 updateWindow(false);
193 mHaveFrame = false;
194 if (mWindow != null) {
195 try {
196 mSession.remove(mWindow);
197 } catch (RemoteException ex) {
198 }
199 mWindow = null;
200 }
201 mSession = null;
202 mLayout.token = null;
203
204 super.onDetachedFromWindow();
205 }
206
207 @Override
208 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
209 int width = getDefaultSize(mRequestedWidth, widthMeasureSpec);
210 int height = getDefaultSize(mRequestedHeight, heightMeasureSpec);
211 setMeasuredDimension(width, height);
212 }
213
214 @Override
215 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
216 super.onScrollChanged(l, t, oldl, oldt);
217 updateWindow(false);
218 }
219
220 @Override
221 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
222 super.onSizeChanged(w, h, oldw, oldh);
223 updateWindow(false);
224 }
225
226 @Override
227 public boolean gatherTransparentRegion(Region region) {
228 boolean opaque = true;
229 if ((mPrivateFlags & SKIP_DRAW) == 0) {
230 // this view draws, remove it from the transparent region
231 opaque = super.gatherTransparentRegion(region);
232 } else if (region != null) {
233 int w = getWidth();
234 int h = getHeight();
235 if (w>0 && h>0) {
236 getLocationInWindow(mLocation);
237 // otherwise, punch a hole in the whole hierarchy
238 int l = mLocation[0];
239 int t = mLocation[1];
240 region.op(l, t, l+w, t+h, Region.Op.UNION);
241 }
242 }
243 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
244 opaque = false;
245 }
246 return opaque;
247 }
248
249 @Override
250 public void draw(Canvas canvas) {
251 // draw() is not called when SKIP_DRAW is set
252 if ((mPrivateFlags & SKIP_DRAW) == 0) {
253 // punch a whole in the view-hierarchy below us
254 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
255 }
256 super.draw(canvas);
257 }
258
259 @Override
260 protected void dispatchDraw(Canvas canvas) {
261 // if SKIP_DRAW is cleared, draw() has already punched a hole
262 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
263 // punch a whole in the view-hierarchy below us
264 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
265 }
266 // reposition ourselves where the surface is
267 mHaveFrame = true;
268 updateWindow(false);
269 super.dispatchDraw(canvas);
270 }
271
272 private void updateWindow(boolean force) {
273 if (!mHaveFrame) {
274 return;
275 }
276
277 int myWidth = mRequestedWidth;
278 if (myWidth <= 0) myWidth = getWidth();
279 int myHeight = mRequestedHeight;
280 if (myHeight <= 0) myHeight = getHeight();
281
282 getLocationInWindow(mLocation);
283 final boolean creating = mWindow == null;
284 final boolean formatChanged = mFormat != mRequestedFormat;
285 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
286 final boolean visibleChanged = mVisible != mRequestedVisible
287 || mNewSurfaceNeeded;
288 final boolean typeChanged = mType != mRequestedType;
289 if (force || creating || formatChanged || sizeChanged || visibleChanged
290 || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]) {
291
292 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
293 + " format=" + formatChanged + " size=" + sizeChanged
294 + " visible=" + visibleChanged
295 + " left=" + (mLeft != mLocation[0])
296 + " top=" + (mTop != mLocation[1]));
297
298 try {
299 final boolean visible = mVisible = mRequestedVisible;
300 mLeft = mLocation[0];
301 mTop = mLocation[1];
302 mWidth = myWidth;
303 mHeight = myHeight;
304 mFormat = mRequestedFormat;
305 mType = mRequestedType;
306
307 mLayout.x = mLeft;
308 mLayout.y = mTop;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700309 mLayout.width = (int) (getWidth() * mAppScale);
310 mLayout.height = (int) (getHeight() * mAppScale);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700311 mLayout.format = mRequestedFormat;
312 mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
313 | WindowManager.LayoutParams.FLAG_SCALED
314 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
315 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
316 ;
317
318 mLayout.memoryType = mRequestedType;
319
320 if (mWindow == null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500321 mWindow = new MyWindow(this);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700322 mLayout.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
323 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
324 mSession.add(mWindow, mLayout,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800325 mVisible ? VISIBLE : GONE, mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700326 }
327
328 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
329 reportSurfaceDestroyed();
330 }
331
332 mNewSurfaceNeeded = false;
333
334 mSurfaceLock.lock();
335 mDrawingStopped = !visible;
336 final int relayoutResult = mSession.relayout(
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700337 mWindow, mLayout, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale),
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800338 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
339 mVisibleInsets, mSurface);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700340
341 mContentInsets.scale(mAppScaleInverted);
342 mVisibleInsets.scale(mAppScaleInverted);
343 mWinFrame.scale(mAppScaleInverted);
344
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700345 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
346 + ", vis=" + visible + ", frame=" + mWinFrame);
347 mSurfaceFrame.left = 0;
348 mSurfaceFrame.top = 0;
349 mSurfaceFrame.right = mWinFrame.width();
350 mSurfaceFrame.bottom = mWinFrame.height();
351 mSurfaceLock.unlock();
352
353 try {
354 if (visible) {
355 mDestroyReportNeeded = true;
356
357 SurfaceHolder.Callback callbacks[];
358 synchronized (mCallbacks) {
359 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
360 mCallbacks.toArray(callbacks);
361 }
362
363 if (visibleChanged) {
364 mIsCreating = true;
365 for (SurfaceHolder.Callback c : callbacks) {
366 c.surfaceCreated(mSurfaceHolder);
367 }
368 }
369 if (creating || formatChanged || sizeChanged
370 || visibleChanged) {
371 for (SurfaceHolder.Callback c : callbacks) {
372 c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
373 }
374 }
375 }
376 } finally {
377 mIsCreating = false;
378 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
379 mSession.finishDrawing(mWindow);
380 }
381 }
382 } catch (RemoteException ex) {
383 }
384 if (localLOGV) Log.v(
385 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
386 " w=" + mLayout.width + " h=" + mLayout.height +
387 ", frame=" + mSurfaceFrame);
388 }
389 }
390
391 private void reportSurfaceDestroyed() {
392 if (mDestroyReportNeeded) {
393 mDestroyReportNeeded = false;
394 SurfaceHolder.Callback callbacks[];
395 synchronized (mCallbacks) {
396 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
397 mCallbacks.toArray(callbacks);
398 }
399 for (SurfaceHolder.Callback c : callbacks) {
400 c.surfaceDestroyed(mSurfaceHolder);
401 }
402 }
403 super.onDetachedFromWindow();
404 }
405
406 void handleGetNewSurface() {
407 mNewSurfaceNeeded = true;
408 updateWindow(false);
409 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800410
Jon Larimer9bdf5762009-01-02 18:55:15 -0500411 private static class MyWindow extends IWindow.Stub {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700412 private final WeakReference<SurfaceView> mSurfaceView;
413 private final float mAppScale;
414 private final float mAppScaleInverted;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500415
416 public MyWindow(SurfaceView surfaceView) {
417 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700418 mAppScale = surfaceView.getContext().getApplicationScale();
419 mAppScaleInverted = 1.0f / mAppScale;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500420 }
421
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800422 public void resized(int w, int h, Rect coveredInsets,
423 Rect visibleInsets, boolean reportDraw) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500424 SurfaceView surfaceView = mSurfaceView.get();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700425 float scale = mAppScaleInverted;
426 w *= scale;
427 h *= scale;
428 coveredInsets.scale(scale);
429 visibleInsets.scale(scale);
430
Jon Larimer9bdf5762009-01-02 18:55:15 -0500431 if (surfaceView != null) {
432 if (localLOGV) Log.v(
433 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800434 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500435 synchronized (this) {
436 if (mCurWidth != w || mCurHeight != h) {
437 mCurWidth = w;
438 mCurHeight = h;
439 }
440 if (reportDraw) {
441 try {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800442 surfaceView.mSession.finishDrawing(surfaceView.mWindow);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500443 } catch (RemoteException e) {
444 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700445 }
446 }
447 }
448 }
449
450 public void dispatchKey(KeyEvent event) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500451 SurfaceView surfaceView = mSurfaceView.get();
452 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800453 //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
454 if (surfaceView.mSession != null && surfaceView.mSurface != null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500455 try {
456 surfaceView.mSession.finishKey(surfaceView.mWindow);
457 } catch (RemoteException ex) {
458 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700459 }
460 }
461 }
462
463 public void dispatchPointer(MotionEvent event, long eventTime) {
464 Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
465 //if (mSession != null && mSurface != null) {
466 // try {
467 // //mSession.finishKey(mWindow);
468 // } catch (RemoteException ex) {
469 // }
470 //}
471 }
472
473 public void dispatchTrackball(MotionEvent event, long eventTime) {
474 Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
475 //if (mSession != null && mSurface != null) {
476 // try {
477 // //mSession.finishKey(mWindow);
478 // } catch (RemoteException ex) {
479 // }
480 //}
481 }
482
483 public void dispatchAppVisibility(boolean visible) {
484 // The point of SurfaceView is to let the app control the surface.
485 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800486
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700487 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500488 SurfaceView surfaceView = mSurfaceView.get();
489 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800490 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
491 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500492 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700493 }
494
495 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
496 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
497 }
498
499 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
500 }
501
502 int mCurWidth = -1;
503 int mCurHeight = -1;
504 }
505
506 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
507
508 private static final String LOG_TAG = "SurfaceHolder";
509
510 public boolean isCreating() {
511 return mIsCreating;
512 }
513
514 public void addCallback(Callback callback) {
515 synchronized (mCallbacks) {
516 // This is a linear search, but in practice we'll
517 // have only a couple callbacks, so it doesn't matter.
518 if (mCallbacks.contains(callback) == false) {
519 mCallbacks.add(callback);
520 }
521 }
522 }
523
524 public void removeCallback(Callback callback) {
525 synchronized (mCallbacks) {
526 mCallbacks.remove(callback);
527 }
528 }
529
530 public void setFixedSize(int width, int height) {
531 if (mRequestedWidth != width || mRequestedHeight != height) {
532 mRequestedWidth = width;
533 mRequestedHeight = height;
534 requestLayout();
535 }
536 }
537
538 public void setSizeFromLayout() {
539 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
540 mRequestedWidth = mRequestedHeight = -1;
541 requestLayout();
542 }
543 }
544
545 public void setFormat(int format) {
546 mRequestedFormat = format;
547 if (mWindow != null) {
548 updateWindow(false);
549 }
550 }
551
552 public void setType(int type) {
553 switch (type) {
554 case SURFACE_TYPE_NORMAL:
555 case SURFACE_TYPE_HARDWARE:
556 case SURFACE_TYPE_GPU:
557 case SURFACE_TYPE_PUSH_BUFFERS:
558 mRequestedType = type;
559 if (mWindow != null) {
560 updateWindow(false);
561 }
562 break;
563 }
564 }
565
566 public void setKeepScreenOn(boolean screenOn) {
567 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
568 msg.arg1 = screenOn ? 1 : 0;
569 mHandler.sendMessage(msg);
570 }
571
572 public Canvas lockCanvas() {
573 return internalLockCanvas(null);
574 }
575
576 public Canvas lockCanvas(Rect dirty) {
577 return internalLockCanvas(dirty);
578 }
579
580 private final Canvas internalLockCanvas(Rect dirty) {
581 if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
582 throw new BadSurfaceTypeException(
583 "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
584 }
585 mSurfaceLock.lock();
586
587 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
588 + mDrawingStopped + ", win=" + mWindow);
589
590 Canvas c = null;
591 if (!mDrawingStopped && mWindow != null) {
592 Rect frame = dirty != null ? dirty : mSurfaceFrame;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700593 frame.scale(mAppScale);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700594 try {
595 c = mSurface.lockCanvas(frame);
596 } catch (Exception e) {
597 Log.e(LOG_TAG, "Exception locking surface", e);
598 }
599 }
600
601 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
602 if (c != null) {
603 mLastLockTime = SystemClock.uptimeMillis();
604 return c;
605 }
606
607 // If the Surface is not ready to be drawn, then return null,
608 // but throttle calls to this function so it isn't called more
609 // than every 100ms.
610 long now = SystemClock.uptimeMillis();
611 long nextTime = mLastLockTime + 100;
612 if (nextTime > now) {
613 try {
614 Thread.sleep(nextTime-now);
615 } catch (InterruptedException e) {
616 }
617 now = SystemClock.uptimeMillis();
618 }
619 mLastLockTime = now;
620 mSurfaceLock.unlock();
621
622 return null;
623 }
624
625 public void unlockCanvasAndPost(Canvas canvas) {
626 mSurface.unlockCanvasAndPost(canvas);
627 mSurfaceLock.unlock();
628 }
629
630 public Surface getSurface() {
631 return mSurface;
632 }
633
634 public Rect getSurfaceFrame() {
635 return mSurfaceFrame;
636 }
637 };
638}