blob: 53c238c4c5090a9a952362856a782b2cd0cc04ac [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;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080022import android.content.res.Configuration;
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -070023import android.content.res.Resources;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070024import android.content.res.CompatibilityInfo.Translator;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070025import android.graphics.Canvas;
26import android.graphics.PixelFormat;
27import android.graphics.PorterDuff;
28import android.graphics.Rect;
29import android.graphics.Region;
30import android.os.Handler;
31import android.os.Message;
32import android.os.RemoteException;
33import android.os.SystemClock;
34import android.os.ParcelFileDescriptor;
35import android.util.AttributeSet;
36import android.util.Config;
37import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070038
Jon Larimer9bdf5762009-01-02 18:55:15 -050039import java.lang.ref.WeakReference;
40import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070041import java.util.concurrent.locks.ReentrantLock;
42
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();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700104 final Configuration mConfiguration = new Configuration();
105
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700106 static final int KEEP_SCREEN_ON_MSG = 1;
107 static final int GET_NEW_SURFACE_MSG = 2;
108
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700109 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
110
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700111 boolean mIsCreating = false;
112
113 final Handler mHandler = new Handler() {
114 @Override
115 public void handleMessage(Message msg) {
116 switch (msg.what) {
117 case KEEP_SCREEN_ON_MSG: {
118 setKeepScreenOn(msg.arg1 != 0);
119 } break;
120 case GET_NEW_SURFACE_MSG: {
121 handleGetNewSurface();
122 } break;
123 }
124 }
125 };
126
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700127 final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
128 = new ViewTreeObserver.OnScrollChangedListener() {
129 public void onScrollChanged() {
130 updateWindow(false);
131 }
132 };
133
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700134 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700135 boolean mWindowVisibility = false;
136 boolean mViewVisibility = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700137 int mRequestedWidth = -1;
138 int mRequestedHeight = -1;
139 int mRequestedFormat = PixelFormat.OPAQUE;
140 int mRequestedType = -1;
141
142 boolean mHaveFrame = false;
143 boolean mDestroyReportNeeded = false;
144 boolean mNewSurfaceNeeded = false;
145 long mLastLockTime = 0;
146
147 boolean mVisible = false;
148 int mLeft = -1;
149 int mTop = -1;
150 int mWidth = -1;
151 int mHeight = -1;
152 int mFormat = -1;
153 int mType = -1;
154 final Rect mSurfaceFrame = new Rect();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700155 private Translator mTranslator;
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700156
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700157 public SurfaceView(Context context) {
158 super(context);
159 setWillNotDraw(true);
160 }
161
162 public SurfaceView(Context context, AttributeSet attrs) {
163 super(context, attrs);
164 setWillNotDraw(true);
165 }
166
167 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
168 super(context, attrs, defStyle);
169 setWillNotDraw(true);
170 }
171
172 /**
173 * Return the SurfaceHolder providing access and control over this
174 * SurfaceView's underlying surface.
175 *
176 * @return SurfaceHolder The holder of the surface.
177 */
178 public SurfaceHolder getHolder() {
179 return mSurfaceHolder;
180 }
181
182 @Override
183 protected void onAttachedToWindow() {
184 super.onAttachedToWindow();
185 mParent.requestTransparentRegion(this);
186 mSession = getWindowSession();
187 mLayout.token = getWindowToken();
188 mLayout.setTitle("SurfaceView");
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700189 mViewVisibility = getVisibility() == VISIBLE;
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700190 getViewTreeObserver().addOnScrollChangedListener(mScrollChangedListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700191 }
192
193 @Override
194 protected void onWindowVisibilityChanged(int visibility) {
195 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700196 mWindowVisibility = visibility == VISIBLE;
197 mRequestedVisible = mWindowVisibility && mViewVisibility;
198 updateWindow(false);
199 }
200
201 @Override
202 public void setVisibility(int visibility) {
203 super.setVisibility(visibility);
204 mViewVisibility = visibility == VISIBLE;
205 mRequestedVisible = mWindowVisibility && mViewVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700206 updateWindow(false);
207 }
208
209 @Override
210 protected void onDetachedFromWindow() {
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700211 getViewTreeObserver().removeOnScrollChangedListener(mScrollChangedListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700212 mRequestedVisible = false;
213 updateWindow(false);
214 mHaveFrame = false;
215 if (mWindow != null) {
216 try {
217 mSession.remove(mWindow);
218 } catch (RemoteException ex) {
219 }
220 mWindow = null;
221 }
222 mSession = null;
223 mLayout.token = null;
224
225 super.onDetachedFromWindow();
226 }
227
228 @Override
229 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
230 int width = getDefaultSize(mRequestedWidth, widthMeasureSpec);
231 int height = getDefaultSize(mRequestedHeight, heightMeasureSpec);
232 setMeasuredDimension(width, height);
233 }
234
235 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700236 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
237 super.onSizeChanged(w, h, oldw, oldh);
238 updateWindow(false);
239 }
240
241 @Override
242 public boolean gatherTransparentRegion(Region region) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700243 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
244 return super.gatherTransparentRegion(region);
245 }
246
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700247 boolean opaque = true;
248 if ((mPrivateFlags & SKIP_DRAW) == 0) {
249 // this view draws, remove it from the transparent region
250 opaque = super.gatherTransparentRegion(region);
251 } else if (region != null) {
252 int w = getWidth();
253 int h = getHeight();
254 if (w>0 && h>0) {
255 getLocationInWindow(mLocation);
256 // otherwise, punch a hole in the whole hierarchy
257 int l = mLocation[0];
258 int t = mLocation[1];
259 region.op(l, t, l+w, t+h, Region.Op.UNION);
260 }
261 }
262 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
263 opaque = false;
264 }
265 return opaque;
266 }
267
268 @Override
269 public void draw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700270 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
271 // draw() is not called when SKIP_DRAW is set
272 if ((mPrivateFlags & SKIP_DRAW) == 0) {
273 // punch a whole in the view-hierarchy below us
274 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
275 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700276 }
277 super.draw(canvas);
278 }
279
280 @Override
281 protected void dispatchDraw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700282 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
283 // if SKIP_DRAW is cleared, draw() has already punched a hole
284 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
285 // punch a whole in the view-hierarchy below us
286 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
287 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700288 }
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 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700296 * Control whether the surface view's surface is placed on top of another
297 * regular surface view in the window (but still behind the window itself).
298 * This is typically used to place overlays on top of an underlying media
299 * surface view.
300 *
301 * <p>Note that this must be set before the surface view's containing
302 * window is attached to the window manager.
303 *
304 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
305 */
306 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
307 mWindowType = isMediaOverlay
308 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
309 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
310 }
311
312 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700313 * Control whether the surface view's surface is placed on top of its
314 * window. Normally it is placed behind the window, to allow it to
315 * (for the most part) appear to composite with the views in the
316 * hierarchy. By setting this, you cause it to be placed above the
317 * window. This means that none of the contents of the window this
318 * SurfaceView is in will be visible on top of its surface.
319 *
320 * <p>Note that this must be set before the surface view's containing
321 * window is attached to the window manager.
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700322 *
323 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700324 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700325 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500326 if (onTop) {
327 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
328 // ensures the surface is placed below the IME
329 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
330 } else {
331 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
332 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
333 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700334 }
335
336 /**
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700337 * Hack to allow special layering of windows. The type is one of the
338 * types in WindowManager.LayoutParams. This is a hack so:
339 * @hide
340 */
341 public void setWindowType(int type) {
342 mWindowType = type;
343 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700344
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700345 private void updateWindow(boolean force) {
346 if (!mHaveFrame) {
347 return;
348 }
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700349 ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
Joe Onorato168173a2009-08-12 21:40:29 -0700350 if (viewRoot != null) {
351 mTranslator = viewRoot.mTranslator;
352 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700353
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700354 Resources res = getContext().getResources();
355 if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700356 mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700357 }
358
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700359 int myWidth = mRequestedWidth;
360 if (myWidth <= 0) myWidth = getWidth();
361 int myHeight = mRequestedHeight;
362 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700363
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700364 getLocationInWindow(mLocation);
365 final boolean creating = mWindow == null;
366 final boolean formatChanged = mFormat != mRequestedFormat;
367 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
368 final boolean visibleChanged = mVisible != mRequestedVisible
369 || mNewSurfaceNeeded;
370 final boolean typeChanged = mType != mRequestedType;
371 if (force || creating || formatChanged || sizeChanged || visibleChanged
372 || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]) {
373
374 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
375 + " format=" + formatChanged + " size=" + sizeChanged
376 + " visible=" + visibleChanged
377 + " left=" + (mLeft != mLocation[0])
378 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700379
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700380 try {
381 final boolean visible = mVisible = mRequestedVisible;
382 mLeft = mLocation[0];
383 mTop = mLocation[1];
384 mWidth = myWidth;
385 mHeight = myHeight;
386 mFormat = mRequestedFormat;
387 mType = mRequestedType;
388
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700389 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
390
391 // Places the window relative
392 mLayout.x = mLeft;
393 mLayout.y = mTop;
394 mLayout.width = getWidth();
395 mLayout.height = getHeight();
396 if (mTranslator != null) {
397 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
398 }
399
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700400 mLayout.format = mRequestedFormat;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700401 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
402 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
403 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700404 | WindowManager.LayoutParams.FLAG_SCALED
405 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
406 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
407 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700408 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
409 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
410 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700411
412 mLayout.memoryType = mRequestedType;
413
414 if (mWindow == null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500415 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700416 mLayout.type = mWindowType;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700417 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
418 mSession.add(mWindow, mLayout,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800419 mVisible ? VISIBLE : GONE, mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700420 }
421
422 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
423 reportSurfaceDestroyed();
424 }
425
426 mNewSurfaceNeeded = false;
427
428 mSurfaceLock.lock();
429 mDrawingStopped = !visible;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700430
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700431 final int relayoutResult = mSession.relayout(
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700432 mWindow, mLayout, mWidth, mHeight,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800433 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700434 mVisibleInsets, mConfiguration, mSurface);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700435
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700436 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
437 + ", vis=" + visible + ", frame=" + mWinFrame);
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700438
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700439 mSurfaceFrame.left = 0;
440 mSurfaceFrame.top = 0;
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700441 if (mTranslator == null) {
442 mSurfaceFrame.right = mWinFrame.width();
443 mSurfaceFrame.bottom = mWinFrame.height();
444 } else {
445 float appInvertedScale = mTranslator.applicationInvertedScale;
446 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
447 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
448 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700449 mSurfaceLock.unlock();
450
451 try {
452 if (visible) {
453 mDestroyReportNeeded = true;
454
455 SurfaceHolder.Callback callbacks[];
456 synchronized (mCallbacks) {
457 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
458 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700459 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700460
461 if (visibleChanged) {
462 mIsCreating = true;
463 for (SurfaceHolder.Callback c : callbacks) {
464 c.surfaceCreated(mSurfaceHolder);
465 }
466 }
467 if (creating || formatChanged || sizeChanged
468 || visibleChanged) {
469 for (SurfaceHolder.Callback c : callbacks) {
470 c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
471 }
472 }
473 }
474 } finally {
475 mIsCreating = false;
476 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
477 mSession.finishDrawing(mWindow);
478 }
479 }
480 } catch (RemoteException ex) {
481 }
482 if (localLOGV) Log.v(
483 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
484 " w=" + mLayout.width + " h=" + mLayout.height +
485 ", frame=" + mSurfaceFrame);
486 }
487 }
488
489 private void reportSurfaceDestroyed() {
490 if (mDestroyReportNeeded) {
491 mDestroyReportNeeded = false;
492 SurfaceHolder.Callback callbacks[];
493 synchronized (mCallbacks) {
494 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
495 mCallbacks.toArray(callbacks);
496 }
497 for (SurfaceHolder.Callback c : callbacks) {
498 c.surfaceDestroyed(mSurfaceHolder);
499 }
500 }
501 super.onDetachedFromWindow();
502 }
503
504 void handleGetNewSurface() {
505 mNewSurfaceNeeded = true;
506 updateWindow(false);
507 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800508
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700509 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700510 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500511
512 public MyWindow(SurfaceView surfaceView) {
513 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
514 }
515
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800516 public void resized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800517 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500518 SurfaceView surfaceView = mSurfaceView.get();
519 if (surfaceView != null) {
520 if (localLOGV) Log.v(
521 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800522 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500523 synchronized (this) {
524 if (mCurWidth != w || mCurHeight != h) {
525 mCurWidth = w;
526 mCurHeight = h;
527 }
528 if (reportDraw) {
529 try {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800530 surfaceView.mSession.finishDrawing(surfaceView.mWindow);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500531 } catch (RemoteException e) {
532 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700533 }
534 }
535 }
536 }
537
538 public void dispatchKey(KeyEvent event) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500539 SurfaceView surfaceView = mSurfaceView.get();
540 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800541 //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
542 if (surfaceView.mSession != null && surfaceView.mSurface != null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500543 try {
544 surfaceView.mSession.finishKey(surfaceView.mWindow);
545 } catch (RemoteException ex) {
546 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700547 }
548 }
549 }
550
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700551 public void dispatchPointer(MotionEvent event, long eventTime,
552 boolean callWhenDone) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700553 Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
554 //if (mSession != null && mSurface != null) {
555 // try {
556 // //mSession.finishKey(mWindow);
557 // } catch (RemoteException ex) {
558 // }
559 //}
560 }
561
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700562 public void dispatchTrackball(MotionEvent event, long eventTime,
563 boolean callWhenDone) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700564 Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
565 //if (mSession != null && mSurface != null) {
566 // try {
567 // //mSession.finishKey(mWindow);
568 // } catch (RemoteException ex) {
569 // }
570 //}
571 }
572
573 public void dispatchAppVisibility(boolean visible) {
574 // The point of SurfaceView is to let the app control the surface.
575 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800576
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700577 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500578 SurfaceView surfaceView = mSurfaceView.get();
579 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800580 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
581 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500582 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700583 }
584
585 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
586 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
587 }
588
589 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
590 }
591
592 int mCurWidth = -1;
593 int mCurHeight = -1;
594 }
595
596 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
597
598 private static final String LOG_TAG = "SurfaceHolder";
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700599 private int mSaveCount;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700600
601 public boolean isCreating() {
602 return mIsCreating;
603 }
604
605 public void addCallback(Callback callback) {
606 synchronized (mCallbacks) {
607 // This is a linear search, but in practice we'll
608 // have only a couple callbacks, so it doesn't matter.
609 if (mCallbacks.contains(callback) == false) {
610 mCallbacks.add(callback);
611 }
612 }
613 }
614
615 public void removeCallback(Callback callback) {
616 synchronized (mCallbacks) {
617 mCallbacks.remove(callback);
618 }
619 }
620
621 public void setFixedSize(int width, int height) {
622 if (mRequestedWidth != width || mRequestedHeight != height) {
623 mRequestedWidth = width;
624 mRequestedHeight = height;
625 requestLayout();
626 }
627 }
628
629 public void setSizeFromLayout() {
630 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
631 mRequestedWidth = mRequestedHeight = -1;
632 requestLayout();
633 }
634 }
635
636 public void setFormat(int format) {
637 mRequestedFormat = format;
638 if (mWindow != null) {
639 updateWindow(false);
640 }
641 }
642
643 public void setType(int type) {
644 switch (type) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700645 case SURFACE_TYPE_HARDWARE:
646 case SURFACE_TYPE_GPU:
Mathias Agopian317a6282009-08-13 17:29:02 -0700647 // these are deprecated, treat as "NORMAL"
648 type = SURFACE_TYPE_NORMAL;
649 break;
650 }
651 switch (type) {
652 case SURFACE_TYPE_NORMAL:
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700653 case SURFACE_TYPE_PUSH_BUFFERS:
654 mRequestedType = type;
655 if (mWindow != null) {
656 updateWindow(false);
657 }
658 break;
659 }
660 }
661
662 public void setKeepScreenOn(boolean screenOn) {
663 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
664 msg.arg1 = screenOn ? 1 : 0;
665 mHandler.sendMessage(msg);
666 }
667
668 public Canvas lockCanvas() {
669 return internalLockCanvas(null);
670 }
671
672 public Canvas lockCanvas(Rect dirty) {
673 return internalLockCanvas(dirty);
674 }
675
676 private final Canvas internalLockCanvas(Rect dirty) {
677 if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
678 throw new BadSurfaceTypeException(
679 "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
680 }
681 mSurfaceLock.lock();
682
683 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
684 + mDrawingStopped + ", win=" + mWindow);
685
686 Canvas c = null;
687 if (!mDrawingStopped && mWindow != null) {
688 Rect frame = dirty != null ? dirty : mSurfaceFrame;
689 try {
690 c = mSurface.lockCanvas(frame);
691 } catch (Exception e) {
692 Log.e(LOG_TAG, "Exception locking surface", e);
693 }
694 }
695
696 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
697 if (c != null) {
698 mLastLockTime = SystemClock.uptimeMillis();
699 return c;
700 }
701
702 // If the Surface is not ready to be drawn, then return null,
703 // but throttle calls to this function so it isn't called more
704 // than every 100ms.
705 long now = SystemClock.uptimeMillis();
706 long nextTime = mLastLockTime + 100;
707 if (nextTime > now) {
708 try {
709 Thread.sleep(nextTime-now);
710 } catch (InterruptedException e) {
711 }
712 now = SystemClock.uptimeMillis();
713 }
714 mLastLockTime = now;
715 mSurfaceLock.unlock();
716
717 return null;
718 }
719
720 public void unlockCanvasAndPost(Canvas canvas) {
721 mSurface.unlockCanvasAndPost(canvas);
722 mSurfaceLock.unlock();
723 }
724
725 public Surface getSurface() {
726 return mSurface;
727 }
728
729 public Rect getSurfaceFrame() {
730 return mSurfaceFrame;
731 }
732 };
733}