blob: aa701af633fe987b6bb0d9ce99720e3e12be5fce [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 Oshima841f13c2009-07-17 17:23:31 -0700260 mTranslator.translateEventInScreenToAppWindow(event);
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 Oshima841f13c2009-07-17 17:23:31 -0700299 ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
300 mTranslator = viewRoot.mTranslator;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700301
302 float appScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303
304 int myWidth = mRequestedWidth;
305 if (myWidth <= 0) myWidth = getWidth();
306 int myHeight = mRequestedHeight;
307 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700308
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700309 // Use original size if the app specified the size of the view,
310 // and let the flinger to scale up.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700311 if (mRequestedWidth <= 0 && mTranslator != null) {
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700312 myWidth *= appScale;
313 myHeight *= appScale;
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700314 mScaled = true;
315 } else {
316 mScaled = false;
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700317 }
318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 getLocationInWindow(mLocation);
320 final boolean creating = mWindow == null;
321 final boolean formatChanged = mFormat != mRequestedFormat;
322 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
323 final boolean visibleChanged = mVisible != mRequestedVisible
324 || mNewSurfaceNeeded;
325 final boolean typeChanged = mType != mRequestedType;
326 if (force || creating || formatChanged || sizeChanged || visibleChanged
327 || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]) {
328
329 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
330 + " format=" + formatChanged + " size=" + sizeChanged
331 + " visible=" + visibleChanged
332 + " left=" + (mLeft != mLocation[0])
333 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 try {
336 final boolean visible = mVisible = mRequestedVisible;
337 mLeft = mLocation[0];
338 mTop = mLocation[1];
339 mWidth = myWidth;
340 mHeight = myHeight;
341 mFormat = mRequestedFormat;
342 mType = mRequestedType;
343
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700344 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
345
346 // Places the window relative
347 mLayout.x = mLeft;
348 mLayout.y = mTop;
349 mLayout.width = getWidth();
350 mLayout.height = getHeight();
351 if (mTranslator != null) {
352 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
353 }
354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 mLayout.format = mRequestedFormat;
356 mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
357 | WindowManager.LayoutParams.FLAG_SCALED
358 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
359 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
360 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700361 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
362 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
363 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364
365 mLayout.memoryType = mRequestedType;
366
367 if (mWindow == null) {
368 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700369 mLayout.type = mWindowType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
371 mSession.add(mWindow, mLayout,
372 mVisible ? VISIBLE : GONE, mContentInsets);
373 }
374
375 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
376 reportSurfaceDestroyed();
377 }
378
379 mNewSurfaceNeeded = false;
380
381 mSurfaceLock.lock();
382 mDrawingStopped = !visible;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 final int relayoutResult = mSession.relayout(
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700385 mWindow, mLayout, mWidth, mHeight,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
387 mVisibleInsets, mSurface);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
390 + ", vis=" + visible + ", frame=" + mWinFrame);
391 mSurfaceFrame.left = 0;
392 mSurfaceFrame.top = 0;
393 mSurfaceFrame.right = mWinFrame.width();
394 mSurfaceFrame.bottom = mWinFrame.height();
395 mSurfaceLock.unlock();
396
397 try {
398 if (visible) {
399 mDestroyReportNeeded = true;
400
401 SurfaceHolder.Callback callbacks[];
402 synchronized (mCallbacks) {
403 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
404 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406
407 if (visibleChanged) {
408 mIsCreating = true;
409 for (SurfaceHolder.Callback c : callbacks) {
410 c.surfaceCreated(mSurfaceHolder);
411 }
412 }
413 if (creating || formatChanged || sizeChanged
414 || visibleChanged) {
415 for (SurfaceHolder.Callback c : callbacks) {
416 c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
417 }
418 }
419 }
420 } finally {
421 mIsCreating = false;
422 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
423 mSession.finishDrawing(mWindow);
424 }
425 }
426 } catch (RemoteException ex) {
427 }
428 if (localLOGV) Log.v(
429 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
430 " w=" + mLayout.width + " h=" + mLayout.height +
431 ", frame=" + mSurfaceFrame);
432 }
433 }
434
435 private void reportSurfaceDestroyed() {
436 if (mDestroyReportNeeded) {
437 mDestroyReportNeeded = false;
438 SurfaceHolder.Callback callbacks[];
439 synchronized (mCallbacks) {
440 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
441 mCallbacks.toArray(callbacks);
442 }
443 for (SurfaceHolder.Callback c : callbacks) {
444 c.surfaceDestroyed(mSurfaceHolder);
445 }
446 }
447 super.onDetachedFromWindow();
448 }
449
450 void handleGetNewSurface() {
451 mNewSurfaceNeeded = true;
452 updateWindow(false);
453 }
454
455 private static class MyWindow extends IWindow.Stub {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700456 private final WeakReference<SurfaceView> mSurfaceView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457
458 public MyWindow(SurfaceView surfaceView) {
459 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
460 }
461
462 public void resized(int w, int h, Rect coveredInsets,
463 Rect visibleInsets, boolean reportDraw) {
464 SurfaceView surfaceView = mSurfaceView.get();
465 if (surfaceView != null) {
466 if (localLOGV) Log.v(
467 "SurfaceView", surfaceView + " got resized: w=" +
468 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
469 synchronized (this) {
470 if (mCurWidth != w || mCurHeight != h) {
471 mCurWidth = w;
472 mCurHeight = h;
473 }
474 if (reportDraw) {
475 try {
476 surfaceView.mSession.finishDrawing(surfaceView.mWindow);
477 } catch (RemoteException e) {
478 }
479 }
480 }
481 }
482 }
483
484 public void dispatchKey(KeyEvent event) {
485 SurfaceView surfaceView = mSurfaceView.get();
486 if (surfaceView != null) {
487 //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
488 if (surfaceView.mSession != null && surfaceView.mSurface != null) {
489 try {
490 surfaceView.mSession.finishKey(surfaceView.mWindow);
491 } catch (RemoteException ex) {
492 }
493 }
494 }
495 }
496
497 public void dispatchPointer(MotionEvent event, long eventTime) {
498 Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
499 //if (mSession != null && mSurface != null) {
500 // try {
501 // //mSession.finishKey(mWindow);
502 // } catch (RemoteException ex) {
503 // }
504 //}
505 }
506
507 public void dispatchTrackball(MotionEvent event, long eventTime) {
508 Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
509 //if (mSession != null && mSurface != null) {
510 // try {
511 // //mSession.finishKey(mWindow);
512 // } catch (RemoteException ex) {
513 // }
514 //}
515 }
516
517 public void dispatchAppVisibility(boolean visible) {
518 // The point of SurfaceView is to let the app control the surface.
519 }
520
521 public void dispatchGetNewSurface() {
522 SurfaceView surfaceView = mSurfaceView.get();
523 if (surfaceView != null) {
524 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
525 surfaceView.mHandler.sendMessage(msg);
526 }
527 }
528
529 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
530 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
531 }
532
533 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
534 }
535
536 int mCurWidth = -1;
537 int mCurHeight = -1;
538 }
539
540 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
541
542 private static final String LOG_TAG = "SurfaceHolder";
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700543 private int mSaveCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544
545 public boolean isCreating() {
546 return mIsCreating;
547 }
548
549 public void addCallback(Callback callback) {
550 synchronized (mCallbacks) {
551 // This is a linear search, but in practice we'll
552 // have only a couple callbacks, so it doesn't matter.
553 if (mCallbacks.contains(callback) == false) {
554 mCallbacks.add(callback);
555 }
556 }
557 }
558
559 public void removeCallback(Callback callback) {
560 synchronized (mCallbacks) {
561 mCallbacks.remove(callback);
562 }
563 }
564
565 public void setFixedSize(int width, int height) {
566 if (mRequestedWidth != width || mRequestedHeight != height) {
567 mRequestedWidth = width;
568 mRequestedHeight = height;
569 requestLayout();
570 }
571 }
572
573 public void setSizeFromLayout() {
574 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
575 mRequestedWidth = mRequestedHeight = -1;
576 requestLayout();
577 }
578 }
579
580 public void setFormat(int format) {
581 mRequestedFormat = format;
582 if (mWindow != null) {
583 updateWindow(false);
584 }
585 }
586
587 public void setType(int type) {
588 switch (type) {
589 case SURFACE_TYPE_NORMAL:
590 case SURFACE_TYPE_HARDWARE:
591 case SURFACE_TYPE_GPU:
592 case SURFACE_TYPE_PUSH_BUFFERS:
593 mRequestedType = type;
594 if (mWindow != null) {
595 updateWindow(false);
596 }
597 break;
598 }
599 }
600
601 public void setKeepScreenOn(boolean screenOn) {
602 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
603 msg.arg1 = screenOn ? 1 : 0;
604 mHandler.sendMessage(msg);
605 }
606
607 public Canvas lockCanvas() {
608 return internalLockCanvas(null);
609 }
610
611 public Canvas lockCanvas(Rect dirty) {
612 return internalLockCanvas(dirty);
613 }
614
615 private final Canvas internalLockCanvas(Rect dirty) {
616 if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
617 throw new BadSurfaceTypeException(
618 "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
619 }
620 mSurfaceLock.lock();
621
622 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
623 + mDrawingStopped + ", win=" + mWindow);
624
625 Canvas c = null;
626 if (!mDrawingStopped && mWindow != null) {
627 Rect frame = dirty != null ? dirty : mSurfaceFrame;
628 try {
629 c = mSurface.lockCanvas(frame);
630 } catch (Exception e) {
631 Log.e(LOG_TAG, "Exception locking surface", e);
632 }
633 }
634
635 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
636 if (c != null) {
637 mLastLockTime = SystemClock.uptimeMillis();
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700638 if (mScaled) {
639 mSaveCount = c.save();
640 mTranslator.translateCanvas(c);
641 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 return c;
643 }
644
645 // If the Surface is not ready to be drawn, then return null,
646 // but throttle calls to this function so it isn't called more
647 // than every 100ms.
648 long now = SystemClock.uptimeMillis();
649 long nextTime = mLastLockTime + 100;
650 if (nextTime > now) {
651 try {
652 Thread.sleep(nextTime-now);
653 } catch (InterruptedException e) {
654 }
655 now = SystemClock.uptimeMillis();
656 }
657 mLastLockTime = now;
658 mSurfaceLock.unlock();
659
660 return null;
661 }
662
663 public void unlockCanvasAndPost(Canvas canvas) {
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700664 if (mScaled) {
665 canvas.restoreToCount(mSaveCount);
666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 mSurface.unlockCanvasAndPost(canvas);
668 mSurfaceLock.unlock();
669 }
670
671 public Surface getSurface() {
672 return mSurface;
673 }
674
675 public Rect getSurfaceFrame() {
676 return mSurfaceFrame;
677 }
678 };
679}