blob: 938104c8d7d5e67d0e0071286d882f1b23ec4f21 [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 Oshima38ed7d772009-07-21 14:39:34 -070020import android.content.res.Resources;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070021import android.content.res.CompatibilityInfo.Translator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.graphics.Canvas;
23import android.graphics.PixelFormat;
24import android.graphics.PorterDuff;
25import android.graphics.Rect;
26import android.graphics.Region;
27import android.os.Handler;
28import android.os.Message;
29import android.os.RemoteException;
30import android.os.SystemClock;
31import android.os.ParcelFileDescriptor;
32import android.util.AttributeSet;
33import android.util.Config;
34import android.util.Log;
35import java.util.ArrayList;
36
37import java.util.concurrent.locks.ReentrantLock;
38import java.lang.ref.WeakReference;
39
40/**
41 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
42 * You can control the format of this surface and, if you like, its size; the
43 * SurfaceView takes care of placing the surface at the correct location on the
44 * screen
45 *
46 * <p>The surface is Z ordered so that it is behind the window holding its
47 * SurfaceView; the SurfaceView punches a hole in its window to allow its
48 * surface to be displayed. The view hierarchy will take care of correctly
49 * compositing with the Surface any siblings of the SurfaceView that would
50 * normally appear on top of it. This can be used to place overlays such as
51 * buttons on top of the Surface, though note however that it can have an
52 * impact on performance since a full alpha-blended composite will be performed
53 * each time the Surface changes.
54 *
55 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
56 * which can be retrieved by calling {@link #getHolder}.
57 *
58 * <p>The Surface will be created for you while the SurfaceView's window is
59 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
60 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
61 * Surface is created and destroyed as the window is shown and hidden.
62 *
63 * <p>One of the purposes of this class is to provide a surface in which a
64 * secondary thread can render in to the screen. If you are going to use it
65 * this way, you need to be aware of some threading semantics:
66 *
67 * <ul>
68 * <li> All SurfaceView and
69 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
70 * from the thread running the SurfaceView's window (typically the main thread
71 * of the application). They thus need to correctly synchronize with any
72 * state that is also touched by the drawing thread.
73 * <li> You must ensure that the drawing thread only touches the underlying
74 * Surface while it is valid -- between
75 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
76 * and
77 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
78 * </ul>
79 */
80public class SurfaceView extends View {
81 static private final String TAG = "SurfaceView";
82 static private final boolean DEBUG = false;
83 static private final boolean localLOGV = DEBUG ? true : Config.LOGV;
84
85 final ArrayList<SurfaceHolder.Callback> mCallbacks
86 = new ArrayList<SurfaceHolder.Callback>();
87
88 final int[] mLocation = new int[2];
89
90 final ReentrantLock mSurfaceLock = new ReentrantLock();
91 final Surface mSurface = new Surface();
92 boolean mDrawingStopped = true;
93
94 final WindowManager.LayoutParams mLayout
95 = new WindowManager.LayoutParams();
96 IWindowSession mSession;
97 MyWindow mWindow;
98 final Rect mVisibleInsets = new Rect();
99 final Rect mWinFrame = new Rect();
100 final Rect mContentInsets = new Rect();
101
102 static final int KEEP_SCREEN_ON_MSG = 1;
103 static final int GET_NEW_SURFACE_MSG = 2;
104
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700105 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 boolean mIsCreating = false;
108
109 final Handler mHandler = new Handler() {
110 @Override
111 public void handleMessage(Message msg) {
112 switch (msg.what) {
113 case KEEP_SCREEN_ON_MSG: {
114 setKeepScreenOn(msg.arg1 != 0);
115 } break;
116 case GET_NEW_SURFACE_MSG: {
117 handleGetNewSurface();
118 } break;
119 }
120 }
121 };
122
123 boolean mRequestedVisible = false;
124 int mRequestedWidth = -1;
125 int mRequestedHeight = -1;
126 int mRequestedFormat = PixelFormat.OPAQUE;
127 int mRequestedType = -1;
128
129 boolean mHaveFrame = false;
130 boolean mDestroyReportNeeded = false;
131 boolean mNewSurfaceNeeded = false;
132 long mLastLockTime = 0;
133
134 boolean mVisible = false;
135 int mLeft = -1;
136 int mTop = -1;
137 int mWidth = -1;
138 int mHeight = -1;
139 int mFormat = -1;
140 int mType = -1;
141 final Rect mSurfaceFrame = new Rect();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700142 private Translator mTranslator;
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700143
144 // A flag to indicate that the Canvas has to be scaled
145 private boolean mScaleCanvas = false;
146 // A flag to indicate that the Canvas is in use and being scaled.
147 // This may remain to be false even if mScaleCanvas is true if the applicatio
148 // does not use the canvas (such as GLSurfaceView, VideoView).
149 private boolean mCanvasScaled = false;
150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 public SurfaceView(Context context) {
152 super(context);
153 setWillNotDraw(true);
154 }
155
156 public SurfaceView(Context context, AttributeSet attrs) {
157 super(context, attrs);
158 setWillNotDraw(true);
159 }
160
161 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
162 super(context, attrs, defStyle);
163 setWillNotDraw(true);
164 }
165
166 /**
167 * Return the SurfaceHolder providing access and control over this
168 * SurfaceView's underlying surface.
169 *
170 * @return SurfaceHolder The holder of the surface.
171 */
172 public SurfaceHolder getHolder() {
173 return mSurfaceHolder;
174 }
175
176 @Override
177 protected void onAttachedToWindow() {
178 super.onAttachedToWindow();
179 mParent.requestTransparentRegion(this);
180 mSession = getWindowSession();
181 mLayout.token = getWindowToken();
182 mLayout.setTitle("SurfaceView");
183 }
184
185 @Override
186 protected void onWindowVisibilityChanged(int visibility) {
187 super.onWindowVisibilityChanged(visibility);
188 mRequestedVisible = visibility == VISIBLE;
189 updateWindow(false);
190 }
191
192 @Override
193 protected void onDetachedFromWindow() {
194 mRequestedVisible = false;
195 updateWindow(false);
196 mHaveFrame = false;
197 if (mWindow != null) {
198 try {
199 mSession.remove(mWindow);
200 } catch (RemoteException ex) {
201 }
202 mWindow = null;
203 }
204 mSession = null;
205 mLayout.token = null;
206
207 super.onDetachedFromWindow();
208 }
209
210 @Override
211 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
212 int width = getDefaultSize(mRequestedWidth, widthMeasureSpec);
213 int height = getDefaultSize(mRequestedHeight, heightMeasureSpec);
214 setMeasuredDimension(width, height);
215 }
216
217 @Override
218 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
219 super.onScrollChanged(l, t, oldl, oldt);
220 updateWindow(false);
221 }
222
223 @Override
224 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
225 super.onSizeChanged(w, h, oldw, oldh);
226 updateWindow(false);
227 }
228
229 @Override
230 public boolean gatherTransparentRegion(Region region) {
231 boolean opaque = true;
232 if ((mPrivateFlags & SKIP_DRAW) == 0) {
233 // this view draws, remove it from the transparent region
234 opaque = super.gatherTransparentRegion(region);
235 } else if (region != null) {
236 int w = getWidth();
237 int h = getHeight();
238 if (w>0 && h>0) {
239 getLocationInWindow(mLocation);
240 // otherwise, punch a hole in the whole hierarchy
241 int l = mLocation[0];
242 int t = mLocation[1];
243 region.op(l, t, l+w, t+h, Region.Op.UNION);
244 }
245 }
246 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
247 opaque = false;
248 }
249 return opaque;
250 }
251
252 @Override
253 public void draw(Canvas canvas) {
254 // draw() is not called when SKIP_DRAW is set
255 if ((mPrivateFlags & SKIP_DRAW) == 0) {
256 // punch a whole in the view-hierarchy below us
257 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
258 }
259 super.draw(canvas);
260 }
261
262 @Override
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700263 public boolean dispatchTouchEvent(MotionEvent event) {
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700264 if (mTranslator == null || mCanvasScaled) {
265 // Use the event as is if no scaling is required, or the surface's canvas
266 // is scaled too.
267 return super.dispatchTouchEvent(event);
268 } else {
269 // The surface is in native size, so we need to scale the event
270 // back to native location.
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700271 MotionEvent scaledBack = MotionEvent.obtain(event);
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700272 // scale back to original
273 scaledBack.scale(mTranslator.applicationScale);
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700274 try {
275 return super.dispatchTouchEvent(scaledBack);
276 } finally {
277 scaledBack.recycle();
278 }
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700279 }
280 }
281
282 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 protected void dispatchDraw(Canvas canvas) {
284 // if SKIP_DRAW is cleared, draw() has already punched a hole
285 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
286 // punch a whole in the view-hierarchy below us
287 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
288 }
289 // reposition ourselves where the surface is
290 mHaveFrame = true;
291 updateWindow(false);
292 super.dispatchDraw(canvas);
293 }
294
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700295 /**
296 * Hack to allow special layering of windows. The type is one of the
297 * types in WindowManager.LayoutParams. This is a hack so:
298 * @hide
299 */
300 public void setWindowType(int type) {
301 mWindowType = type;
302 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 private void updateWindow(boolean force) {
305 if (!mHaveFrame) {
306 return;
307 }
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700308 ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
309 mTranslator = viewRoot.mTranslator;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700310
311 float appScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700312
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700313 Resources res = getContext().getResources();
314 if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700315 mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700316 }
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 int myWidth = mRequestedWidth;
319 if (myWidth <= 0) myWidth = getWidth();
320 int myHeight = mRequestedHeight;
321 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700322
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700323 // Use requested size if the app specified the size of the view
324 // and let the flinger to scale up. Otherwise, use the native size
325 // (* appScale) and assume the application can handle it.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700326 if (mRequestedWidth <= 0 && mTranslator != null) {
Mitsuru Oshima61324e52009-07-21 15:40:36 -0700327 myWidth = (int) (myWidth * appScale + 0.5f);
328 myHeight = (int) (myHeight * appScale + 0.5f);
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700329 mScaleCanvas = true;
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700330 } else {
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700331 mScaleCanvas = false;
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700332 }
333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 getLocationInWindow(mLocation);
335 final boolean creating = mWindow == null;
336 final boolean formatChanged = mFormat != mRequestedFormat;
337 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
338 final boolean visibleChanged = mVisible != mRequestedVisible
339 || mNewSurfaceNeeded;
340 final boolean typeChanged = mType != mRequestedType;
341 if (force || creating || formatChanged || sizeChanged || visibleChanged
342 || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]) {
343
344 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
345 + " format=" + formatChanged + " size=" + sizeChanged
346 + " visible=" + visibleChanged
347 + " left=" + (mLeft != mLocation[0])
348 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 try {
351 final boolean visible = mVisible = mRequestedVisible;
352 mLeft = mLocation[0];
353 mTop = mLocation[1];
354 mWidth = myWidth;
355 mHeight = myHeight;
356 mFormat = mRequestedFormat;
357 mType = mRequestedType;
358
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700359 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
360
361 // Places the window relative
362 mLayout.x = mLeft;
363 mLayout.y = mTop;
364 mLayout.width = getWidth();
365 mLayout.height = getHeight();
366 if (mTranslator != null) {
367 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
368 }
369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 mLayout.format = mRequestedFormat;
371 mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
372 | WindowManager.LayoutParams.FLAG_SCALED
373 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
374 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
375 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700376 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
377 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379
380 mLayout.memoryType = mRequestedType;
381
382 if (mWindow == null) {
383 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700384 mLayout.type = mWindowType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
386 mSession.add(mWindow, mLayout,
387 mVisible ? VISIBLE : GONE, mContentInsets);
388 }
389
390 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
391 reportSurfaceDestroyed();
392 }
393
394 mNewSurfaceNeeded = false;
395
396 mSurfaceLock.lock();
397 mDrawingStopped = !visible;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 final int relayoutResult = mSession.relayout(
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700400 mWindow, mLayout, mWidth, mHeight,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
402 mVisibleInsets, mSurface);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
405 + ", vis=" + visible + ", frame=" + mWinFrame);
406 mSurfaceFrame.left = 0;
407 mSurfaceFrame.top = 0;
408 mSurfaceFrame.right = mWinFrame.width();
409 mSurfaceFrame.bottom = mWinFrame.height();
410 mSurfaceLock.unlock();
411
412 try {
413 if (visible) {
414 mDestroyReportNeeded = true;
415
416 SurfaceHolder.Callback callbacks[];
417 synchronized (mCallbacks) {
418 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
419 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421
422 if (visibleChanged) {
423 mIsCreating = true;
424 for (SurfaceHolder.Callback c : callbacks) {
425 c.surfaceCreated(mSurfaceHolder);
426 }
427 }
428 if (creating || formatChanged || sizeChanged
429 || visibleChanged) {
430 for (SurfaceHolder.Callback c : callbacks) {
431 c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
432 }
433 }
434 }
435 } finally {
436 mIsCreating = false;
437 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
438 mSession.finishDrawing(mWindow);
439 }
440 }
441 } catch (RemoteException ex) {
442 }
443 if (localLOGV) Log.v(
444 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
445 " w=" + mLayout.width + " h=" + mLayout.height +
446 ", frame=" + mSurfaceFrame);
447 }
448 }
449
450 private void reportSurfaceDestroyed() {
451 if (mDestroyReportNeeded) {
452 mDestroyReportNeeded = false;
453 SurfaceHolder.Callback callbacks[];
454 synchronized (mCallbacks) {
455 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
456 mCallbacks.toArray(callbacks);
457 }
458 for (SurfaceHolder.Callback c : callbacks) {
459 c.surfaceDestroyed(mSurfaceHolder);
460 }
461 }
462 super.onDetachedFromWindow();
463 }
464
465 void handleGetNewSurface() {
466 mNewSurfaceNeeded = true;
467 updateWindow(false);
468 }
469
470 private static class MyWindow extends IWindow.Stub {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700471 private final WeakReference<SurfaceView> mSurfaceView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472
473 public MyWindow(SurfaceView surfaceView) {
474 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
475 }
476
477 public void resized(int w, int h, Rect coveredInsets,
478 Rect visibleInsets, boolean reportDraw) {
479 SurfaceView surfaceView = mSurfaceView.get();
480 if (surfaceView != null) {
481 if (localLOGV) Log.v(
482 "SurfaceView", surfaceView + " got resized: w=" +
483 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
484 synchronized (this) {
485 if (mCurWidth != w || mCurHeight != h) {
486 mCurWidth = w;
487 mCurHeight = h;
488 }
489 if (reportDraw) {
490 try {
491 surfaceView.mSession.finishDrawing(surfaceView.mWindow);
492 } catch (RemoteException e) {
493 }
494 }
495 }
496 }
497 }
498
499 public void dispatchKey(KeyEvent event) {
500 SurfaceView surfaceView = mSurfaceView.get();
501 if (surfaceView != null) {
502 //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
503 if (surfaceView.mSession != null && surfaceView.mSurface != null) {
504 try {
505 surfaceView.mSession.finishKey(surfaceView.mWindow);
506 } catch (RemoteException ex) {
507 }
508 }
509 }
510 }
511
512 public void dispatchPointer(MotionEvent event, long eventTime) {
513 Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
514 //if (mSession != null && mSurface != null) {
515 // try {
516 // //mSession.finishKey(mWindow);
517 // } catch (RemoteException ex) {
518 // }
519 //}
520 }
521
522 public void dispatchTrackball(MotionEvent event, long eventTime) {
523 Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
524 //if (mSession != null && mSurface != null) {
525 // try {
526 // //mSession.finishKey(mWindow);
527 // } catch (RemoteException ex) {
528 // }
529 //}
530 }
531
532 public void dispatchAppVisibility(boolean visible) {
533 // The point of SurfaceView is to let the app control the surface.
534 }
535
536 public void dispatchGetNewSurface() {
537 SurfaceView surfaceView = mSurfaceView.get();
538 if (surfaceView != null) {
539 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
540 surfaceView.mHandler.sendMessage(msg);
541 }
542 }
543
544 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
545 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
546 }
547
548 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
549 }
550
551 int mCurWidth = -1;
552 int mCurHeight = -1;
553 }
554
555 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
556
557 private static final String LOG_TAG = "SurfaceHolder";
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700558 private int mSaveCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559
560 public boolean isCreating() {
561 return mIsCreating;
562 }
563
564 public void addCallback(Callback callback) {
565 synchronized (mCallbacks) {
566 // This is a linear search, but in practice we'll
567 // have only a couple callbacks, so it doesn't matter.
568 if (mCallbacks.contains(callback) == false) {
569 mCallbacks.add(callback);
570 }
571 }
572 }
573
574 public void removeCallback(Callback callback) {
575 synchronized (mCallbacks) {
576 mCallbacks.remove(callback);
577 }
578 }
579
580 public void setFixedSize(int width, int height) {
581 if (mRequestedWidth != width || mRequestedHeight != height) {
582 mRequestedWidth = width;
583 mRequestedHeight = height;
584 requestLayout();
585 }
586 }
587
588 public void setSizeFromLayout() {
589 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
590 mRequestedWidth = mRequestedHeight = -1;
591 requestLayout();
592 }
593 }
594
595 public void setFormat(int format) {
596 mRequestedFormat = format;
597 if (mWindow != null) {
598 updateWindow(false);
599 }
600 }
601
602 public void setType(int type) {
603 switch (type) {
604 case SURFACE_TYPE_NORMAL:
605 case SURFACE_TYPE_HARDWARE:
606 case SURFACE_TYPE_GPU:
607 case SURFACE_TYPE_PUSH_BUFFERS:
608 mRequestedType = type;
609 if (mWindow != null) {
610 updateWindow(false);
611 }
612 break;
613 }
614 }
615
616 public void setKeepScreenOn(boolean screenOn) {
617 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
618 msg.arg1 = screenOn ? 1 : 0;
619 mHandler.sendMessage(msg);
620 }
621
622 public Canvas lockCanvas() {
623 return internalLockCanvas(null);
624 }
625
626 public Canvas lockCanvas(Rect dirty) {
627 return internalLockCanvas(dirty);
628 }
629
630 private final Canvas internalLockCanvas(Rect dirty) {
631 if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
632 throw new BadSurfaceTypeException(
633 "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
634 }
635 mSurfaceLock.lock();
636
637 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
638 + mDrawingStopped + ", win=" + mWindow);
639
640 Canvas c = null;
641 if (!mDrawingStopped && mWindow != null) {
642 Rect frame = dirty != null ? dirty : mSurfaceFrame;
643 try {
644 c = mSurface.lockCanvas(frame);
645 } catch (Exception e) {
646 Log.e(LOG_TAG, "Exception locking surface", e);
647 }
648 }
649
650 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
651 if (c != null) {
652 mLastLockTime = SystemClock.uptimeMillis();
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700653 if (mScaleCanvas) {
654 // When the canvas is scaled, don't scale back the event's location.
655 mCanvasScaled = true;
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700656 mSaveCount = c.save();
657 mTranslator.translateCanvas(c);
658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 return c;
660 }
661
662 // If the Surface is not ready to be drawn, then return null,
663 // but throttle calls to this function so it isn't called more
664 // than every 100ms.
665 long now = SystemClock.uptimeMillis();
666 long nextTime = mLastLockTime + 100;
667 if (nextTime > now) {
668 try {
669 Thread.sleep(nextTime-now);
670 } catch (InterruptedException e) {
671 }
672 now = SystemClock.uptimeMillis();
673 }
674 mLastLockTime = now;
675 mSurfaceLock.unlock();
676
677 return null;
678 }
679
680 public void unlockCanvasAndPost(Canvas canvas) {
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700681 if (mCanvasScaled) {
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700682 canvas.restoreToCount(mSaveCount);
683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 mSurface.unlockCanvasAndPost(canvas);
685 mSurfaceLock.unlock();
686 }
687
688 public Surface getSurface() {
689 return mSurface;
690 }
691
692 public Rect getSurfaceFrame() {
693 return mSurfaceFrame;
694 }
695 };
696}