blob: 7f7d207f6bbe989c56fb20cb41324ccabf1cba18 [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 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700425
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700426 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 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700473 } else {
474 mSurface.release();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700475 }
476 } finally {
477 mIsCreating = false;
478 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
479 mSession.finishDrawing(mWindow);
480 }
481 }
482 } catch (RemoteException ex) {
483 }
484 if (localLOGV) Log.v(
485 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
486 " w=" + mLayout.width + " h=" + mLayout.height +
487 ", frame=" + mSurfaceFrame);
488 }
489 }
490
491 private void reportSurfaceDestroyed() {
492 if (mDestroyReportNeeded) {
493 mDestroyReportNeeded = false;
494 SurfaceHolder.Callback callbacks[];
495 synchronized (mCallbacks) {
496 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
497 mCallbacks.toArray(callbacks);
498 }
499 for (SurfaceHolder.Callback c : callbacks) {
500 c.surfaceDestroyed(mSurfaceHolder);
501 }
502 }
503 super.onDetachedFromWindow();
504 }
505
506 void handleGetNewSurface() {
507 mNewSurfaceNeeded = true;
508 updateWindow(false);
509 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800510
Derek Sollenberger7179b812010-03-22 13:41:20 -0400511 /**
512 * Check to see if the surface has fixed size dimensions or if the surface's
513 * dimensions are dimensions are dependent on its current layout.
514 *
515 * @return true if the surface has dimensions that are fixed in size
516 * @hide
517 */
518 public boolean isFixedSize() {
519 return (mRequestedWidth != -1 || mRequestedHeight != -1);
520 }
521
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700522 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700523 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500524
525 public MyWindow(SurfaceView surfaceView) {
526 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
527 }
528
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800529 public void resized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800530 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500531 SurfaceView surfaceView = mSurfaceView.get();
532 if (surfaceView != null) {
533 if (localLOGV) Log.v(
534 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800535 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500536 synchronized (this) {
537 if (mCurWidth != w || mCurHeight != h) {
538 mCurWidth = w;
539 mCurHeight = h;
540 }
541 if (reportDraw) {
542 try {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800543 surfaceView.mSession.finishDrawing(surfaceView.mWindow);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500544 } catch (RemoteException e) {
545 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700546 }
547 }
548 }
549 }
550
551 public void dispatchKey(KeyEvent event) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500552 SurfaceView surfaceView = mSurfaceView.get();
553 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800554 //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
555 if (surfaceView.mSession != null && surfaceView.mSurface != null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500556 try {
557 surfaceView.mSession.finishKey(surfaceView.mWindow);
558 } catch (RemoteException ex) {
559 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700560 }
561 }
562 }
563
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700564 public void dispatchPointer(MotionEvent event, long eventTime,
565 boolean callWhenDone) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700566 Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
567 //if (mSession != null && mSurface != null) {
568 // try {
569 // //mSession.finishKey(mWindow);
570 // } catch (RemoteException ex) {
571 // }
572 //}
573 }
574
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700575 public void dispatchTrackball(MotionEvent event, long eventTime,
576 boolean callWhenDone) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700577 Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
578 //if (mSession != null && mSurface != null) {
579 // try {
580 // //mSession.finishKey(mWindow);
581 // } catch (RemoteException ex) {
582 // }
583 //}
584 }
585
586 public void dispatchAppVisibility(boolean visible) {
587 // The point of SurfaceView is to let the app control the surface.
588 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800589
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700590 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500591 SurfaceView surfaceView = mSurfaceView.get();
592 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800593 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
594 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500595 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700596 }
597
598 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
599 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
600 }
601
602 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
603 }
604
605 int mCurWidth = -1;
606 int mCurHeight = -1;
607 }
608
609 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
610
611 private static final String LOG_TAG = "SurfaceHolder";
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700612 private int mSaveCount;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700613
614 public boolean isCreating() {
615 return mIsCreating;
616 }
617
618 public void addCallback(Callback callback) {
619 synchronized (mCallbacks) {
620 // This is a linear search, but in practice we'll
621 // have only a couple callbacks, so it doesn't matter.
622 if (mCallbacks.contains(callback) == false) {
623 mCallbacks.add(callback);
624 }
625 }
626 }
627
628 public void removeCallback(Callback callback) {
629 synchronized (mCallbacks) {
630 mCallbacks.remove(callback);
631 }
632 }
633
634 public void setFixedSize(int width, int height) {
635 if (mRequestedWidth != width || mRequestedHeight != height) {
636 mRequestedWidth = width;
637 mRequestedHeight = height;
638 requestLayout();
639 }
640 }
641
642 public void setSizeFromLayout() {
643 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
644 mRequestedWidth = mRequestedHeight = -1;
645 requestLayout();
646 }
647 }
648
649 public void setFormat(int format) {
650 mRequestedFormat = format;
651 if (mWindow != null) {
652 updateWindow(false);
653 }
654 }
655
656 public void setType(int type) {
657 switch (type) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700658 case SURFACE_TYPE_HARDWARE:
659 case SURFACE_TYPE_GPU:
Mathias Agopian317a6282009-08-13 17:29:02 -0700660 // these are deprecated, treat as "NORMAL"
661 type = SURFACE_TYPE_NORMAL;
662 break;
663 }
664 switch (type) {
665 case SURFACE_TYPE_NORMAL:
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700666 case SURFACE_TYPE_PUSH_BUFFERS:
667 mRequestedType = type;
668 if (mWindow != null) {
669 updateWindow(false);
670 }
671 break;
672 }
673 }
674
675 public void setKeepScreenOn(boolean screenOn) {
676 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
677 msg.arg1 = screenOn ? 1 : 0;
678 mHandler.sendMessage(msg);
679 }
680
681 public Canvas lockCanvas() {
682 return internalLockCanvas(null);
683 }
684
685 public Canvas lockCanvas(Rect dirty) {
686 return internalLockCanvas(dirty);
687 }
688
689 private final Canvas internalLockCanvas(Rect dirty) {
690 if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
691 throw new BadSurfaceTypeException(
692 "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
693 }
694 mSurfaceLock.lock();
695
696 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
697 + mDrawingStopped + ", win=" + mWindow);
698
699 Canvas c = null;
700 if (!mDrawingStopped && mWindow != null) {
701 Rect frame = dirty != null ? dirty : mSurfaceFrame;
702 try {
703 c = mSurface.lockCanvas(frame);
704 } catch (Exception e) {
705 Log.e(LOG_TAG, "Exception locking surface", e);
706 }
707 }
708
709 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
710 if (c != null) {
711 mLastLockTime = SystemClock.uptimeMillis();
712 return c;
713 }
714
715 // If the Surface is not ready to be drawn, then return null,
716 // but throttle calls to this function so it isn't called more
717 // than every 100ms.
718 long now = SystemClock.uptimeMillis();
719 long nextTime = mLastLockTime + 100;
720 if (nextTime > now) {
721 try {
722 Thread.sleep(nextTime-now);
723 } catch (InterruptedException e) {
724 }
725 now = SystemClock.uptimeMillis();
726 }
727 mLastLockTime = now;
728 mSurfaceLock.unlock();
729
730 return null;
731 }
732
733 public void unlockCanvasAndPost(Canvas canvas) {
734 mSurface.unlockCanvasAndPost(canvas);
735 mSurfaceLock.unlock();
736 }
737
738 public Surface getSurface() {
739 return mSurface;
740 }
741
742 public Rect getSurfaceFrame() {
743 return mSurfaceFrame;
744 }
745 };
746}