blob: 8beceeca856172f3ca2a9aa5ba659297ff93a5c8 [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
Romain Guyafc3e112010-06-07 17:04:33 -070019import android.util.DisplayMetrics;
Dianne Hackborn72c82ab2009-08-11 21:13:54 -070020import com.android.internal.view.BaseIWindow;
21
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070022import android.content.Context;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080023import android.content.res.Configuration;
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -070024import android.content.res.Resources;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070025import android.content.res.CompatibilityInfo.Translator;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070026import android.graphics.Canvas;
27import android.graphics.PixelFormat;
28import android.graphics.PorterDuff;
29import android.graphics.Rect;
30import android.graphics.Region;
31import android.os.Handler;
32import android.os.Message;
33import android.os.RemoteException;
34import android.os.SystemClock;
35import android.os.ParcelFileDescriptor;
36import android.util.AttributeSet;
37import android.util.Config;
38import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070039
Jon Larimer9bdf5762009-01-02 18:55:15 -050040import java.lang.ref.WeakReference;
41import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070042import java.util.concurrent.locks.ReentrantLock;
43
44/**
45 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
46 * You can control the format of this surface and, if you like, its size; the
47 * SurfaceView takes care of placing the surface at the correct location on the
48 * screen
49 *
50 * <p>The surface is Z ordered so that it is behind the window holding its
51 * SurfaceView; the SurfaceView punches a hole in its window to allow its
52 * surface to be displayed. The view hierarchy will take care of correctly
53 * compositing with the Surface any siblings of the SurfaceView that would
54 * normally appear on top of it. This can be used to place overlays such as
55 * buttons on top of the Surface, though note however that it can have an
56 * impact on performance since a full alpha-blended composite will be performed
57 * each time the Surface changes.
58 *
59 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
60 * which can be retrieved by calling {@link #getHolder}.
61 *
62 * <p>The Surface will be created for you while the SurfaceView's window is
63 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
64 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
65 * Surface is created and destroyed as the window is shown and hidden.
66 *
67 * <p>One of the purposes of this class is to provide a surface in which a
68 * secondary thread can render in to the screen. If you are going to use it
69 * this way, you need to be aware of some threading semantics:
70 *
71 * <ul>
72 * <li> All SurfaceView and
73 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
74 * from the thread running the SurfaceView's window (typically the main thread
75 * of the application). They thus need to correctly synchronize with any
76 * state that is also touched by the drawing thread.
77 * <li> You must ensure that the drawing thread only touches the underlying
78 * Surface while it is valid -- between
79 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
80 * and
81 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
82 * </ul>
83 */
84public class SurfaceView extends View {
85 static private final String TAG = "SurfaceView";
86 static private final boolean DEBUG = false;
87 static private final boolean localLOGV = DEBUG ? true : Config.LOGV;
88
89 final ArrayList<SurfaceHolder.Callback> mCallbacks
90 = new ArrayList<SurfaceHolder.Callback>();
91
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080092 final int[] mLocation = new int[2];
93
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070094 final ReentrantLock mSurfaceLock = new ReentrantLock();
95 final Surface mSurface = new Surface();
96 boolean mDrawingStopped = true;
97
98 final WindowManager.LayoutParams mLayout
99 = new WindowManager.LayoutParams();
100 IWindowSession mSession;
101 MyWindow mWindow;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800102 final Rect mVisibleInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700103 final Rect mWinFrame = new Rect();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800104 final Rect mContentInsets = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700105 final Configuration mConfiguration = new Configuration();
106
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700107 static final int KEEP_SCREEN_ON_MSG = 1;
108 static final int GET_NEW_SURFACE_MSG = 2;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700109 static final int UPDATE_WINDOW_MSG = 3;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700110
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700111 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
112
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700113 boolean mIsCreating = false;
114
115 final Handler mHandler = new Handler() {
116 @Override
117 public void handleMessage(Message msg) {
118 switch (msg.what) {
119 case KEEP_SCREEN_ON_MSG: {
120 setKeepScreenOn(msg.arg1 != 0);
121 } break;
122 case GET_NEW_SURFACE_MSG: {
123 handleGetNewSurface();
124 } break;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700125 case UPDATE_WINDOW_MSG: {
126 updateWindow(false);
127 } break;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700128 }
129 }
130 };
131
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700132 final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
133 = new ViewTreeObserver.OnScrollChangedListener() {
134 public void onScrollChanged() {
135 updateWindow(false);
136 }
137 };
138
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700139 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700140 boolean mWindowVisibility = false;
141 boolean mViewVisibility = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700142 int mRequestedWidth = -1;
143 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700144 /* Set SurfaceView's format to 565 by default to maintain backward
145 * compatibility with applications assuming this format.
146 */
147 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700148 int mRequestedType = -1;
149
150 boolean mHaveFrame = false;
151 boolean mDestroyReportNeeded = false;
152 boolean mNewSurfaceNeeded = false;
153 long mLastLockTime = 0;
154
155 boolean mVisible = false;
156 int mLeft = -1;
157 int mTop = -1;
158 int mWidth = -1;
159 int mHeight = -1;
160 int mFormat = -1;
161 int mType = -1;
162 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700163 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
164 boolean mUpdateWindowNeeded;
165 boolean mReportDrawNeeded;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700166 private Translator mTranslator;
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700167
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700168 public SurfaceView(Context context) {
169 super(context);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700170 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700171 }
172
173 public SurfaceView(Context context, AttributeSet attrs) {
174 super(context, attrs);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700175 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700176 }
177
178 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
179 super(context, attrs, defStyle);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700180 init();
181 }
182
183 private void init() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700184 setWillNotDraw(true);
185 }
186
187 /**
188 * Return the SurfaceHolder providing access and control over this
189 * SurfaceView's underlying surface.
190 *
191 * @return SurfaceHolder The holder of the surface.
192 */
193 public SurfaceHolder getHolder() {
194 return mSurfaceHolder;
195 }
196
197 @Override
198 protected void onAttachedToWindow() {
199 super.onAttachedToWindow();
200 mParent.requestTransparentRegion(this);
201 mSession = getWindowSession();
202 mLayout.token = getWindowToken();
203 mLayout.setTitle("SurfaceView");
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700204 mViewVisibility = getVisibility() == VISIBLE;
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700205 getViewTreeObserver().addOnScrollChangedListener(mScrollChangedListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700206 }
207
208 @Override
209 protected void onWindowVisibilityChanged(int visibility) {
210 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700211 mWindowVisibility = visibility == VISIBLE;
212 mRequestedVisible = mWindowVisibility && mViewVisibility;
213 updateWindow(false);
214 }
215
216 @Override
217 public void setVisibility(int visibility) {
218 super.setVisibility(visibility);
219 mViewVisibility = visibility == VISIBLE;
220 mRequestedVisible = mWindowVisibility && mViewVisibility;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700221 updateWindow(false);
222 }
Romain Guyafc3e112010-06-07 17:04:33 -0700223
224 /**
225 * This method is not intended for general use. It was created
226 * temporarily to improve performance of 3D layers in Launcher
227 * and should be removed and fixed properly.
228 *
229 * Do not call this method. Ever.
230 *
231 * @hide
232 */
233 protected void showSurface() {
234 if (mSession != null) {
235 updateWindow(true);
236 }
237 }
238
239 /**
240 * This method is not intended for general use. It was created
241 * temporarily to improve performance of 3D layers in Launcher
242 * and should be removed and fixed properly.
243 *
244 * Do not call this method. Ever.
245 *
246 * @hide
247 */
248 protected void hideSurface() {
249 if (mSession != null && mWindow != null) {
250 mSurfaceLock.lock();
251 try {
252 DisplayMetrics metrics = getResources().getDisplayMetrics();
253 mLayout.x = metrics.widthPixels * 3;
254 mSession.relayout(mWindow, mLayout, mWidth, mHeight, VISIBLE, false,
255 mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurface);
256 } catch (RemoteException e) {
257 // Ignore
258 } finally {
259 mSurfaceLock.unlock();
260 }
261 }
262 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700263
264 @Override
265 protected void onDetachedFromWindow() {
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700266 getViewTreeObserver().removeOnScrollChangedListener(mScrollChangedListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700267 mRequestedVisible = false;
268 updateWindow(false);
269 mHaveFrame = false;
270 if (mWindow != null) {
271 try {
272 mSession.remove(mWindow);
273 } catch (RemoteException ex) {
274 }
275 mWindow = null;
276 }
277 mSession = null;
278 mLayout.token = null;
279
280 super.onDetachedFromWindow();
281 }
282
283 @Override
284 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
285 int width = getDefaultSize(mRequestedWidth, widthMeasureSpec);
286 int height = getDefaultSize(mRequestedHeight, heightMeasureSpec);
287 setMeasuredDimension(width, height);
288 }
289
290 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700291 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
292 super.onSizeChanged(w, h, oldw, oldh);
293 updateWindow(false);
294 }
295
296 @Override
297 public boolean gatherTransparentRegion(Region region) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700298 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
299 return super.gatherTransparentRegion(region);
300 }
301
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700302 boolean opaque = true;
303 if ((mPrivateFlags & SKIP_DRAW) == 0) {
304 // this view draws, remove it from the transparent region
305 opaque = super.gatherTransparentRegion(region);
306 } else if (region != null) {
307 int w = getWidth();
308 int h = getHeight();
309 if (w>0 && h>0) {
310 getLocationInWindow(mLocation);
311 // otherwise, punch a hole in the whole hierarchy
312 int l = mLocation[0];
313 int t = mLocation[1];
314 region.op(l, t, l+w, t+h, Region.Op.UNION);
315 }
316 }
317 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
318 opaque = false;
319 }
320 return opaque;
321 }
322
323 @Override
324 public void draw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700325 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
326 // draw() is not called when SKIP_DRAW is set
327 if ((mPrivateFlags & SKIP_DRAW) == 0) {
328 // punch a whole in the view-hierarchy below us
329 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
330 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700331 }
332 super.draw(canvas);
333 }
334
335 @Override
336 protected void dispatchDraw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700337 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
338 // if SKIP_DRAW is cleared, draw() has already punched a hole
339 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
340 // punch a whole in the view-hierarchy below us
341 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
342 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700343 }
344 // reposition ourselves where the surface is
345 mHaveFrame = true;
346 updateWindow(false);
347 super.dispatchDraw(canvas);
348 }
349
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700350 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700351 * Control whether the surface view's surface is placed on top of another
352 * regular surface view in the window (but still behind the window itself).
353 * This is typically used to place overlays on top of an underlying media
354 * surface view.
355 *
356 * <p>Note that this must be set before the surface view's containing
357 * window is attached to the window manager.
358 *
359 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
360 */
361 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
362 mWindowType = isMediaOverlay
363 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
364 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
365 }
366
367 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700368 * Control whether the surface view's surface is placed on top of its
369 * window. Normally it is placed behind the window, to allow it to
370 * (for the most part) appear to composite with the views in the
371 * hierarchy. By setting this, you cause it to be placed above the
372 * window. This means that none of the contents of the window this
373 * SurfaceView is in will be visible on top of its surface.
374 *
375 * <p>Note that this must be set before the surface view's containing
376 * window is attached to the window manager.
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700377 *
378 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700379 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700380 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500381 if (onTop) {
382 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
383 // ensures the surface is placed below the IME
384 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
385 } else {
386 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
387 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
388 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700389 }
390
391 /**
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700392 * Hack to allow special layering of windows. The type is one of the
393 * types in WindowManager.LayoutParams. This is a hack so:
394 * @hide
395 */
396 public void setWindowType(int type) {
397 mWindowType = type;
398 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700399
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700400 private void updateWindow(boolean force) {
401 if (!mHaveFrame) {
402 return;
403 }
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700404 ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
Joe Onorato168173a2009-08-12 21:40:29 -0700405 if (viewRoot != null) {
406 mTranslator = viewRoot.mTranslator;
407 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700408
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700409 Resources res = getContext().getResources();
410 if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700411 mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700412 }
413
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700414 int myWidth = mRequestedWidth;
415 if (myWidth <= 0) myWidth = getWidth();
416 int myHeight = mRequestedHeight;
417 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700418
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700419 getLocationInWindow(mLocation);
420 final boolean creating = mWindow == null;
421 final boolean formatChanged = mFormat != mRequestedFormat;
422 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
423 final boolean visibleChanged = mVisible != mRequestedVisible
424 || mNewSurfaceNeeded;
425 final boolean typeChanged = mType != mRequestedType;
426 if (force || creating || formatChanged || sizeChanged || visibleChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700427 || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]
428 || mUpdateWindowNeeded || mReportDrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700429
430 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
431 + " format=" + formatChanged + " size=" + sizeChanged
432 + " visible=" + visibleChanged
433 + " left=" + (mLeft != mLocation[0])
434 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700435
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700436 try {
437 final boolean visible = mVisible = mRequestedVisible;
438 mLeft = mLocation[0];
439 mTop = mLocation[1];
440 mWidth = myWidth;
441 mHeight = myHeight;
442 mFormat = mRequestedFormat;
443 mType = mRequestedType;
444
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700445 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
446
447 // Places the window relative
448 mLayout.x = mLeft;
449 mLayout.y = mTop;
450 mLayout.width = getWidth();
451 mLayout.height = getHeight();
452 if (mTranslator != null) {
453 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
454 }
455
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700456 mLayout.format = mRequestedFormat;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700457 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
458 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
459 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700460 | WindowManager.LayoutParams.FLAG_SCALED
461 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
462 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
463 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700464 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
465 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
466 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700467
468 mLayout.memoryType = mRequestedType;
469
470 if (mWindow == null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500471 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700472 mLayout.type = mWindowType;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700473 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700474 mSession.addWithoutInputChannel(mWindow, mLayout,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800475 mVisible ? VISIBLE : GONE, mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700476 }
477
478 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
479 reportSurfaceDestroyed();
480 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700481
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700482 mNewSurfaceNeeded = false;
483
Dianne Hackborn726426e2010-03-31 22:04:36 -0700484 boolean realSizeChanged;
485 boolean reportDrawNeeded;
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700486
Dianne Hackborn726426e2010-03-31 22:04:36 -0700487 mSurfaceLock.lock();
488 try {
489 mUpdateWindowNeeded = false;
490 reportDrawNeeded = mReportDrawNeeded;
491 mReportDrawNeeded = false;
492 mDrawingStopped = !visible;
493
494 final int relayoutResult = mSession.relayout(
495 mWindow, mLayout, mWidth, mHeight,
496 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
497 mVisibleInsets, mConfiguration, mSurface);
498 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
499 mReportDrawNeeded = true;
500 }
501
502 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
503 + ", vis=" + visible + ", frame=" + mWinFrame);
504
505 mSurfaceFrame.left = 0;
506 mSurfaceFrame.top = 0;
507 if (mTranslator == null) {
508 mSurfaceFrame.right = mWinFrame.width();
509 mSurfaceFrame.bottom = mWinFrame.height();
510 } else {
511 float appInvertedScale = mTranslator.applicationInvertedScale;
512 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
513 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
514 }
515
516 final int surfaceWidth = mSurfaceFrame.right;
517 final int surfaceHeight = mSurfaceFrame.bottom;
518 realSizeChanged = mLastSurfaceWidth != surfaceWidth
519 || mLastSurfaceHeight != surfaceHeight;
520 mLastSurfaceWidth = surfaceWidth;
521 mLastSurfaceHeight = surfaceHeight;
522 } finally {
523 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700524 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700525
526 try {
527 if (visible) {
528 mDestroyReportNeeded = true;
529
530 SurfaceHolder.Callback callbacks[];
531 synchronized (mCallbacks) {
532 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
533 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700534 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700535
536 if (visibleChanged) {
537 mIsCreating = true;
538 for (SurfaceHolder.Callback c : callbacks) {
539 c.surfaceCreated(mSurfaceHolder);
540 }
541 }
542 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700543 || visibleChanged || realSizeChanged) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700544 for (SurfaceHolder.Callback c : callbacks) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700545 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700546 }
547 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700548 } else {
549 mSurface.release();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700550 }
551 } finally {
552 mIsCreating = false;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700553 if (creating || reportDrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700554 mSession.finishDrawing(mWindow);
555 }
556 }
557 } catch (RemoteException ex) {
558 }
559 if (localLOGV) Log.v(
560 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
561 " w=" + mLayout.width + " h=" + mLayout.height +
562 ", frame=" + mSurfaceFrame);
563 }
564 }
565
566 private void reportSurfaceDestroyed() {
567 if (mDestroyReportNeeded) {
568 mDestroyReportNeeded = false;
569 SurfaceHolder.Callback callbacks[];
570 synchronized (mCallbacks) {
571 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
572 mCallbacks.toArray(callbacks);
573 }
574 for (SurfaceHolder.Callback c : callbacks) {
575 c.surfaceDestroyed(mSurfaceHolder);
576 }
577 }
578 super.onDetachedFromWindow();
579 }
580
581 void handleGetNewSurface() {
582 mNewSurfaceNeeded = true;
583 updateWindow(false);
584 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800585
Derek Sollenberger7179b812010-03-22 13:41:20 -0400586 /**
587 * Check to see if the surface has fixed size dimensions or if the surface's
588 * dimensions are dimensions are dependent on its current layout.
589 *
590 * @return true if the surface has dimensions that are fixed in size
591 * @hide
592 */
593 public boolean isFixedSize() {
594 return (mRequestedWidth != -1 || mRequestedHeight != -1);
595 }
596
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700597 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700598 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500599
600 public MyWindow(SurfaceView surfaceView) {
601 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
602 }
603
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800604 public void resized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800605 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500606 SurfaceView surfaceView = mSurfaceView.get();
607 if (surfaceView != null) {
608 if (localLOGV) Log.v(
609 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800610 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700611 surfaceView.mSurfaceLock.lock();
612 try {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500613 if (reportDraw) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700614 surfaceView.mUpdateWindowNeeded = true;
615 surfaceView.mReportDrawNeeded = true;
616 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
617 } else if (surfaceView.mWinFrame.width() != w
618 || surfaceView.mWinFrame.height() != h) {
619 surfaceView.mUpdateWindowNeeded = true;
620 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700621 }
Dianne Hackborn726426e2010-03-31 22:04:36 -0700622 } finally {
623 surfaceView.mSurfaceLock.unlock();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700624 }
625 }
626 }
627
628 public void dispatchKey(KeyEvent event) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500629 SurfaceView surfaceView = mSurfaceView.get();
630 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800631 //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
632 if (surfaceView.mSession != null && surfaceView.mSurface != null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500633 try {
634 surfaceView.mSession.finishKey(surfaceView.mWindow);
635 } catch (RemoteException ex) {
636 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700637 }
638 }
639 }
640
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700641 public void dispatchPointer(MotionEvent event, long eventTime,
642 boolean callWhenDone) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700643 Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
644 //if (mSession != null && mSurface != null) {
645 // try {
646 // //mSession.finishKey(mWindow);
647 // } catch (RemoteException ex) {
648 // }
649 //}
650 }
651
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700652 public void dispatchTrackball(MotionEvent event, long eventTime,
653 boolean callWhenDone) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700654 Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
655 //if (mSession != null && mSurface != null) {
656 // try {
657 // //mSession.finishKey(mWindow);
658 // } catch (RemoteException ex) {
659 // }
660 //}
661 }
662
663 public void dispatchAppVisibility(boolean visible) {
664 // The point of SurfaceView is to let the app control the surface.
665 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800666
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700667 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500668 SurfaceView surfaceView = mSurfaceView.get();
669 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800670 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
671 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500672 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700673 }
674
675 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
676 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
677 }
678
679 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
680 }
681
682 int mCurWidth = -1;
683 int mCurHeight = -1;
684 }
685
686 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
687
688 private static final String LOG_TAG = "SurfaceHolder";
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700689 private int mSaveCount;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700690
691 public boolean isCreating() {
692 return mIsCreating;
693 }
694
695 public void addCallback(Callback callback) {
696 synchronized (mCallbacks) {
697 // This is a linear search, but in practice we'll
698 // have only a couple callbacks, so it doesn't matter.
699 if (mCallbacks.contains(callback) == false) {
700 mCallbacks.add(callback);
701 }
702 }
703 }
704
705 public void removeCallback(Callback callback) {
706 synchronized (mCallbacks) {
707 mCallbacks.remove(callback);
708 }
709 }
710
711 public void setFixedSize(int width, int height) {
712 if (mRequestedWidth != width || mRequestedHeight != height) {
713 mRequestedWidth = width;
714 mRequestedHeight = height;
715 requestLayout();
716 }
717 }
718
719 public void setSizeFromLayout() {
720 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
721 mRequestedWidth = mRequestedHeight = -1;
722 requestLayout();
723 }
724 }
725
726 public void setFormat(int format) {
727 mRequestedFormat = format;
728 if (mWindow != null) {
729 updateWindow(false);
730 }
731 }
732
733 public void setType(int type) {
734 switch (type) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700735 case SURFACE_TYPE_HARDWARE:
736 case SURFACE_TYPE_GPU:
Mathias Agopian317a6282009-08-13 17:29:02 -0700737 // these are deprecated, treat as "NORMAL"
738 type = SURFACE_TYPE_NORMAL;
739 break;
740 }
741 switch (type) {
742 case SURFACE_TYPE_NORMAL:
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700743 case SURFACE_TYPE_PUSH_BUFFERS:
744 mRequestedType = type;
745 if (mWindow != null) {
746 updateWindow(false);
747 }
748 break;
749 }
750 }
751
752 public void setKeepScreenOn(boolean screenOn) {
753 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
754 msg.arg1 = screenOn ? 1 : 0;
755 mHandler.sendMessage(msg);
756 }
757
758 public Canvas lockCanvas() {
759 return internalLockCanvas(null);
760 }
761
762 public Canvas lockCanvas(Rect dirty) {
763 return internalLockCanvas(dirty);
764 }
765
766 private final Canvas internalLockCanvas(Rect dirty) {
767 if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
768 throw new BadSurfaceTypeException(
769 "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
770 }
771 mSurfaceLock.lock();
772
773 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
774 + mDrawingStopped + ", win=" + mWindow);
775
776 Canvas c = null;
777 if (!mDrawingStopped && mWindow != null) {
778 Rect frame = dirty != null ? dirty : mSurfaceFrame;
779 try {
780 c = mSurface.lockCanvas(frame);
781 } catch (Exception e) {
782 Log.e(LOG_TAG, "Exception locking surface", e);
783 }
784 }
785
786 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
787 if (c != null) {
788 mLastLockTime = SystemClock.uptimeMillis();
789 return c;
790 }
791
792 // If the Surface is not ready to be drawn, then return null,
793 // but throttle calls to this function so it isn't called more
794 // than every 100ms.
795 long now = SystemClock.uptimeMillis();
796 long nextTime = mLastLockTime + 100;
797 if (nextTime > now) {
798 try {
799 Thread.sleep(nextTime-now);
800 } catch (InterruptedException e) {
801 }
802 now = SystemClock.uptimeMillis();
803 }
804 mLastLockTime = now;
805 mSurfaceLock.unlock();
806
807 return null;
808 }
809
810 public void unlockCanvasAndPost(Canvas canvas) {
811 mSurface.unlockCanvasAndPost(canvas);
812 mSurfaceLock.unlock();
813 }
814
815 public Surface getSurface() {
816 return mSurface;
817 }
818
819 public Rect getSurfaceFrame() {
820 return mSurfaceFrame;
821 }
822 };
823}