blob: 3efc799d966970338674c4ea469d5233fa459147 [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 Oshima64f59342009-06-21 00:03:11 -070024import android.content.res.CompatibilityInfo.Translator;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070025import android.graphics.Canvas;
26import android.graphics.PixelFormat;
27import android.graphics.PorterDuff;
28import android.graphics.Rect;
29import android.graphics.Region;
30import android.os.Handler;
31import android.os.Message;
32import android.os.RemoteException;
33import android.os.SystemClock;
34import android.os.ParcelFileDescriptor;
35import android.util.AttributeSet;
36import android.util.Config;
37import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070038
Jon Larimer9bdf5762009-01-02 18:55:15 -050039import java.lang.ref.WeakReference;
40import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070041import java.util.concurrent.locks.ReentrantLock;
42
43/**
44 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
45 * You can control the format of this surface and, if you like, its size; the
46 * SurfaceView takes care of placing the surface at the correct location on the
47 * screen
48 *
49 * <p>The surface is Z ordered so that it is behind the window holding its
50 * SurfaceView; the SurfaceView punches a hole in its window to allow its
51 * surface to be displayed. The view hierarchy will take care of correctly
52 * compositing with the Surface any siblings of the SurfaceView that would
53 * normally appear on top of it. This can be used to place overlays such as
54 * buttons on top of the Surface, though note however that it can have an
55 * impact on performance since a full alpha-blended composite will be performed
56 * each time the Surface changes.
57 *
58 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
59 * which can be retrieved by calling {@link #getHolder}.
60 *
61 * <p>The Surface will be created for you while the SurfaceView's window is
62 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
63 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
64 * Surface is created and destroyed as the window is shown and hidden.
65 *
66 * <p>One of the purposes of this class is to provide a surface in which a
Glenn Kasten334031c2010-11-09 21:54:38 -080067 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070068 * this way, you need to be aware of some threading semantics:
69 *
70 * <ul>
71 * <li> All SurfaceView and
72 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
73 * from the thread running the SurfaceView's window (typically the main thread
74 * of the application). They thus need to correctly synchronize with any
75 * state that is also touched by the drawing thread.
76 * <li> You must ensure that the drawing thread only touches the underlying
77 * Surface while it is valid -- between
78 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
79 * and
80 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
81 * </ul>
82 */
83public class SurfaceView extends View {
84 static private final String TAG = "SurfaceView";
85 static private final boolean DEBUG = false;
86 static private final boolean localLOGV = DEBUG ? true : Config.LOGV;
87
88 final ArrayList<SurfaceHolder.Callback> mCallbacks
89 = new ArrayList<SurfaceHolder.Callback>();
90
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080091 final int[] mLocation = new int[2];
92
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070093 final ReentrantLock mSurfaceLock = new ReentrantLock();
94 final Surface mSurface = new Surface();
95 boolean mDrawingStopped = true;
96
97 final WindowManager.LayoutParams mLayout
98 = new WindowManager.LayoutParams();
99 IWindowSession mSession;
100 MyWindow mWindow;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800101 final Rect mVisibleInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700102 final Rect mWinFrame = new Rect();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800103 final Rect mContentInsets = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700104 final Configuration mConfiguration = new Configuration();
105
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700106 static final int KEEP_SCREEN_ON_MSG = 1;
107 static final int GET_NEW_SURFACE_MSG = 2;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700108 static final int UPDATE_WINDOW_MSG = 3;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700109
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700110 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
111
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700112 boolean mIsCreating = false;
113
114 final Handler mHandler = new Handler() {
115 @Override
116 public void handleMessage(Message msg) {
117 switch (msg.what) {
118 case KEEP_SCREEN_ON_MSG: {
119 setKeepScreenOn(msg.arg1 != 0);
120 } break;
121 case GET_NEW_SURFACE_MSG: {
122 handleGetNewSurface();
123 } break;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700124 case UPDATE_WINDOW_MSG: {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700125 updateWindow(false, false);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700126 } break;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700127 }
128 }
129 };
130
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700131 final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
132 = new ViewTreeObserver.OnScrollChangedListener() {
133 public void onScrollChanged() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700134 updateWindow(false, false);
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700135 }
136 };
137
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700138 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700139 boolean mWindowVisibility = false;
140 boolean mViewVisibility = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700141 int mRequestedWidth = -1;
142 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700143 /* Set SurfaceView's format to 565 by default to maintain backward
144 * compatibility with applications assuming this format.
145 */
146 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700147
148 boolean mHaveFrame = false;
149 boolean mDestroyReportNeeded = false;
150 boolean mNewSurfaceNeeded = false;
151 long mLastLockTime = 0;
152
153 boolean mVisible = false;
154 int mLeft = -1;
155 int mTop = -1;
156 int mWidth = -1;
157 int mHeight = -1;
158 int mFormat = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700159 final Rect mSurfaceFrame = new Rect();
Jeff Brown30bc34f2011-01-25 12:56:56 -0800160 Rect mTmpDirty;
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;
Romain Guyf2499fa2011-01-26 18:31:23 -0800165
166 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
167 new ViewTreeObserver.OnPreDrawListener() {
168 @Override
169 public boolean onPreDraw() {
170 // reposition ourselves where the surface is
Romain Guy0c756222011-01-26 18:45:28 -0800171 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Romain Guyf2499fa2011-01-26 18:31:23 -0800172 updateWindow(false, false);
173 return true;
174 }
175 };
Romain Guy01d5edc2011-01-28 11:28:53 -0800176 private boolean mGlobalListenersAdded;
Romain Guyf2499fa2011-01-26 18:31:23 -0800177
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700178 public SurfaceView(Context context) {
179 super(context);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700180 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700181 }
182
183 public SurfaceView(Context context, AttributeSet attrs) {
184 super(context, attrs);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700185 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700186 }
187
188 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
189 super(context, attrs, defStyle);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700190 init();
191 }
192
193 private void init() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700194 setWillNotDraw(true);
195 }
196
197 /**
198 * Return the SurfaceHolder providing access and control over this
199 * SurfaceView's underlying surface.
200 *
201 * @return SurfaceHolder The holder of the surface.
202 */
203 public SurfaceHolder getHolder() {
204 return mSurfaceHolder;
205 }
206
207 @Override
208 protected void onAttachedToWindow() {
209 super.onAttachedToWindow();
210 mParent.requestTransparentRegion(this);
211 mSession = getWindowSession();
212 mLayout.token = getWindowToken();
213 mLayout.setTitle("SurfaceView");
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700214 mViewVisibility = getVisibility() == VISIBLE;
Romain Guy01d5edc2011-01-28 11:28:53 -0800215
216 if (!mGlobalListenersAdded) {
217 ViewTreeObserver observer = getViewTreeObserver();
218 observer.addOnScrollChangedListener(mScrollChangedListener);
219 observer.addOnPreDrawListener(mDrawListener);
220 mGlobalListenersAdded = true;
221 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700222 }
223
224 @Override
225 protected void onWindowVisibilityChanged(int visibility) {
226 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700227 mWindowVisibility = visibility == VISIBLE;
228 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700229 updateWindow(false, false);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700230 }
231
232 @Override
233 public void setVisibility(int visibility) {
234 super.setVisibility(visibility);
235 mViewVisibility = visibility == VISIBLE;
236 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700237 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700238 }
Romain Guyafc3e112010-06-07 17:04:33 -0700239
240 /**
241 * This method is not intended for general use. It was created
242 * temporarily to improve performance of 3D layers in Launcher
243 * and should be removed and fixed properly.
244 *
245 * Do not call this method. Ever.
246 *
247 * @hide
248 */
249 protected void showSurface() {
250 if (mSession != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700251 updateWindow(true, false);
Romain Guyafc3e112010-06-07 17:04:33 -0700252 }
253 }
254
255 /**
256 * This method is not intended for general use. It was created
257 * temporarily to improve performance of 3D layers in Launcher
258 * and should be removed and fixed properly.
259 *
260 * Do not call this method. Ever.
261 *
262 * @hide
263 */
264 protected void hideSurface() {
265 if (mSession != null && mWindow != null) {
266 mSurfaceLock.lock();
267 try {
268 DisplayMetrics metrics = getResources().getDisplayMetrics();
269 mLayout.x = metrics.widthPixels * 3;
270 mSession.relayout(mWindow, mLayout, mWidth, mHeight, VISIBLE, false,
271 mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurface);
272 } catch (RemoteException e) {
273 // Ignore
274 } finally {
275 mSurfaceLock.unlock();
276 }
277 }
278 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700279
280 @Override
281 protected void onDetachedFromWindow() {
Romain Guy01d5edc2011-01-28 11:28:53 -0800282 if (mGlobalListenersAdded) {
283 ViewTreeObserver observer = getViewTreeObserver();
284 observer.removeOnScrollChangedListener(mScrollChangedListener);
285 observer.removeOnPreDrawListener(mDrawListener);
286 mGlobalListenersAdded = false;
287 }
288
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700289 mRequestedVisible = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700290 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700291 mHaveFrame = false;
292 if (mWindow != null) {
293 try {
294 mSession.remove(mWindow);
295 } catch (RemoteException ex) {
Romain Guy01d5edc2011-01-28 11:28:53 -0800296 // Not much we can do here...
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700297 }
298 mWindow = null;
299 }
300 mSession = null;
301 mLayout.token = null;
302
303 super.onDetachedFromWindow();
304 }
305
306 @Override
307 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800308 int width = mRequestedWidth >= 0
309 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
310 : getDefaultSize(0, widthMeasureSpec);
311 int height = mRequestedHeight >= 0
312 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
313 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700314 setMeasuredDimension(width, height);
315 }
316
Mathias Agopianef115302010-10-04 20:15:08 -0700317 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700318 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700319 protected boolean setFrame(int left, int top, int right, int bottom) {
320 boolean result = super.setFrame(left, top, right, bottom);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700321 updateWindow(false, false);
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700322 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700323 }
324
325 @Override
326 public boolean gatherTransparentRegion(Region region) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700327 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
328 return super.gatherTransparentRegion(region);
329 }
330
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700331 boolean opaque = true;
332 if ((mPrivateFlags & SKIP_DRAW) == 0) {
333 // this view draws, remove it from the transparent region
334 opaque = super.gatherTransparentRegion(region);
335 } else if (region != null) {
336 int w = getWidth();
337 int h = getHeight();
338 if (w>0 && h>0) {
339 getLocationInWindow(mLocation);
340 // otherwise, punch a hole in the whole hierarchy
341 int l = mLocation[0];
342 int t = mLocation[1];
343 region.op(l, t, l+w, t+h, Region.Op.UNION);
344 }
345 }
346 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
347 opaque = false;
348 }
349 return opaque;
350 }
351
352 @Override
353 public void draw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700354 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
355 // draw() is not called when SKIP_DRAW is set
356 if ((mPrivateFlags & SKIP_DRAW) == 0) {
357 // punch a whole in the view-hierarchy below us
358 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
359 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700360 }
361 super.draw(canvas);
362 }
363
364 @Override
365 protected void dispatchDraw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700366 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
367 // if SKIP_DRAW is cleared, draw() has already punched a hole
368 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
369 // punch a whole in the view-hierarchy below us
370 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
371 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700372 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700373 super.dispatchDraw(canvas);
374 }
375
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700376 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700377 * Control whether the surface view's surface is placed on top of another
378 * regular surface view in the window (but still behind the window itself).
379 * This is typically used to place overlays on top of an underlying media
380 * surface view.
381 *
382 * <p>Note that this must be set before the surface view's containing
383 * window is attached to the window manager.
384 *
385 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
386 */
387 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
388 mWindowType = isMediaOverlay
389 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
390 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
391 }
392
393 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700394 * Control whether the surface view's surface is placed on top of its
395 * window. Normally it is placed behind the window, to allow it to
396 * (for the most part) appear to composite with the views in the
397 * hierarchy. By setting this, you cause it to be placed above the
398 * window. This means that none of the contents of the window this
399 * SurfaceView is in will be visible on top of its surface.
400 *
401 * <p>Note that this must be set before the surface view's containing
402 * window is attached to the window manager.
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700403 *
404 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700405 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700406 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500407 if (onTop) {
408 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
409 // ensures the surface is placed below the IME
410 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
411 } else {
412 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
413 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
414 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700415 }
416
417 /**
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700418 * Hack to allow special layering of windows. The type is one of the
419 * types in WindowManager.LayoutParams. This is a hack so:
420 * @hide
421 */
422 public void setWindowType(int type) {
423 mWindowType = type;
424 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700425
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700426 private void updateWindow(boolean force, boolean redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700427 if (!mHaveFrame) {
428 return;
429 }
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700430 ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
Joe Onorato168173a2009-08-12 21:40:29 -0700431 if (viewRoot != null) {
432 mTranslator = viewRoot.mTranslator;
433 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700434
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700435 if (mTranslator != null) {
436 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700437 }
438
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700439 int myWidth = mRequestedWidth;
440 if (myWidth <= 0) myWidth = getWidth();
441 int myHeight = mRequestedHeight;
442 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700443
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700444 getLocationInWindow(mLocation);
445 final boolean creating = mWindow == null;
446 final boolean formatChanged = mFormat != mRequestedFormat;
447 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
448 final boolean visibleChanged = mVisible != mRequestedVisible
449 || mNewSurfaceNeeded;
Mathias Agopiand2112302010-12-07 19:38:17 -0800450
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700451 if (force || creating || formatChanged || sizeChanged || visibleChanged
Mathias Agopiand2112302010-12-07 19:38:17 -0800452 || mLeft != mLocation[0] || mTop != mLocation[1]
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700453 || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700454
455 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
456 + " format=" + formatChanged + " size=" + sizeChanged
457 + " visible=" + visibleChanged
458 + " left=" + (mLeft != mLocation[0])
459 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700460
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700461 try {
462 final boolean visible = mVisible = mRequestedVisible;
463 mLeft = mLocation[0];
464 mTop = mLocation[1];
465 mWidth = myWidth;
466 mHeight = myHeight;
467 mFormat = mRequestedFormat;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700468
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700469 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
470
471 // Places the window relative
472 mLayout.x = mLeft;
473 mLayout.y = mTop;
474 mLayout.width = getWidth();
475 mLayout.height = getHeight();
476 if (mTranslator != null) {
477 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
478 }
479
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700480 mLayout.format = mRequestedFormat;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700481 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
482 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
483 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700484 | WindowManager.LayoutParams.FLAG_SCALED
485 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
486 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
487 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700488 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
489 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
490 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700491
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700492 if (mWindow == null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500493 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700494 mLayout.type = mWindowType;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700495 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700496 mSession.addWithoutInputChannel(mWindow, mLayout,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800497 mVisible ? VISIBLE : GONE, mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700498 }
499
500 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
501 reportSurfaceDestroyed();
502 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700503
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700504 mNewSurfaceNeeded = false;
505
Dianne Hackborn726426e2010-03-31 22:04:36 -0700506 boolean realSizeChanged;
507 boolean reportDrawNeeded;
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700508
Dianne Hackborn726426e2010-03-31 22:04:36 -0700509 mSurfaceLock.lock();
510 try {
511 mUpdateWindowNeeded = false;
512 reportDrawNeeded = mReportDrawNeeded;
513 mReportDrawNeeded = false;
514 mDrawingStopped = !visible;
515
516 final int relayoutResult = mSession.relayout(
517 mWindow, mLayout, mWidth, mHeight,
518 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
519 mVisibleInsets, mConfiguration, mSurface);
520 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
521 mReportDrawNeeded = true;
522 }
523
524 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
525 + ", vis=" + visible + ", frame=" + mWinFrame);
526
527 mSurfaceFrame.left = 0;
528 mSurfaceFrame.top = 0;
529 if (mTranslator == null) {
530 mSurfaceFrame.right = mWinFrame.width();
531 mSurfaceFrame.bottom = mWinFrame.height();
532 } else {
533 float appInvertedScale = mTranslator.applicationInvertedScale;
534 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
535 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
536 }
537
538 final int surfaceWidth = mSurfaceFrame.right;
539 final int surfaceHeight = mSurfaceFrame.bottom;
540 realSizeChanged = mLastSurfaceWidth != surfaceWidth
541 || mLastSurfaceHeight != surfaceHeight;
542 mLastSurfaceWidth = surfaceWidth;
543 mLastSurfaceHeight = surfaceHeight;
544 } finally {
545 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700546 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700547
548 try {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700549 redrawNeeded |= creating | reportDrawNeeded;
550
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700551 if (visible) {
552 mDestroyReportNeeded = true;
553
554 SurfaceHolder.Callback callbacks[];
555 synchronized (mCallbacks) {
556 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
557 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700558 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700559
560 if (visibleChanged) {
561 mIsCreating = true;
562 for (SurfaceHolder.Callback c : callbacks) {
563 c.surfaceCreated(mSurfaceHolder);
564 }
565 }
566 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700567 || visibleChanged || realSizeChanged) {
Dianne Hackborn251fd432010-07-14 16:56:31 -0700568 for (SurfaceHolder.Callback c : callbacks) {
569 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
570 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700571 }
572 if (redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700573 for (SurfaceHolder.Callback c : callbacks) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700574 if (c instanceof SurfaceHolder.Callback2) {
575 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
576 mSurfaceHolder);
577 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700578 }
579 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700580 } else {
581 mSurface.release();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700582 }
583 } finally {
584 mIsCreating = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700585 if (redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700586 mSession.finishDrawing(mWindow);
587 }
588 }
589 } catch (RemoteException ex) {
590 }
591 if (localLOGV) Log.v(
592 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
593 " w=" + mLayout.width + " h=" + mLayout.height +
594 ", frame=" + mSurfaceFrame);
595 }
596 }
597
598 private void reportSurfaceDestroyed() {
599 if (mDestroyReportNeeded) {
600 mDestroyReportNeeded = false;
601 SurfaceHolder.Callback callbacks[];
602 synchronized (mCallbacks) {
603 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
604 mCallbacks.toArray(callbacks);
605 }
606 for (SurfaceHolder.Callback c : callbacks) {
607 c.surfaceDestroyed(mSurfaceHolder);
608 }
609 }
610 super.onDetachedFromWindow();
611 }
612
613 void handleGetNewSurface() {
614 mNewSurfaceNeeded = true;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700615 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700616 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800617
Derek Sollenberger7179b812010-03-22 13:41:20 -0400618 /**
619 * Check to see if the surface has fixed size dimensions or if the surface's
620 * dimensions are dimensions are dependent on its current layout.
621 *
622 * @return true if the surface has dimensions that are fixed in size
623 * @hide
624 */
625 public boolean isFixedSize() {
626 return (mRequestedWidth != -1 || mRequestedHeight != -1);
627 }
628
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700629 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700630 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500631
632 public MyWindow(SurfaceView surfaceView) {
633 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
634 }
635
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800636 public void resized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800637 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500638 SurfaceView surfaceView = mSurfaceView.get();
639 if (surfaceView != null) {
640 if (localLOGV) Log.v(
641 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800642 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700643 surfaceView.mSurfaceLock.lock();
644 try {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500645 if (reportDraw) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700646 surfaceView.mUpdateWindowNeeded = true;
647 surfaceView.mReportDrawNeeded = true;
648 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
649 } else if (surfaceView.mWinFrame.width() != w
650 || surfaceView.mWinFrame.height() != h) {
651 surfaceView.mUpdateWindowNeeded = true;
652 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700653 }
Dianne Hackborn726426e2010-03-31 22:04:36 -0700654 } finally {
655 surfaceView.mSurfaceLock.unlock();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700656 }
657 }
658 }
659
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700660 public void dispatchAppVisibility(boolean visible) {
661 // The point of SurfaceView is to let the app control the surface.
662 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800663
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700664 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500665 SurfaceView surfaceView = mSurfaceView.get();
666 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800667 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
668 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500669 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700670 }
671
672 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
673 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
674 }
675
676 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
677 }
678
679 int mCurWidth = -1;
680 int mCurHeight = -1;
681 }
682
683 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
684
685 private static final String LOG_TAG = "SurfaceHolder";
686
687 public boolean isCreating() {
688 return mIsCreating;
689 }
690
691 public void addCallback(Callback callback) {
692 synchronized (mCallbacks) {
693 // This is a linear search, but in practice we'll
694 // have only a couple callbacks, so it doesn't matter.
695 if (mCallbacks.contains(callback) == false) {
696 mCallbacks.add(callback);
697 }
698 }
699 }
700
701 public void removeCallback(Callback callback) {
702 synchronized (mCallbacks) {
703 mCallbacks.remove(callback);
704 }
705 }
706
707 public void setFixedSize(int width, int height) {
708 if (mRequestedWidth != width || mRequestedHeight != height) {
709 mRequestedWidth = width;
710 mRequestedHeight = height;
711 requestLayout();
712 }
713 }
714
715 public void setSizeFromLayout() {
716 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
717 mRequestedWidth = mRequestedHeight = -1;
718 requestLayout();
719 }
720 }
721
722 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700723
724 // for backward compatibility reason, OPAQUE always
725 // means 565 for SurfaceView
726 if (format == PixelFormat.OPAQUE)
727 format = PixelFormat.RGB_565;
728
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700729 mRequestedFormat = format;
730 if (mWindow != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700731 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700732 }
733 }
734
Mathias Agopiand2112302010-12-07 19:38:17 -0800735 /**
736 * @deprecated setType is now ignored.
737 */
738 @Deprecated
739 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700740
741 public void setKeepScreenOn(boolean screenOn) {
742 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
743 msg.arg1 = screenOn ? 1 : 0;
744 mHandler.sendMessage(msg);
745 }
746
747 public Canvas lockCanvas() {
748 return internalLockCanvas(null);
749 }
750
751 public Canvas lockCanvas(Rect dirty) {
752 return internalLockCanvas(dirty);
753 }
754
755 private final Canvas internalLockCanvas(Rect dirty) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700756 mSurfaceLock.lock();
757
758 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
759 + mDrawingStopped + ", win=" + mWindow);
760
761 Canvas c = null;
762 if (!mDrawingStopped && mWindow != null) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800763 if (dirty == null) {
764 if (mTmpDirty == null) {
765 mTmpDirty = new Rect();
766 }
767 mTmpDirty.set(mSurfaceFrame);
768 dirty = mTmpDirty;
769 }
770
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700771 try {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800772 c = mSurface.lockCanvas(dirty);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700773 } catch (Exception e) {
774 Log.e(LOG_TAG, "Exception locking surface", e);
775 }
776 }
777
778 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
779 if (c != null) {
780 mLastLockTime = SystemClock.uptimeMillis();
781 return c;
782 }
783
784 // If the Surface is not ready to be drawn, then return null,
785 // but throttle calls to this function so it isn't called more
786 // than every 100ms.
787 long now = SystemClock.uptimeMillis();
788 long nextTime = mLastLockTime + 100;
789 if (nextTime > now) {
790 try {
791 Thread.sleep(nextTime-now);
792 } catch (InterruptedException e) {
793 }
794 now = SystemClock.uptimeMillis();
795 }
796 mLastLockTime = now;
797 mSurfaceLock.unlock();
798
799 return null;
800 }
801
802 public void unlockCanvasAndPost(Canvas canvas) {
803 mSurface.unlockCanvasAndPost(canvas);
804 mSurfaceLock.unlock();
805 }
806
807 public Surface getSurface() {
808 return mSurface;
809 }
810
811 public Rect getSurfaceFrame() {
812 return mSurfaceFrame;
813 }
814 };
815}