blob: b45aa9972449ee02be9f3f98861e32a0405a65ba [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: {
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 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;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700213 updateWindow(false, false);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700214 }
215
216 @Override
217 public void setVisibility(int visibility) {
218 super.setVisibility(visibility);
219 mViewVisibility = visibility == VISIBLE;
220 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700221 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700222 }
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) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700235 updateWindow(true, false);
Romain Guyafc3e112010-06-07 17:04:33 -0700236 }
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;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700268 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700269 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
Mathias Agopianef115302010-10-04 20:15:08 -0700290 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700291 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700292 protected boolean setFrame(int left, int top, int right, int bottom) {
293 boolean result = super.setFrame(left, top, right, bottom);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700294 updateWindow(false, false);
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700295 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700296 }
297
298 @Override
299 public boolean gatherTransparentRegion(Region region) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700300 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
301 return super.gatherTransparentRegion(region);
302 }
303
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700304 boolean opaque = true;
305 if ((mPrivateFlags & SKIP_DRAW) == 0) {
306 // this view draws, remove it from the transparent region
307 opaque = super.gatherTransparentRegion(region);
308 } else if (region != null) {
309 int w = getWidth();
310 int h = getHeight();
311 if (w>0 && h>0) {
312 getLocationInWindow(mLocation);
313 // otherwise, punch a hole in the whole hierarchy
314 int l = mLocation[0];
315 int t = mLocation[1];
316 region.op(l, t, l+w, t+h, Region.Op.UNION);
317 }
318 }
319 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
320 opaque = false;
321 }
322 return opaque;
323 }
324
325 @Override
326 public void draw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700327 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
328 // draw() is not called when SKIP_DRAW is set
329 if ((mPrivateFlags & SKIP_DRAW) == 0) {
330 // punch a whole in the view-hierarchy below us
331 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
332 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700333 }
334 super.draw(canvas);
335 }
336
337 @Override
338 protected void dispatchDraw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700339 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
340 // if SKIP_DRAW is cleared, draw() has already punched a hole
341 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
342 // punch a whole in the view-hierarchy below us
343 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
344 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700345 }
346 // reposition ourselves where the surface is
347 mHaveFrame = true;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700348 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700349 super.dispatchDraw(canvas);
350 }
351
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700352 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700353 * Control whether the surface view's surface is placed on top of another
354 * regular surface view in the window (but still behind the window itself).
355 * This is typically used to place overlays on top of an underlying media
356 * surface view.
357 *
358 * <p>Note that this must be set before the surface view's containing
359 * window is attached to the window manager.
360 *
361 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
362 */
363 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
364 mWindowType = isMediaOverlay
365 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
366 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
367 }
368
369 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700370 * Control whether the surface view's surface is placed on top of its
371 * window. Normally it is placed behind the window, to allow it to
372 * (for the most part) appear to composite with the views in the
373 * hierarchy. By setting this, you cause it to be placed above the
374 * window. This means that none of the contents of the window this
375 * SurfaceView is in will be visible on top of its surface.
376 *
377 * <p>Note that this must be set before the surface view's containing
378 * window is attached to the window manager.
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700379 *
380 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700381 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700382 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500383 if (onTop) {
384 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
385 // ensures the surface is placed below the IME
386 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
387 } else {
388 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
389 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
390 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700391 }
392
393 /**
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700394 * Hack to allow special layering of windows. The type is one of the
395 * types in WindowManager.LayoutParams. This is a hack so:
396 * @hide
397 */
398 public void setWindowType(int type) {
399 mWindowType = type;
400 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700401
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700402 private void updateWindow(boolean force, boolean redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700403 if (!mHaveFrame) {
404 return;
405 }
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700406 ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
Joe Onorato168173a2009-08-12 21:40:29 -0700407 if (viewRoot != null) {
408 mTranslator = viewRoot.mTranslator;
409 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700410
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700411 Resources res = getContext().getResources();
412 if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700413 mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700414 }
415
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700416 int myWidth = mRequestedWidth;
417 if (myWidth <= 0) myWidth = getWidth();
418 int myHeight = mRequestedHeight;
419 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700420
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700421 getLocationInWindow(mLocation);
422 final boolean creating = mWindow == null;
423 final boolean formatChanged = mFormat != mRequestedFormat;
424 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
425 final boolean visibleChanged = mVisible != mRequestedVisible
426 || mNewSurfaceNeeded;
427 final boolean typeChanged = mType != mRequestedType;
428 if (force || creating || formatChanged || sizeChanged || visibleChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700429 || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700430 || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700431
432 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
433 + " format=" + formatChanged + " size=" + sizeChanged
434 + " visible=" + visibleChanged
435 + " left=" + (mLeft != mLocation[0])
436 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700437
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700438 try {
439 final boolean visible = mVisible = mRequestedVisible;
440 mLeft = mLocation[0];
441 mTop = mLocation[1];
442 mWidth = myWidth;
443 mHeight = myHeight;
444 mFormat = mRequestedFormat;
445 mType = mRequestedType;
446
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700447 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
448
449 // Places the window relative
450 mLayout.x = mLeft;
451 mLayout.y = mTop;
452 mLayout.width = getWidth();
453 mLayout.height = getHeight();
454 if (mTranslator != null) {
455 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
456 }
457
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700458 mLayout.format = mRequestedFormat;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700459 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
460 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
461 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700462 | WindowManager.LayoutParams.FLAG_SCALED
463 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
464 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
465 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700466 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
467 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
468 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700469
470 mLayout.memoryType = mRequestedType;
471
472 if (mWindow == null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500473 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700474 mLayout.type = mWindowType;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700475 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700476 mSession.addWithoutInputChannel(mWindow, mLayout,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800477 mVisible ? VISIBLE : GONE, mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700478 }
479
480 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
481 reportSurfaceDestroyed();
482 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700483
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700484 mNewSurfaceNeeded = false;
485
Dianne Hackborn726426e2010-03-31 22:04:36 -0700486 boolean realSizeChanged;
487 boolean reportDrawNeeded;
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700488
Dianne Hackborn726426e2010-03-31 22:04:36 -0700489 mSurfaceLock.lock();
490 try {
491 mUpdateWindowNeeded = false;
492 reportDrawNeeded = mReportDrawNeeded;
493 mReportDrawNeeded = false;
494 mDrawingStopped = !visible;
495
496 final int relayoutResult = mSession.relayout(
497 mWindow, mLayout, mWidth, mHeight,
498 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
499 mVisibleInsets, mConfiguration, mSurface);
500 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
501 mReportDrawNeeded = true;
502 }
503
504 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
505 + ", vis=" + visible + ", frame=" + mWinFrame);
506
507 mSurfaceFrame.left = 0;
508 mSurfaceFrame.top = 0;
509 if (mTranslator == null) {
510 mSurfaceFrame.right = mWinFrame.width();
511 mSurfaceFrame.bottom = mWinFrame.height();
512 } else {
513 float appInvertedScale = mTranslator.applicationInvertedScale;
514 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
515 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
516 }
517
518 final int surfaceWidth = mSurfaceFrame.right;
519 final int surfaceHeight = mSurfaceFrame.bottom;
520 realSizeChanged = mLastSurfaceWidth != surfaceWidth
521 || mLastSurfaceHeight != surfaceHeight;
522 mLastSurfaceWidth = surfaceWidth;
523 mLastSurfaceHeight = surfaceHeight;
524 } finally {
525 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700526 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700527
528 try {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700529 redrawNeeded |= creating | reportDrawNeeded;
530
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700531 if (visible) {
532 mDestroyReportNeeded = true;
533
534 SurfaceHolder.Callback callbacks[];
535 synchronized (mCallbacks) {
536 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
537 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700538 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700539
540 if (visibleChanged) {
541 mIsCreating = true;
542 for (SurfaceHolder.Callback c : callbacks) {
543 c.surfaceCreated(mSurfaceHolder);
544 }
545 }
546 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700547 || visibleChanged || realSizeChanged) {
Dianne Hackborn251fd432010-07-14 16:56:31 -0700548 for (SurfaceHolder.Callback c : callbacks) {
549 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
550 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700551 }
552 if (redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700553 for (SurfaceHolder.Callback c : callbacks) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700554 if (c instanceof SurfaceHolder.Callback2) {
555 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
556 mSurfaceHolder);
557 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700558 }
559 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700560 } else {
561 mSurface.release();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700562 }
563 } finally {
564 mIsCreating = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700565 if (redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700566 mSession.finishDrawing(mWindow);
567 }
568 }
569 } catch (RemoteException ex) {
570 }
571 if (localLOGV) Log.v(
572 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
573 " w=" + mLayout.width + " h=" + mLayout.height +
574 ", frame=" + mSurfaceFrame);
575 }
576 }
577
578 private void reportSurfaceDestroyed() {
579 if (mDestroyReportNeeded) {
580 mDestroyReportNeeded = false;
581 SurfaceHolder.Callback callbacks[];
582 synchronized (mCallbacks) {
583 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
584 mCallbacks.toArray(callbacks);
585 }
586 for (SurfaceHolder.Callback c : callbacks) {
587 c.surfaceDestroyed(mSurfaceHolder);
588 }
589 }
590 super.onDetachedFromWindow();
591 }
592
593 void handleGetNewSurface() {
594 mNewSurfaceNeeded = true;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700595 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700596 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800597
Derek Sollenberger7179b812010-03-22 13:41:20 -0400598 /**
599 * Check to see if the surface has fixed size dimensions or if the surface's
600 * dimensions are dimensions are dependent on its current layout.
601 *
602 * @return true if the surface has dimensions that are fixed in size
603 * @hide
604 */
605 public boolean isFixedSize() {
606 return (mRequestedWidth != -1 || mRequestedHeight != -1);
607 }
608
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700609 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700610 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500611
612 public MyWindow(SurfaceView surfaceView) {
613 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
614 }
615
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800616 public void resized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800617 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500618 SurfaceView surfaceView = mSurfaceView.get();
619 if (surfaceView != null) {
620 if (localLOGV) Log.v(
621 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800622 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700623 surfaceView.mSurfaceLock.lock();
624 try {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500625 if (reportDraw) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700626 surfaceView.mUpdateWindowNeeded = true;
627 surfaceView.mReportDrawNeeded = true;
628 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
629 } else if (surfaceView.mWinFrame.width() != w
630 || surfaceView.mWinFrame.height() != h) {
631 surfaceView.mUpdateWindowNeeded = true;
632 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700633 }
Dianne Hackborn726426e2010-03-31 22:04:36 -0700634 } finally {
635 surfaceView.mSurfaceLock.unlock();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700636 }
637 }
638 }
639
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700640 public void dispatchAppVisibility(boolean visible) {
641 // The point of SurfaceView is to let the app control the surface.
642 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800643
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700644 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500645 SurfaceView surfaceView = mSurfaceView.get();
646 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800647 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
648 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500649 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700650 }
651
652 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
653 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
654 }
655
656 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
657 }
658
659 int mCurWidth = -1;
660 int mCurHeight = -1;
661 }
662
663 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
664
665 private static final String LOG_TAG = "SurfaceHolder";
666
667 public boolean isCreating() {
668 return mIsCreating;
669 }
670
671 public void addCallback(Callback callback) {
672 synchronized (mCallbacks) {
673 // This is a linear search, but in practice we'll
674 // have only a couple callbacks, so it doesn't matter.
675 if (mCallbacks.contains(callback) == false) {
676 mCallbacks.add(callback);
677 }
678 }
679 }
680
681 public void removeCallback(Callback callback) {
682 synchronized (mCallbacks) {
683 mCallbacks.remove(callback);
684 }
685 }
686
687 public void setFixedSize(int width, int height) {
688 if (mRequestedWidth != width || mRequestedHeight != height) {
689 mRequestedWidth = width;
690 mRequestedHeight = height;
691 requestLayout();
692 }
693 }
694
695 public void setSizeFromLayout() {
696 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
697 mRequestedWidth = mRequestedHeight = -1;
698 requestLayout();
699 }
700 }
701
702 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700703
704 // for backward compatibility reason, OPAQUE always
705 // means 565 for SurfaceView
706 if (format == PixelFormat.OPAQUE)
707 format = PixelFormat.RGB_565;
708
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700709 mRequestedFormat = format;
710 if (mWindow != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700711 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700712 }
713 }
714
715 public void setType(int type) {
716 switch (type) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700717 case SURFACE_TYPE_HARDWARE:
718 case SURFACE_TYPE_GPU:
Mathias Agopian317a6282009-08-13 17:29:02 -0700719 // these are deprecated, treat as "NORMAL"
720 type = SURFACE_TYPE_NORMAL;
721 break;
722 }
723 switch (type) {
724 case SURFACE_TYPE_NORMAL:
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700725 case SURFACE_TYPE_PUSH_BUFFERS:
726 mRequestedType = type;
727 if (mWindow != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700728 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700729 }
730 break;
731 }
732 }
733
734 public void setKeepScreenOn(boolean screenOn) {
735 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
736 msg.arg1 = screenOn ? 1 : 0;
737 mHandler.sendMessage(msg);
738 }
739
740 public Canvas lockCanvas() {
741 return internalLockCanvas(null);
742 }
743
744 public Canvas lockCanvas(Rect dirty) {
745 return internalLockCanvas(dirty);
746 }
747
748 private final Canvas internalLockCanvas(Rect dirty) {
749 if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
750 throw new BadSurfaceTypeException(
751 "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
752 }
753 mSurfaceLock.lock();
754
755 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
756 + mDrawingStopped + ", win=" + mWindow);
757
758 Canvas c = null;
759 if (!mDrawingStopped && mWindow != null) {
760 Rect frame = dirty != null ? dirty : mSurfaceFrame;
761 try {
762 c = mSurface.lockCanvas(frame);
763 } catch (Exception e) {
764 Log.e(LOG_TAG, "Exception locking surface", e);
765 }
766 }
767
768 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
769 if (c != null) {
770 mLastLockTime = SystemClock.uptimeMillis();
771 return c;
772 }
773
774 // If the Surface is not ready to be drawn, then return null,
775 // but throttle calls to this function so it isn't called more
776 // than every 100ms.
777 long now = SystemClock.uptimeMillis();
778 long nextTime = mLastLockTime + 100;
779 if (nextTime > now) {
780 try {
781 Thread.sleep(nextTime-now);
782 } catch (InterruptedException e) {
783 }
784 now = SystemClock.uptimeMillis();
785 }
786 mLastLockTime = now;
787 mSurfaceLock.unlock();
788
789 return null;
790 }
791
792 public void unlockCanvasAndPost(Canvas canvas) {
793 mSurface.unlockCanvasAndPost(canvas);
794 mSurfaceLock.unlock();
795 }
796
797 public Surface getSurface() {
798 return mSurface;
799 }
800
801 public Rect getSurfaceFrame() {
802 return mSurfaceFrame;
803 }
804 };
805}