blob: 6451d47a189c0aec521f7534bae7cc90091ab3cc [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
Glenn Kasten334031c2010-11-09 21:54:38 -080068 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070069 * 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: {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700126 updateWindow(false, false);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700127 } 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() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700135 updateWindow(false, false);
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700136 }
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
149 boolean mHaveFrame = false;
150 boolean mDestroyReportNeeded = false;
151 boolean mNewSurfaceNeeded = false;
152 long mLastLockTime = 0;
153
154 boolean mVisible = false;
155 int mLeft = -1;
156 int mTop = -1;
157 int mWidth = -1;
158 int mHeight = -1;
159 int mFormat = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700160 final Rect mSurfaceFrame = new Rect();
Dianne Hackborn726426e2010-03-31 22:04:36 -0700161 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
162 boolean mUpdateWindowNeeded;
163 boolean mReportDrawNeeded;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700164 private Translator mTranslator;
Mitsuru Oshima424f6682009-07-22 13:13:36 -0700165
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700166 public SurfaceView(Context context) {
167 super(context);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700168 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700169 }
170
171 public SurfaceView(Context context, AttributeSet attrs) {
172 super(context, attrs);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700173 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700174 }
175
176 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
177 super(context, attrs, defStyle);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700178 init();
179 }
180
181 private void init() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700182 setWillNotDraw(true);
183 }
184
185 /**
186 * Return the SurfaceHolder providing access and control over this
187 * SurfaceView's underlying surface.
188 *
189 * @return SurfaceHolder The holder of the surface.
190 */
191 public SurfaceHolder getHolder() {
192 return mSurfaceHolder;
193 }
194
195 @Override
196 protected void onAttachedToWindow() {
197 super.onAttachedToWindow();
198 mParent.requestTransparentRegion(this);
199 mSession = getWindowSession();
200 mLayout.token = getWindowToken();
201 mLayout.setTitle("SurfaceView");
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700202 mViewVisibility = getVisibility() == VISIBLE;
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700203 getViewTreeObserver().addOnScrollChangedListener(mScrollChangedListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700204 }
205
206 @Override
207 protected void onWindowVisibilityChanged(int visibility) {
208 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700209 mWindowVisibility = visibility == VISIBLE;
210 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700211 updateWindow(false, false);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700212 }
213
214 @Override
215 public void setVisibility(int visibility) {
216 super.setVisibility(visibility);
217 mViewVisibility = visibility == VISIBLE;
218 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700219 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700220 }
Romain Guyafc3e112010-06-07 17:04:33 -0700221
222 /**
223 * This method is not intended for general use. It was created
224 * temporarily to improve performance of 3D layers in Launcher
225 * and should be removed and fixed properly.
226 *
227 * Do not call this method. Ever.
228 *
229 * @hide
230 */
231 protected void showSurface() {
232 if (mSession != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700233 updateWindow(true, false);
Romain Guyafc3e112010-06-07 17:04:33 -0700234 }
235 }
236
237 /**
238 * This method is not intended for general use. It was created
239 * temporarily to improve performance of 3D layers in Launcher
240 * and should be removed and fixed properly.
241 *
242 * Do not call this method. Ever.
243 *
244 * @hide
245 */
246 protected void hideSurface() {
247 if (mSession != null && mWindow != null) {
248 mSurfaceLock.lock();
249 try {
250 DisplayMetrics metrics = getResources().getDisplayMetrics();
251 mLayout.x = metrics.widthPixels * 3;
252 mSession.relayout(mWindow, mLayout, mWidth, mHeight, VISIBLE, false,
253 mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurface);
254 } catch (RemoteException e) {
255 // Ignore
256 } finally {
257 mSurfaceLock.unlock();
258 }
259 }
260 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700261
262 @Override
263 protected void onDetachedFromWindow() {
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700264 getViewTreeObserver().removeOnScrollChangedListener(mScrollChangedListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700265 mRequestedVisible = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700266 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700267 mHaveFrame = false;
268 if (mWindow != null) {
269 try {
270 mSession.remove(mWindow);
271 } catch (RemoteException ex) {
272 }
273 mWindow = null;
274 }
275 mSession = null;
276 mLayout.token = null;
277
278 super.onDetachedFromWindow();
279 }
280
281 @Override
282 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800283 int width = mRequestedWidth >= 0
284 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
285 : getDefaultSize(0, widthMeasureSpec);
286 int height = mRequestedHeight >= 0
287 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
288 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700289 setMeasuredDimension(width, height);
290 }
291
Mathias Agopianef115302010-10-04 20:15:08 -0700292 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700293 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700294 protected boolean setFrame(int left, int top, int right, int bottom) {
295 boolean result = super.setFrame(left, top, right, bottom);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700296 updateWindow(false, false);
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700297 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700298 }
299
300 @Override
301 public boolean gatherTransparentRegion(Region region) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700302 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
303 return super.gatherTransparentRegion(region);
304 }
305
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700306 boolean opaque = true;
307 if ((mPrivateFlags & SKIP_DRAW) == 0) {
308 // this view draws, remove it from the transparent region
309 opaque = super.gatherTransparentRegion(region);
310 } else if (region != null) {
311 int w = getWidth();
312 int h = getHeight();
313 if (w>0 && h>0) {
314 getLocationInWindow(mLocation);
315 // otherwise, punch a hole in the whole hierarchy
316 int l = mLocation[0];
317 int t = mLocation[1];
318 region.op(l, t, l+w, t+h, Region.Op.UNION);
319 }
320 }
321 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
322 opaque = false;
323 }
324 return opaque;
325 }
326
327 @Override
328 public void draw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700329 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
330 // draw() is not called when SKIP_DRAW is set
331 if ((mPrivateFlags & SKIP_DRAW) == 0) {
332 // punch a whole in the view-hierarchy below us
333 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
334 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700335 }
336 super.draw(canvas);
337 }
338
339 @Override
340 protected void dispatchDraw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700341 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
342 // if SKIP_DRAW is cleared, draw() has already punched a hole
343 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
344 // punch a whole in the view-hierarchy below us
345 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
346 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700347 }
348 // reposition ourselves where the surface is
349 mHaveFrame = true;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700350 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700351 super.dispatchDraw(canvas);
352 }
353
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700354 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700355 * Control whether the surface view's surface is placed on top of another
356 * regular surface view in the window (but still behind the window itself).
357 * This is typically used to place overlays on top of an underlying media
358 * surface view.
359 *
360 * <p>Note that this must be set before the surface view's containing
361 * window is attached to the window manager.
362 *
363 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
364 */
365 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
366 mWindowType = isMediaOverlay
367 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
368 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
369 }
370
371 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700372 * Control whether the surface view's surface is placed on top of its
373 * window. Normally it is placed behind the window, to allow it to
374 * (for the most part) appear to composite with the views in the
375 * hierarchy. By setting this, you cause it to be placed above the
376 * window. This means that none of the contents of the window this
377 * SurfaceView is in will be visible on top of its surface.
378 *
379 * <p>Note that this must be set before the surface view's containing
380 * window is attached to the window manager.
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700381 *
382 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700383 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700384 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500385 if (onTop) {
386 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
387 // ensures the surface is placed below the IME
388 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
389 } else {
390 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
391 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
392 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700393 }
394
395 /**
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700396 * Hack to allow special layering of windows. The type is one of the
397 * types in WindowManager.LayoutParams. This is a hack so:
398 * @hide
399 */
400 public void setWindowType(int type) {
401 mWindowType = type;
402 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700403
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700404 private void updateWindow(boolean force, boolean redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700405 if (!mHaveFrame) {
406 return;
407 }
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700408 ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
Joe Onorato168173a2009-08-12 21:40:29 -0700409 if (viewRoot != null) {
410 mTranslator = viewRoot.mTranslator;
411 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700412
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700413 Resources res = getContext().getResources();
414 if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700415 mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700416 }
417
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700418 int myWidth = mRequestedWidth;
419 if (myWidth <= 0) myWidth = getWidth();
420 int myHeight = mRequestedHeight;
421 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700422
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700423 getLocationInWindow(mLocation);
424 final boolean creating = mWindow == null;
425 final boolean formatChanged = mFormat != mRequestedFormat;
426 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
427 final boolean visibleChanged = mVisible != mRequestedVisible
428 || mNewSurfaceNeeded;
Mathias Agopiand2112302010-12-07 19:38:17 -0800429
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700430 if (force || creating || formatChanged || sizeChanged || visibleChanged
Mathias Agopiand2112302010-12-07 19:38:17 -0800431 || mLeft != mLocation[0] || mTop != mLocation[1]
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700432 || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700433
434 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
435 + " format=" + formatChanged + " size=" + sizeChanged
436 + " visible=" + visibleChanged
437 + " left=" + (mLeft != mLocation[0])
438 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700439
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700440 try {
441 final boolean visible = mVisible = mRequestedVisible;
442 mLeft = mLocation[0];
443 mTop = mLocation[1];
444 mWidth = myWidth;
445 mHeight = myHeight;
446 mFormat = mRequestedFormat;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700447
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700448 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
449
450 // Places the window relative
451 mLayout.x = mLeft;
452 mLayout.y = mTop;
453 mLayout.width = getWidth();
454 mLayout.height = getHeight();
455 if (mTranslator != null) {
456 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
457 }
458
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700459 mLayout.format = mRequestedFormat;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700460 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
461 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
462 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700463 | WindowManager.LayoutParams.FLAG_SCALED
464 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
465 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
466 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700467 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
468 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
469 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700470
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700471 if (mWindow == null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500472 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700473 mLayout.type = mWindowType;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700474 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700475 mSession.addWithoutInputChannel(mWindow, mLayout,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800476 mVisible ? VISIBLE : GONE, mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700477 }
478
479 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
480 reportSurfaceDestroyed();
481 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700482
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700483 mNewSurfaceNeeded = false;
484
Dianne Hackborn726426e2010-03-31 22:04:36 -0700485 boolean realSizeChanged;
486 boolean reportDrawNeeded;
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700487
Dianne Hackborn726426e2010-03-31 22:04:36 -0700488 mSurfaceLock.lock();
489 try {
490 mUpdateWindowNeeded = false;
491 reportDrawNeeded = mReportDrawNeeded;
492 mReportDrawNeeded = false;
493 mDrawingStopped = !visible;
494
495 final int relayoutResult = mSession.relayout(
496 mWindow, mLayout, mWidth, mHeight,
497 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
498 mVisibleInsets, mConfiguration, mSurface);
499 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
500 mReportDrawNeeded = true;
501 }
502
503 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
504 + ", vis=" + visible + ", frame=" + mWinFrame);
505
506 mSurfaceFrame.left = 0;
507 mSurfaceFrame.top = 0;
508 if (mTranslator == null) {
509 mSurfaceFrame.right = mWinFrame.width();
510 mSurfaceFrame.bottom = mWinFrame.height();
511 } else {
512 float appInvertedScale = mTranslator.applicationInvertedScale;
513 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
514 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
515 }
516
517 final int surfaceWidth = mSurfaceFrame.right;
518 final int surfaceHeight = mSurfaceFrame.bottom;
519 realSizeChanged = mLastSurfaceWidth != surfaceWidth
520 || mLastSurfaceHeight != surfaceHeight;
521 mLastSurfaceWidth = surfaceWidth;
522 mLastSurfaceHeight = surfaceHeight;
523 } finally {
524 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700525 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700526
527 try {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700528 redrawNeeded |= creating | reportDrawNeeded;
529
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700530 if (visible) {
531 mDestroyReportNeeded = true;
532
533 SurfaceHolder.Callback callbacks[];
534 synchronized (mCallbacks) {
535 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
536 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700537 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700538
539 if (visibleChanged) {
540 mIsCreating = true;
541 for (SurfaceHolder.Callback c : callbacks) {
542 c.surfaceCreated(mSurfaceHolder);
543 }
544 }
545 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700546 || visibleChanged || realSizeChanged) {
Dianne Hackborn251fd432010-07-14 16:56:31 -0700547 for (SurfaceHolder.Callback c : callbacks) {
548 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
549 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700550 }
551 if (redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700552 for (SurfaceHolder.Callback c : callbacks) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700553 if (c instanceof SurfaceHolder.Callback2) {
554 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
555 mSurfaceHolder);
556 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700557 }
558 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700559 } else {
560 mSurface.release();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700561 }
562 } finally {
563 mIsCreating = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700564 if (redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700565 mSession.finishDrawing(mWindow);
566 }
567 }
568 } catch (RemoteException ex) {
569 }
570 if (localLOGV) Log.v(
571 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
572 " w=" + mLayout.width + " h=" + mLayout.height +
573 ", frame=" + mSurfaceFrame);
574 }
575 }
576
577 private void reportSurfaceDestroyed() {
578 if (mDestroyReportNeeded) {
579 mDestroyReportNeeded = false;
580 SurfaceHolder.Callback callbacks[];
581 synchronized (mCallbacks) {
582 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
583 mCallbacks.toArray(callbacks);
584 }
585 for (SurfaceHolder.Callback c : callbacks) {
586 c.surfaceDestroyed(mSurfaceHolder);
587 }
588 }
589 super.onDetachedFromWindow();
590 }
591
592 void handleGetNewSurface() {
593 mNewSurfaceNeeded = true;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700594 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700595 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800596
Derek Sollenberger7179b812010-03-22 13:41:20 -0400597 /**
598 * Check to see if the surface has fixed size dimensions or if the surface's
599 * dimensions are dimensions are dependent on its current layout.
600 *
601 * @return true if the surface has dimensions that are fixed in size
602 * @hide
603 */
604 public boolean isFixedSize() {
605 return (mRequestedWidth != -1 || mRequestedHeight != -1);
606 }
607
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700608 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700609 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500610
611 public MyWindow(SurfaceView surfaceView) {
612 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
613 }
614
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800615 public void resized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800616 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500617 SurfaceView surfaceView = mSurfaceView.get();
618 if (surfaceView != null) {
619 if (localLOGV) Log.v(
620 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800621 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700622 surfaceView.mSurfaceLock.lock();
623 try {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500624 if (reportDraw) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700625 surfaceView.mUpdateWindowNeeded = true;
626 surfaceView.mReportDrawNeeded = true;
627 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
628 } else if (surfaceView.mWinFrame.width() != w
629 || surfaceView.mWinFrame.height() != h) {
630 surfaceView.mUpdateWindowNeeded = true;
631 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700632 }
Dianne Hackborn726426e2010-03-31 22:04:36 -0700633 } finally {
634 surfaceView.mSurfaceLock.unlock();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700635 }
636 }
637 }
638
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700639 public void dispatchAppVisibility(boolean visible) {
640 // The point of SurfaceView is to let the app control the surface.
641 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800642
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700643 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500644 SurfaceView surfaceView = mSurfaceView.get();
645 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800646 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
647 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500648 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700649 }
650
651 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
652 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
653 }
654
655 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
656 }
657
658 int mCurWidth = -1;
659 int mCurHeight = -1;
660 }
661
662 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
663
664 private static final String LOG_TAG = "SurfaceHolder";
665
666 public boolean isCreating() {
667 return mIsCreating;
668 }
669
670 public void addCallback(Callback callback) {
671 synchronized (mCallbacks) {
672 // This is a linear search, but in practice we'll
673 // have only a couple callbacks, so it doesn't matter.
674 if (mCallbacks.contains(callback) == false) {
675 mCallbacks.add(callback);
676 }
677 }
678 }
679
680 public void removeCallback(Callback callback) {
681 synchronized (mCallbacks) {
682 mCallbacks.remove(callback);
683 }
684 }
685
686 public void setFixedSize(int width, int height) {
687 if (mRequestedWidth != width || mRequestedHeight != height) {
688 mRequestedWidth = width;
689 mRequestedHeight = height;
690 requestLayout();
691 }
692 }
693
694 public void setSizeFromLayout() {
695 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
696 mRequestedWidth = mRequestedHeight = -1;
697 requestLayout();
698 }
699 }
700
701 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700702
703 // for backward compatibility reason, OPAQUE always
704 // means 565 for SurfaceView
705 if (format == PixelFormat.OPAQUE)
706 format = PixelFormat.RGB_565;
707
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700708 mRequestedFormat = format;
709 if (mWindow != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700710 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700711 }
712 }
713
Mathias Agopiand2112302010-12-07 19:38:17 -0800714 /**
715 * @deprecated setType is now ignored.
716 */
717 @Deprecated
718 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700719
720 public void setKeepScreenOn(boolean screenOn) {
721 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
722 msg.arg1 = screenOn ? 1 : 0;
723 mHandler.sendMessage(msg);
724 }
725
726 public Canvas lockCanvas() {
727 return internalLockCanvas(null);
728 }
729
730 public Canvas lockCanvas(Rect dirty) {
731 return internalLockCanvas(dirty);
732 }
733
734 private final Canvas internalLockCanvas(Rect dirty) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700735 mSurfaceLock.lock();
736
737 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
738 + mDrawingStopped + ", win=" + mWindow);
739
740 Canvas c = null;
741 if (!mDrawingStopped && mWindow != null) {
742 Rect frame = dirty != null ? dirty : mSurfaceFrame;
743 try {
744 c = mSurface.lockCanvas(frame);
745 } catch (Exception e) {
746 Log.e(LOG_TAG, "Exception locking surface", e);
747 }
748 }
749
750 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
751 if (c != null) {
752 mLastLockTime = SystemClock.uptimeMillis();
753 return c;
754 }
755
756 // If the Surface is not ready to be drawn, then return null,
757 // but throttle calls to this function so it isn't called more
758 // than every 100ms.
759 long now = SystemClock.uptimeMillis();
760 long nextTime = mLastLockTime + 100;
761 if (nextTime > now) {
762 try {
763 Thread.sleep(nextTime-now);
764 } catch (InterruptedException e) {
765 }
766 now = SystemClock.uptimeMillis();
767 }
768 mLastLockTime = now;
769 mSurfaceLock.unlock();
770
771 return null;
772 }
773
774 public void unlockCanvasAndPost(Canvas canvas) {
775 mSurface.unlockCanvasAndPost(canvas);
776 mSurfaceLock.unlock();
777 }
778
779 public Surface getSurface() {
780 return mSurface;
781 }
782
783 public Rect getSurfaceFrame() {
784 return mSurfaceFrame;
785 }
786 };
787}