blob: ea879ed94358817fc2ec21e0da761f40368ef268 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Dianne Hackborn72c82ab2009-08-11 21:13:54 -070019import com.android.internal.view.BaseIWindow;
20
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070021import android.content.Context;
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -070022import android.content.res.Resources;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070023import android.content.res.CompatibilityInfo.Translator;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070024import android.graphics.Canvas;
25import android.graphics.PixelFormat;
26import android.graphics.PorterDuff;
27import android.graphics.Rect;
28import android.graphics.Region;
29import android.os.Handler;
30import android.os.Message;
31import android.os.RemoteException;
32import android.os.SystemClock;
33import android.os.ParcelFileDescriptor;
34import android.util.AttributeSet;
35import android.util.Config;
36import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070037
Jon Larimer9bdf5762009-01-02 18:55:15 -050038import java.lang.ref.WeakReference;
39import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070040import java.util.concurrent.locks.ReentrantLock;
The Android Open Source Projectb7986892009-01-09 17:51:23 -080041import java.lang.ref.WeakReference;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070042
43/**
44 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
45 * You can control the format of this surface and, if you like, its size; the
46 * SurfaceView takes care of placing the surface at the correct location on the
47 * screen
48 *
49 * <p>The surface is Z ordered so that it is behind the window holding its
50 * SurfaceView; the SurfaceView punches a hole in its window to allow its
51 * surface to be displayed. The view hierarchy will take care of correctly
52 * compositing with the Surface any siblings of the SurfaceView that would
53 * normally appear on top of it. This can be used to place overlays such as
54 * buttons on top of the Surface, though note however that it can have an
55 * impact on performance since a full alpha-blended composite will be performed
56 * each time the Surface changes.
57 *
58 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
59 * which can be retrieved by calling {@link #getHolder}.
60 *
61 * <p>The Surface will be created for you while the SurfaceView's window is
62 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
63 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
64 * Surface is created and destroyed as the window is shown and hidden.
65 *
66 * <p>One of the purposes of this class is to provide a surface in which a
67 * secondary thread can render in to the screen. If you are going to use it
68 * this way, you need to be aware of some threading semantics:
69 *
70 * <ul>
71 * <li> All SurfaceView and
72 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
73 * from the thread running the SurfaceView's window (typically the main thread
74 * of the application). They thus need to correctly synchronize with any
75 * state that is also touched by the drawing thread.
76 * <li> You must ensure that the drawing thread only touches the underlying
77 * Surface while it is valid -- between
78 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
79 * and
80 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
81 * </ul>
82 */
83public class SurfaceView extends View {
84 static private final String TAG = "SurfaceView";
85 static private final boolean DEBUG = false;
86 static private final boolean localLOGV = DEBUG ? true : Config.LOGV;
87
88 final ArrayList<SurfaceHolder.Callback> mCallbacks
89 = new ArrayList<SurfaceHolder.Callback>();
90
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080091 final int[] mLocation = new int[2];
92
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070093 final ReentrantLock mSurfaceLock = new ReentrantLock();
94 final Surface mSurface = new Surface();
95 boolean mDrawingStopped = true;
96
97 final WindowManager.LayoutParams mLayout
98 = new WindowManager.LayoutParams();
99 IWindowSession mSession;
100 MyWindow mWindow;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800101 final Rect mVisibleInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700102 final Rect mWinFrame = new Rect();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800103 final Rect mContentInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700104
105 static final int KEEP_SCREEN_ON_MSG = 1;
106 static final int GET_NEW_SURFACE_MSG = 2;
107
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700108 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
109
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700110 boolean mIsCreating = false;
111
112 final Handler mHandler = new Handler() {
113 @Override
114 public void handleMessage(Message msg) {
115 switch (msg.what) {
116 case KEEP_SCREEN_ON_MSG: {
117 setKeepScreenOn(msg.arg1 != 0);
118 } break;
119 case GET_NEW_SURFACE_MSG: {
120 handleGetNewSurface();
121 } break;
122 }
123 }
124 };
125
126 boolean mRequestedVisible = false;
127 int mRequestedWidth = -1;
128 int mRequestedHeight = -1;
129 int mRequestedFormat = PixelFormat.OPAQUE;
130 int mRequestedType = -1;
131
132 boolean mHaveFrame = false;
133 boolean mDestroyReportNeeded = false;
134 boolean mNewSurfaceNeeded = false;
135 long mLastLockTime = 0;
136
137 boolean mVisible = false;
138 int mLeft = -1;
139 int mTop = -1;
140 int mWidth = -1;
141 int mHeight = -1;
142 int mFormat = -1;
143 int mType = -1;
144 final Rect mSurfaceFrame = new Rect();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700145 private Translator mTranslator;
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700146
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700147 public SurfaceView(Context context) {
148 super(context);
149 setWillNotDraw(true);
150 }
151
152 public SurfaceView(Context context, AttributeSet attrs) {
153 super(context, attrs);
154 setWillNotDraw(true);
155 }
156
157 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
158 super(context, attrs, defStyle);
159 setWillNotDraw(true);
160 }
161
162 /**
163 * Return the SurfaceHolder providing access and control over this
164 * SurfaceView's underlying surface.
165 *
166 * @return SurfaceHolder The holder of the surface.
167 */
168 public SurfaceHolder getHolder() {
169 return mSurfaceHolder;
170 }
171
172 @Override
173 protected void onAttachedToWindow() {
174 super.onAttachedToWindow();
175 mParent.requestTransparentRegion(this);
176 mSession = getWindowSession();
177 mLayout.token = getWindowToken();
178 mLayout.setTitle("SurfaceView");
179 }
180
181 @Override
182 protected void onWindowVisibilityChanged(int visibility) {
183 super.onWindowVisibilityChanged(visibility);
184 mRequestedVisible = visibility == VISIBLE;
185 updateWindow(false);
186 }
187
188 @Override
189 protected void onDetachedFromWindow() {
190 mRequestedVisible = false;
191 updateWindow(false);
192 mHaveFrame = false;
193 if (mWindow != null) {
194 try {
195 mSession.remove(mWindow);
196 } catch (RemoteException ex) {
197 }
198 mWindow = null;
199 }
200 mSession = null;
201 mLayout.token = null;
202
203 super.onDetachedFromWindow();
204 }
205
206 @Override
207 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
208 int width = getDefaultSize(mRequestedWidth, widthMeasureSpec);
209 int height = getDefaultSize(mRequestedHeight, heightMeasureSpec);
210 setMeasuredDimension(width, height);
211 }
212
213 @Override
214 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
215 super.onScrollChanged(l, t, oldl, oldt);
216 updateWindow(false);
217 }
218
219 @Override
220 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
221 super.onSizeChanged(w, h, oldw, oldh);
222 updateWindow(false);
223 }
224
225 @Override
226 public boolean gatherTransparentRegion(Region region) {
227 boolean opaque = true;
228 if ((mPrivateFlags & SKIP_DRAW) == 0) {
229 // this view draws, remove it from the transparent region
230 opaque = super.gatherTransparentRegion(region);
231 } else if (region != null) {
232 int w = getWidth();
233 int h = getHeight();
234 if (w>0 && h>0) {
235 getLocationInWindow(mLocation);
236 // otherwise, punch a hole in the whole hierarchy
237 int l = mLocation[0];
238 int t = mLocation[1];
239 region.op(l, t, l+w, t+h, Region.Op.UNION);
240 }
241 }
242 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
243 opaque = false;
244 }
245 return opaque;
246 }
247
248 @Override
249 public void draw(Canvas canvas) {
250 // draw() is not called when SKIP_DRAW is set
251 if ((mPrivateFlags & SKIP_DRAW) == 0) {
252 // punch a whole in the view-hierarchy below us
253 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
254 }
255 super.draw(canvas);
256 }
257
258 @Override
259 protected void dispatchDraw(Canvas canvas) {
260 // if SKIP_DRAW is cleared, draw() has already punched a hole
261 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
262 // punch a whole in the view-hierarchy below us
263 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
264 }
265 // reposition ourselves where the surface is
266 mHaveFrame = true;
267 updateWindow(false);
268 super.dispatchDraw(canvas);
269 }
270
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700271 /**
272 * Hack to allow special layering of windows. The type is one of the
273 * types in WindowManager.LayoutParams. This is a hack so:
274 * @hide
275 */
276 public void setWindowType(int type) {
277 mWindowType = type;
278 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700279
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700280 private void updateWindow(boolean force) {
281 if (!mHaveFrame) {
282 return;
283 }
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700284 ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
Joe Onorato168173a2009-08-12 21:40:29 -0700285 if (viewRoot != null) {
286 mTranslator = viewRoot.mTranslator;
287 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700288
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700289 Resources res = getContext().getResources();
290 if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700291 mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700292 }
293
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700294 int myWidth = mRequestedWidth;
295 if (myWidth <= 0) myWidth = getWidth();
296 int myHeight = mRequestedHeight;
297 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700298
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700299 getLocationInWindow(mLocation);
300 final boolean creating = mWindow == null;
301 final boolean formatChanged = mFormat != mRequestedFormat;
302 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
303 final boolean visibleChanged = mVisible != mRequestedVisible
304 || mNewSurfaceNeeded;
305 final boolean typeChanged = mType != mRequestedType;
306 if (force || creating || formatChanged || sizeChanged || visibleChanged
307 || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]) {
308
309 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
310 + " format=" + formatChanged + " size=" + sizeChanged
311 + " visible=" + visibleChanged
312 + " left=" + (mLeft != mLocation[0])
313 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700314
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700315 try {
316 final boolean visible = mVisible = mRequestedVisible;
317 mLeft = mLocation[0];
318 mTop = mLocation[1];
319 mWidth = myWidth;
320 mHeight = myHeight;
321 mFormat = mRequestedFormat;
322 mType = mRequestedType;
323
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700324 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
325
326 // Places the window relative
327 mLayout.x = mLeft;
328 mLayout.y = mTop;
329 mLayout.width = getWidth();
330 mLayout.height = getHeight();
331 if (mTranslator != null) {
332 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
333 }
334
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700335 mLayout.format = mRequestedFormat;
336 mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
337 | WindowManager.LayoutParams.FLAG_SCALED
338 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
339 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
340 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700341 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
342 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
343 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700344
345 mLayout.memoryType = mRequestedType;
346
347 if (mWindow == null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500348 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700349 mLayout.type = mWindowType;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700350 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
351 mSession.add(mWindow, mLayout,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800352 mVisible ? VISIBLE : GONE, mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700353 }
354
355 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
356 reportSurfaceDestroyed();
357 }
358
359 mNewSurfaceNeeded = false;
360
361 mSurfaceLock.lock();
362 mDrawingStopped = !visible;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700363
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700364 final int relayoutResult = mSession.relayout(
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700365 mWindow, mLayout, mWidth, mHeight,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800366 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
367 mVisibleInsets, mSurface);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700368
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700369 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
370 + ", vis=" + visible + ", frame=" + mWinFrame);
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700371
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700372 mSurfaceFrame.left = 0;
373 mSurfaceFrame.top = 0;
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700374 if (mTranslator == null) {
375 mSurfaceFrame.right = mWinFrame.width();
376 mSurfaceFrame.bottom = mWinFrame.height();
377 } else {
378 float appInvertedScale = mTranslator.applicationInvertedScale;
379 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
380 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
381 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700382 mSurfaceLock.unlock();
383
384 try {
385 if (visible) {
386 mDestroyReportNeeded = true;
387
388 SurfaceHolder.Callback callbacks[];
389 synchronized (mCallbacks) {
390 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
391 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700392 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700393
394 if (visibleChanged) {
395 mIsCreating = true;
396 for (SurfaceHolder.Callback c : callbacks) {
397 c.surfaceCreated(mSurfaceHolder);
398 }
399 }
400 if (creating || formatChanged || sizeChanged
401 || visibleChanged) {
402 for (SurfaceHolder.Callback c : callbacks) {
403 c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
404 }
405 }
406 }
407 } finally {
408 mIsCreating = false;
409 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
410 mSession.finishDrawing(mWindow);
411 }
412 }
413 } catch (RemoteException ex) {
414 }
415 if (localLOGV) Log.v(
416 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
417 " w=" + mLayout.width + " h=" + mLayout.height +
418 ", frame=" + mSurfaceFrame);
419 }
420 }
421
422 private void reportSurfaceDestroyed() {
423 if (mDestroyReportNeeded) {
424 mDestroyReportNeeded = false;
425 SurfaceHolder.Callback callbacks[];
426 synchronized (mCallbacks) {
427 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
428 mCallbacks.toArray(callbacks);
429 }
430 for (SurfaceHolder.Callback c : callbacks) {
431 c.surfaceDestroyed(mSurfaceHolder);
432 }
433 }
434 super.onDetachedFromWindow();
435 }
436
437 void handleGetNewSurface() {
438 mNewSurfaceNeeded = true;
439 updateWindow(false);
440 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800441
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700442 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700443 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500444
445 public MyWindow(SurfaceView surfaceView) {
446 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
447 }
448
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800449 public void resized(int w, int h, Rect coveredInsets,
450 Rect visibleInsets, boolean reportDraw) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500451 SurfaceView surfaceView = mSurfaceView.get();
452 if (surfaceView != null) {
453 if (localLOGV) Log.v(
454 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800455 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500456 synchronized (this) {
457 if (mCurWidth != w || mCurHeight != h) {
458 mCurWidth = w;
459 mCurHeight = h;
460 }
461 if (reportDraw) {
462 try {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800463 surfaceView.mSession.finishDrawing(surfaceView.mWindow);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500464 } catch (RemoteException e) {
465 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700466 }
467 }
468 }
469 }
470
471 public void dispatchKey(KeyEvent event) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500472 SurfaceView surfaceView = mSurfaceView.get();
473 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800474 //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
475 if (surfaceView.mSession != null && surfaceView.mSurface != null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500476 try {
477 surfaceView.mSession.finishKey(surfaceView.mWindow);
478 } catch (RemoteException ex) {
479 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700480 }
481 }
482 }
483
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700484 public void dispatchPointer(MotionEvent event, long eventTime,
485 boolean callWhenDone) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700486 Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
487 //if (mSession != null && mSurface != null) {
488 // try {
489 // //mSession.finishKey(mWindow);
490 // } catch (RemoteException ex) {
491 // }
492 //}
493 }
494
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700495 public void dispatchTrackball(MotionEvent event, long eventTime,
496 boolean callWhenDone) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700497 Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
498 //if (mSession != null && mSurface != null) {
499 // try {
500 // //mSession.finishKey(mWindow);
501 // } catch (RemoteException ex) {
502 // }
503 //}
504 }
505
506 public void dispatchAppVisibility(boolean visible) {
507 // The point of SurfaceView is to let the app control the surface.
508 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800509
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700510 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500511 SurfaceView surfaceView = mSurfaceView.get();
512 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800513 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
514 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500515 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700516 }
517
518 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
519 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
520 }
521
522 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
523 }
524
525 int mCurWidth = -1;
526 int mCurHeight = -1;
527 }
528
529 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
530
531 private static final String LOG_TAG = "SurfaceHolder";
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700532 private int mSaveCount;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700533
534 public boolean isCreating() {
535 return mIsCreating;
536 }
537
538 public void addCallback(Callback callback) {
539 synchronized (mCallbacks) {
540 // This is a linear search, but in practice we'll
541 // have only a couple callbacks, so it doesn't matter.
542 if (mCallbacks.contains(callback) == false) {
543 mCallbacks.add(callback);
544 }
545 }
546 }
547
548 public void removeCallback(Callback callback) {
549 synchronized (mCallbacks) {
550 mCallbacks.remove(callback);
551 }
552 }
553
554 public void setFixedSize(int width, int height) {
555 if (mRequestedWidth != width || mRequestedHeight != height) {
556 mRequestedWidth = width;
557 mRequestedHeight = height;
558 requestLayout();
559 }
560 }
561
562 public void setSizeFromLayout() {
563 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
564 mRequestedWidth = mRequestedHeight = -1;
565 requestLayout();
566 }
567 }
568
569 public void setFormat(int format) {
570 mRequestedFormat = format;
571 if (mWindow != null) {
572 updateWindow(false);
573 }
574 }
575
576 public void setType(int type) {
577 switch (type) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700578 case SURFACE_TYPE_HARDWARE:
579 case SURFACE_TYPE_GPU:
Mathias Agopian317a6282009-08-13 17:29:02 -0700580 // these are deprecated, treat as "NORMAL"
581 type = SURFACE_TYPE_NORMAL;
582 break;
583 }
584 switch (type) {
585 case SURFACE_TYPE_NORMAL:
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700586 case SURFACE_TYPE_PUSH_BUFFERS:
587 mRequestedType = type;
588 if (mWindow != null) {
589 updateWindow(false);
590 }
591 break;
592 }
593 }
594
595 public void setKeepScreenOn(boolean screenOn) {
596 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
597 msg.arg1 = screenOn ? 1 : 0;
598 mHandler.sendMessage(msg);
599 }
600
601 public Canvas lockCanvas() {
602 return internalLockCanvas(null);
603 }
604
605 public Canvas lockCanvas(Rect dirty) {
606 return internalLockCanvas(dirty);
607 }
608
609 private final Canvas internalLockCanvas(Rect dirty) {
610 if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
611 throw new BadSurfaceTypeException(
612 "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
613 }
614 mSurfaceLock.lock();
615
616 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
617 + mDrawingStopped + ", win=" + mWindow);
618
619 Canvas c = null;
620 if (!mDrawingStopped && mWindow != null) {
621 Rect frame = dirty != null ? dirty : mSurfaceFrame;
622 try {
623 c = mSurface.lockCanvas(frame);
624 } catch (Exception e) {
625 Log.e(LOG_TAG, "Exception locking surface", e);
626 }
627 }
628
629 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
630 if (c != null) {
631 mLastLockTime = SystemClock.uptimeMillis();
632 return c;
633 }
634
635 // If the Surface is not ready to be drawn, then return null,
636 // but throttle calls to this function so it isn't called more
637 // than every 100ms.
638 long now = SystemClock.uptimeMillis();
639 long nextTime = mLastLockTime + 100;
640 if (nextTime > now) {
641 try {
642 Thread.sleep(nextTime-now);
643 } catch (InterruptedException e) {
644 }
645 now = SystemClock.uptimeMillis();
646 }
647 mLastLockTime = now;
648 mSurfaceLock.unlock();
649
650 return null;
651 }
652
653 public void unlockCanvasAndPost(Canvas canvas) {
654 mSurface.unlockCanvasAndPost(canvas);
655 mSurfaceLock.unlock();
656 }
657
658 public Surface getSurface() {
659 return mSurface;
660 }
661
662 public Rect getSurfaceFrame() {
663 return mSurfaceFrame;
664 }
665 };
666}