blob: 28c1fe1fefb5b35ccac20f9216fcdc3518232236 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070020import android.content.res.CompatibilityInfo.Translator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.graphics.Canvas;
22import android.graphics.PixelFormat;
23import android.graphics.PorterDuff;
24import android.graphics.Rect;
25import android.graphics.Region;
26import android.os.Handler;
27import android.os.Message;
28import android.os.RemoteException;
29import android.os.SystemClock;
30import android.os.ParcelFileDescriptor;
31import android.util.AttributeSet;
32import android.util.Config;
33import android.util.Log;
34import java.util.ArrayList;
35
36import java.util.concurrent.locks.ReentrantLock;
37import java.lang.ref.WeakReference;
38
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
87 final int[] mLocation = new int[2];
88
89 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;
97 final Rect mVisibleInsets = new Rect();
98 final Rect mWinFrame = new Rect();
99 final Rect mContentInsets = new Rect();
100
101 static final int KEEP_SCREEN_ON_MSG = 1;
102 static final int GET_NEW_SURFACE_MSG = 2;
103
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700104 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 boolean mIsCreating = false;
107
108 final Handler mHandler = new Handler() {
109 @Override
110 public void handleMessage(Message msg) {
111 switch (msg.what) {
112 case KEEP_SCREEN_ON_MSG: {
113 setKeepScreenOn(msg.arg1 != 0);
114 } break;
115 case GET_NEW_SURFACE_MSG: {
116 handleGetNewSurface();
117 } break;
118 }
119 }
120 };
121
122 boolean mRequestedVisible = false;
123 int mRequestedWidth = -1;
124 int mRequestedHeight = -1;
125 int mRequestedFormat = PixelFormat.OPAQUE;
126 int mRequestedType = -1;
127
128 boolean mHaveFrame = false;
129 boolean mDestroyReportNeeded = false;
130 boolean mNewSurfaceNeeded = false;
131 long mLastLockTime = 0;
132
133 boolean mVisible = false;
134 int mLeft = -1;
135 int mTop = -1;
136 int mWidth = -1;
137 int mHeight = -1;
138 int mFormat = -1;
139 int mType = -1;
140 final Rect mSurfaceFrame = new Rect();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700141 private Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142
143 public SurfaceView(Context context) {
144 super(context);
145 setWillNotDraw(true);
146 }
147
148 public SurfaceView(Context context, AttributeSet attrs) {
149 super(context, attrs);
150 setWillNotDraw(true);
151 }
152
153 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
154 super(context, attrs, defStyle);
155 setWillNotDraw(true);
156 }
157
158 /**
159 * Return the SurfaceHolder providing access and control over this
160 * SurfaceView's underlying surface.
161 *
162 * @return SurfaceHolder The holder of the surface.
163 */
164 public SurfaceHolder getHolder() {
165 return mSurfaceHolder;
166 }
167
168 @Override
169 protected void onAttachedToWindow() {
170 super.onAttachedToWindow();
171 mParent.requestTransparentRegion(this);
172 mSession = getWindowSession();
173 mLayout.token = getWindowToken();
174 mLayout.setTitle("SurfaceView");
175 }
176
177 @Override
178 protected void onWindowVisibilityChanged(int visibility) {
179 super.onWindowVisibilityChanged(visibility);
180 mRequestedVisible = visibility == VISIBLE;
181 updateWindow(false);
182 }
183
184 @Override
185 protected void onDetachedFromWindow() {
186 mRequestedVisible = false;
187 updateWindow(false);
188 mHaveFrame = false;
189 if (mWindow != null) {
190 try {
191 mSession.remove(mWindow);
192 } catch (RemoteException ex) {
193 }
194 mWindow = null;
195 }
196 mSession = null;
197 mLayout.token = null;
198
199 super.onDetachedFromWindow();
200 }
201
202 @Override
203 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
204 int width = getDefaultSize(mRequestedWidth, widthMeasureSpec);
205 int height = getDefaultSize(mRequestedHeight, heightMeasureSpec);
206 setMeasuredDimension(width, height);
207 }
208
209 @Override
210 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
211 super.onScrollChanged(l, t, oldl, oldt);
212 updateWindow(false);
213 }
214
215 @Override
216 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
217 super.onSizeChanged(w, h, oldw, oldh);
218 updateWindow(false);
219 }
220
221 @Override
222 public boolean gatherTransparentRegion(Region region) {
223 boolean opaque = true;
224 if ((mPrivateFlags & SKIP_DRAW) == 0) {
225 // this view draws, remove it from the transparent region
226 opaque = super.gatherTransparentRegion(region);
227 } else if (region != null) {
228 int w = getWidth();
229 int h = getHeight();
230 if (w>0 && h>0) {
231 getLocationInWindow(mLocation);
232 // otherwise, punch a hole in the whole hierarchy
233 int l = mLocation[0];
234 int t = mLocation[1];
235 region.op(l, t, l+w, t+h, Region.Op.UNION);
236 }
237 }
238 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
239 opaque = false;
240 }
241 return opaque;
242 }
243
244 @Override
245 public void draw(Canvas canvas) {
246 // draw() is not called when SKIP_DRAW is set
247 if ((mPrivateFlags & SKIP_DRAW) == 0) {
248 // punch a whole in the view-hierarchy below us
249 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
250 }
251 super.draw(canvas);
252 }
253
254 @Override
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700255 public boolean dispatchTouchEvent(MotionEvent event) {
256 // SurfaceView uses pre-scaled size unless fixed size is requested. This hook
257 // scales the event back to the pre-scaled coordinates for such surface.
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700258 if (mScaled) {
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700259 MotionEvent scaledBack = MotionEvent.obtain(event);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700260 scaledBack.scale(mTranslator.applicationScale);
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700261 try {
262 return super.dispatchTouchEvent(scaledBack);
263 } finally {
264 scaledBack.recycle();
265 }
266 } else {
267 return super.dispatchTouchEvent(event);
268 }
269 }
270
271 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 protected void dispatchDraw(Canvas canvas) {
273 // if SKIP_DRAW is cleared, draw() has already punched a hole
274 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
275 // punch a whole in the view-hierarchy below us
276 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
277 }
278 // reposition ourselves where the surface is
279 mHaveFrame = true;
280 updateWindow(false);
281 super.dispatchDraw(canvas);
282 }
283
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700284 /**
285 * Hack to allow special layering of windows. The type is one of the
286 * types in WindowManager.LayoutParams. This is a hack so:
287 * @hide
288 */
289 public void setWindowType(int type) {
290 mWindowType = type;
291 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700292
293 boolean mScaled = false;
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 private void updateWindow(boolean force) {
296 if (!mHaveFrame) {
297 return;
298 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700299 mTranslator = ((ViewRoot)getRootView().getParent()).mTranslator;
300
301 float appScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302
303 int myWidth = mRequestedWidth;
304 if (myWidth <= 0) myWidth = getWidth();
305 int myHeight = mRequestedHeight;
306 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700307
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700308 // Use original size if the app specified the size of the view,
309 // and let the flinger to scale up.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700310 if (mRequestedWidth <= 0 && mTranslator != null) {
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700311 myWidth *= appScale;
312 myHeight *= appScale;
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700313 mScaled = true;
314 } else {
315 mScaled = false;
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700316 }
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 getLocationInWindow(mLocation);
319 final boolean creating = mWindow == null;
320 final boolean formatChanged = mFormat != mRequestedFormat;
321 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
322 final boolean visibleChanged = mVisible != mRequestedVisible
323 || mNewSurfaceNeeded;
324 final boolean typeChanged = mType != mRequestedType;
325 if (force || creating || formatChanged || sizeChanged || visibleChanged
326 || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]) {
327
328 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
329 + " format=" + formatChanged + " size=" + sizeChanged
330 + " visible=" + visibleChanged
331 + " left=" + (mLeft != mLocation[0])
332 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 try {
335 final boolean visible = mVisible = mRequestedVisible;
336 mLeft = mLocation[0];
337 mTop = mLocation[1];
338 mWidth = myWidth;
339 mHeight = myHeight;
340 mFormat = mRequestedFormat;
341 mType = mRequestedType;
342
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700343 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
344
345 // Places the window relative
346 mLayout.x = mLeft;
347 mLayout.y = mTop;
348 mLayout.width = getWidth();
349 mLayout.height = getHeight();
350 if (mTranslator != null) {
351 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
352 }
353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 mLayout.format = mRequestedFormat;
355 mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
356 | WindowManager.LayoutParams.FLAG_SCALED
357 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
358 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700359 | WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 ;
361
362 mLayout.memoryType = mRequestedType;
363
364 if (mWindow == null) {
365 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700366 mLayout.type = mWindowType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
368 mSession.add(mWindow, mLayout,
369 mVisible ? VISIBLE : GONE, mContentInsets);
370 }
371
372 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
373 reportSurfaceDestroyed();
374 }
375
376 mNewSurfaceNeeded = false;
377
378 mSurfaceLock.lock();
379 mDrawingStopped = !visible;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 final int relayoutResult = mSession.relayout(
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700382 mWindow, mLayout, mWidth, mHeight,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
384 mVisibleInsets, mSurface);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
387 + ", vis=" + visible + ", frame=" + mWinFrame);
388 mSurfaceFrame.left = 0;
389 mSurfaceFrame.top = 0;
390 mSurfaceFrame.right = mWinFrame.width();
391 mSurfaceFrame.bottom = mWinFrame.height();
392 mSurfaceLock.unlock();
393
394 try {
395 if (visible) {
396 mDestroyReportNeeded = true;
397
398 SurfaceHolder.Callback callbacks[];
399 synchronized (mCallbacks) {
400 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
401 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700402 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403
404 if (visibleChanged) {
405 mIsCreating = true;
406 for (SurfaceHolder.Callback c : callbacks) {
407 c.surfaceCreated(mSurfaceHolder);
408 }
409 }
410 if (creating || formatChanged || sizeChanged
411 || visibleChanged) {
412 for (SurfaceHolder.Callback c : callbacks) {
413 c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
414 }
415 }
416 }
417 } finally {
418 mIsCreating = false;
419 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
420 mSession.finishDrawing(mWindow);
421 }
422 }
423 } catch (RemoteException ex) {
424 }
425 if (localLOGV) Log.v(
426 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
427 " w=" + mLayout.width + " h=" + mLayout.height +
428 ", frame=" + mSurfaceFrame);
429 }
430 }
431
432 private void reportSurfaceDestroyed() {
433 if (mDestroyReportNeeded) {
434 mDestroyReportNeeded = false;
435 SurfaceHolder.Callback callbacks[];
436 synchronized (mCallbacks) {
437 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
438 mCallbacks.toArray(callbacks);
439 }
440 for (SurfaceHolder.Callback c : callbacks) {
441 c.surfaceDestroyed(mSurfaceHolder);
442 }
443 }
444 super.onDetachedFromWindow();
445 }
446
447 void handleGetNewSurface() {
448 mNewSurfaceNeeded = true;
449 updateWindow(false);
450 }
451
452 private static class MyWindow extends IWindow.Stub {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700453 private final WeakReference<SurfaceView> mSurfaceView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454
455 public MyWindow(SurfaceView surfaceView) {
456 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
457 }
458
459 public void resized(int w, int h, Rect coveredInsets,
460 Rect visibleInsets, boolean reportDraw) {
461 SurfaceView surfaceView = mSurfaceView.get();
462 if (surfaceView != null) {
463 if (localLOGV) Log.v(
464 "SurfaceView", surfaceView + " got resized: w=" +
465 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
466 synchronized (this) {
467 if (mCurWidth != w || mCurHeight != h) {
468 mCurWidth = w;
469 mCurHeight = h;
470 }
471 if (reportDraw) {
472 try {
473 surfaceView.mSession.finishDrawing(surfaceView.mWindow);
474 } catch (RemoteException e) {
475 }
476 }
477 }
478 }
479 }
480
481 public void dispatchKey(KeyEvent event) {
482 SurfaceView surfaceView = mSurfaceView.get();
483 if (surfaceView != null) {
484 //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
485 if (surfaceView.mSession != null && surfaceView.mSurface != null) {
486 try {
487 surfaceView.mSession.finishKey(surfaceView.mWindow);
488 } catch (RemoteException ex) {
489 }
490 }
491 }
492 }
493
494 public void dispatchPointer(MotionEvent event, long eventTime) {
495 Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
496 //if (mSession != null && mSurface != null) {
497 // try {
498 // //mSession.finishKey(mWindow);
499 // } catch (RemoteException ex) {
500 // }
501 //}
502 }
503
504 public void dispatchTrackball(MotionEvent event, long eventTime) {
505 Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
506 //if (mSession != null && mSurface != null) {
507 // try {
508 // //mSession.finishKey(mWindow);
509 // } catch (RemoteException ex) {
510 // }
511 //}
512 }
513
514 public void dispatchAppVisibility(boolean visible) {
515 // The point of SurfaceView is to let the app control the surface.
516 }
517
518 public void dispatchGetNewSurface() {
519 SurfaceView surfaceView = mSurfaceView.get();
520 if (surfaceView != null) {
521 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
522 surfaceView.mHandler.sendMessage(msg);
523 }
524 }
525
526 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
527 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
528 }
529
530 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
531 }
532
533 int mCurWidth = -1;
534 int mCurHeight = -1;
535 }
536
537 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
538
539 private static final String LOG_TAG = "SurfaceHolder";
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700540 private int mSaveCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541
542 public boolean isCreating() {
543 return mIsCreating;
544 }
545
546 public void addCallback(Callback callback) {
547 synchronized (mCallbacks) {
548 // This is a linear search, but in practice we'll
549 // have only a couple callbacks, so it doesn't matter.
550 if (mCallbacks.contains(callback) == false) {
551 mCallbacks.add(callback);
552 }
553 }
554 }
555
556 public void removeCallback(Callback callback) {
557 synchronized (mCallbacks) {
558 mCallbacks.remove(callback);
559 }
560 }
561
562 public void setFixedSize(int width, int height) {
563 if (mRequestedWidth != width || mRequestedHeight != height) {
564 mRequestedWidth = width;
565 mRequestedHeight = height;
566 requestLayout();
567 }
568 }
569
570 public void setSizeFromLayout() {
571 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
572 mRequestedWidth = mRequestedHeight = -1;
573 requestLayout();
574 }
575 }
576
577 public void setFormat(int format) {
578 mRequestedFormat = format;
579 if (mWindow != null) {
580 updateWindow(false);
581 }
582 }
583
584 public void setType(int type) {
585 switch (type) {
586 case SURFACE_TYPE_NORMAL:
587 case SURFACE_TYPE_HARDWARE:
588 case SURFACE_TYPE_GPU:
589 case SURFACE_TYPE_PUSH_BUFFERS:
590 mRequestedType = type;
591 if (mWindow != null) {
592 updateWindow(false);
593 }
594 break;
595 }
596 }
597
598 public void setKeepScreenOn(boolean screenOn) {
599 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
600 msg.arg1 = screenOn ? 1 : 0;
601 mHandler.sendMessage(msg);
602 }
603
604 public Canvas lockCanvas() {
605 return internalLockCanvas(null);
606 }
607
608 public Canvas lockCanvas(Rect dirty) {
609 return internalLockCanvas(dirty);
610 }
611
612 private final Canvas internalLockCanvas(Rect dirty) {
613 if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
614 throw new BadSurfaceTypeException(
615 "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
616 }
617 mSurfaceLock.lock();
618
619 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
620 + mDrawingStopped + ", win=" + mWindow);
621
622 Canvas c = null;
623 if (!mDrawingStopped && mWindow != null) {
624 Rect frame = dirty != null ? dirty : mSurfaceFrame;
625 try {
626 c = mSurface.lockCanvas(frame);
627 } catch (Exception e) {
628 Log.e(LOG_TAG, "Exception locking surface", e);
629 }
630 }
631
632 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
633 if (c != null) {
634 mLastLockTime = SystemClock.uptimeMillis();
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700635 if (mScaled) {
636 mSaveCount = c.save();
637 mTranslator.translateCanvas(c);
638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 return c;
640 }
641
642 // If the Surface is not ready to be drawn, then return null,
643 // but throttle calls to this function so it isn't called more
644 // than every 100ms.
645 long now = SystemClock.uptimeMillis();
646 long nextTime = mLastLockTime + 100;
647 if (nextTime > now) {
648 try {
649 Thread.sleep(nextTime-now);
650 } catch (InterruptedException e) {
651 }
652 now = SystemClock.uptimeMillis();
653 }
654 mLastLockTime = now;
655 mSurfaceLock.unlock();
656
657 return null;
658 }
659
660 public void unlockCanvasAndPost(Canvas canvas) {
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700661 if (mScaled) {
662 canvas.restoreToCount(mSaveCount);
663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 mSurface.unlockCanvasAndPost(canvas);
665 mSurfaceLock.unlock();
666 }
667
668 public Surface getSurface() {
669 return mSurface;
670 }
671
672 public Rect getSurfaceFrame() {
673 return mSurfaceFrame;
674 }
675 };
676}