blob: 5d516700873f536b3a98b7df04e411740c56bc4f [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Dianne Hackborn72c82ab2009-08-11 21:13:54 -070019import com.android.internal.view.BaseIWindow;
20
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070021import android.content.Context;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080022import android.content.res.Configuration;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070023import android.content.res.CompatibilityInfo.Translator;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070024import android.graphics.Canvas;
25import android.graphics.PixelFormat;
26import android.graphics.PorterDuff;
27import android.graphics.Rect;
28import android.graphics.Region;
29import android.os.Handler;
30import android.os.Message;
31import android.os.RemoteException;
32import android.os.SystemClock;
33import android.os.ParcelFileDescriptor;
34import android.util.AttributeSet;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070035import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070036
Jon Larimer9bdf5762009-01-02 18:55:15 -050037import java.lang.ref.WeakReference;
38import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070039import java.util.concurrent.locks.ReentrantLock;
40
41/**
42 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
43 * You can control the format of this surface and, if you like, its size; the
44 * SurfaceView takes care of placing the surface at the correct location on the
45 * screen
46 *
47 * <p>The surface is Z ordered so that it is behind the window holding its
48 * SurfaceView; the SurfaceView punches a hole in its window to allow its
49 * surface to be displayed. The view hierarchy will take care of correctly
50 * compositing with the Surface any siblings of the SurfaceView that would
51 * normally appear on top of it. This can be used to place overlays such as
52 * buttons on top of the Surface, though note however that it can have an
53 * impact on performance since a full alpha-blended composite will be performed
54 * each time the Surface changes.
55 *
56 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
57 * which can be retrieved by calling {@link #getHolder}.
58 *
59 * <p>The Surface will be created for you while the SurfaceView's window is
60 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
61 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
62 * Surface is created and destroyed as the window is shown and hidden.
63 *
64 * <p>One of the purposes of this class is to provide a surface in which a
Glenn Kasten334031c2010-11-09 21:54:38 -080065 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070066 * this way, you need to be aware of some threading semantics:
67 *
68 * <ul>
69 * <li> All SurfaceView and
70 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
71 * from the thread running the SurfaceView's window (typically the main thread
72 * of the application). They thus need to correctly synchronize with any
73 * state that is also touched by the drawing thread.
74 * <li> You must ensure that the drawing thread only touches the underlying
75 * Surface while it is valid -- between
76 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
77 * and
78 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
79 * </ul>
80 */
81public class SurfaceView extends View {
82 static private final String TAG = "SurfaceView";
83 static private final boolean DEBUG = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070084
85 final ArrayList<SurfaceHolder.Callback> mCallbacks
86 = new ArrayList<SurfaceHolder.Callback>();
87
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080088 final int[] mLocation = new int[2];
89
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070090 final ReentrantLock mSurfaceLock = new ReentrantLock();
Dianne Hackborn61566cc2011-12-02 23:31:52 -080091 final Surface mSurface = new Surface(); // Current surface in use
92 final Surface mNewSurface = new Surface(); // New surface we are switching to
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070093 boolean mDrawingStopped = true;
94
95 final WindowManager.LayoutParams mLayout
96 = new WindowManager.LayoutParams();
97 IWindowSession mSession;
98 MyWindow mWindow;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080099 final Rect mVisibleInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700100 final Rect mWinFrame = new Rect();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800101 final Rect mContentInsets = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700102 final Configuration mConfiguration = new Configuration();
103
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700104 static final int KEEP_SCREEN_ON_MSG = 1;
105 static final int GET_NEW_SURFACE_MSG = 2;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700106 static final int UPDATE_WINDOW_MSG = 3;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700107
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700108 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
109
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700110 boolean mIsCreating = false;
111
112 final Handler mHandler = new Handler() {
113 @Override
114 public void handleMessage(Message msg) {
115 switch (msg.what) {
116 case KEEP_SCREEN_ON_MSG: {
117 setKeepScreenOn(msg.arg1 != 0);
118 } break;
119 case GET_NEW_SURFACE_MSG: {
120 handleGetNewSurface();
121 } break;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700122 case UPDATE_WINDOW_MSG: {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700123 updateWindow(false, false);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700124 } break;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700125 }
126 }
127 };
128
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700129 final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
130 = new ViewTreeObserver.OnScrollChangedListener() {
131 public void onScrollChanged() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700132 updateWindow(false, false);
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700133 }
134 };
135
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700136 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700137 boolean mWindowVisibility = false;
138 boolean mViewVisibility = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700139 int mRequestedWidth = -1;
140 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700141 /* Set SurfaceView's format to 565 by default to maintain backward
142 * compatibility with applications assuming this format.
143 */
144 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700145
146 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800147 boolean mSurfaceCreated = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700148 long mLastLockTime = 0;
149
150 boolean mVisible = false;
151 int mLeft = -1;
152 int mTop = -1;
153 int mWidth = -1;
154 int mHeight = -1;
155 int mFormat = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700156 final Rect mSurfaceFrame = new Rect();
Jeff Brown30bc34f2011-01-25 12:56:56 -0800157 Rect mTmpDirty;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700158 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
159 boolean mUpdateWindowNeeded;
160 boolean mReportDrawNeeded;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700161 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800162
163 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
164 new ViewTreeObserver.OnPreDrawListener() {
165 @Override
166 public boolean onPreDraw() {
167 // reposition ourselves where the surface is
Romain Guy0c756222011-01-26 18:45:28 -0800168 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Romain Guyf2499fa2011-01-26 18:31:23 -0800169 updateWindow(false, false);
170 return true;
171 }
172 };
Romain Guy01d5edc2011-01-28 11:28:53 -0800173 private boolean mGlobalListenersAdded;
Romain Guyf2499fa2011-01-26 18:31:23 -0800174
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700175 public SurfaceView(Context context) {
176 super(context);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700177 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700178 }
179
180 public SurfaceView(Context context, AttributeSet attrs) {
181 super(context, attrs);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700182 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700183 }
184
185 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
186 super(context, attrs, defStyle);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700187 init();
188 }
189
190 private void init() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700191 setWillNotDraw(true);
192 }
193
194 /**
195 * Return the SurfaceHolder providing access and control over this
196 * SurfaceView's underlying surface.
197 *
198 * @return SurfaceHolder The holder of the surface.
199 */
200 public SurfaceHolder getHolder() {
201 return mSurfaceHolder;
202 }
203
204 @Override
205 protected void onAttachedToWindow() {
206 super.onAttachedToWindow();
207 mParent.requestTransparentRegion(this);
208 mSession = getWindowSession();
209 mLayout.token = getWindowToken();
210 mLayout.setTitle("SurfaceView");
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700211 mViewVisibility = getVisibility() == VISIBLE;
Romain Guy01d5edc2011-01-28 11:28:53 -0800212
213 if (!mGlobalListenersAdded) {
214 ViewTreeObserver observer = getViewTreeObserver();
215 observer.addOnScrollChangedListener(mScrollChangedListener);
216 observer.addOnPreDrawListener(mDrawListener);
217 mGlobalListenersAdded = true;
218 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700219 }
220
221 @Override
222 protected void onWindowVisibilityChanged(int visibility) {
223 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700224 mWindowVisibility = visibility == VISIBLE;
225 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700226 updateWindow(false, false);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700227 }
228
229 @Override
230 public void setVisibility(int visibility) {
231 super.setVisibility(visibility);
232 mViewVisibility = visibility == VISIBLE;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700233 boolean newRequestedVisible = mWindowVisibility && mViewVisibility;
234 if (newRequestedVisible != mRequestedVisible) {
235 // our base class (View) invalidates the layout only when
236 // we go from/to the GONE state. However, SurfaceView needs
237 // to request a re-layout when the visibility changes at all.
238 // This is needed because the transparent region is computed
239 // as part of the layout phase, and it changes (obviously) when
240 // the visibility changes.
241 requestLayout();
242 }
243 mRequestedVisible = newRequestedVisible;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700244 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700245 }
Romain Guyafc3e112010-06-07 17:04:33 -0700246
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700247 @Override
248 protected void onDetachedFromWindow() {
Romain Guy01d5edc2011-01-28 11:28:53 -0800249 if (mGlobalListenersAdded) {
250 ViewTreeObserver observer = getViewTreeObserver();
251 observer.removeOnScrollChangedListener(mScrollChangedListener);
252 observer.removeOnPreDrawListener(mDrawListener);
253 mGlobalListenersAdded = false;
254 }
255
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700256 mRequestedVisible = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700257 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700258 mHaveFrame = false;
259 if (mWindow != null) {
260 try {
261 mSession.remove(mWindow);
262 } catch (RemoteException ex) {
Romain Guy01d5edc2011-01-28 11:28:53 -0800263 // Not much we can do here...
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700264 }
265 mWindow = null;
266 }
267 mSession = null;
268 mLayout.token = null;
269
270 super.onDetachedFromWindow();
271 }
272
273 @Override
274 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800275 int width = mRequestedWidth >= 0
276 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
277 : getDefaultSize(0, widthMeasureSpec);
278 int height = mRequestedHeight >= 0
279 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
280 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700281 setMeasuredDimension(width, height);
282 }
283
Mathias Agopianef115302010-10-04 20:15:08 -0700284 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700285 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700286 protected boolean setFrame(int left, int top, int right, int bottom) {
287 boolean result = super.setFrame(left, top, right, bottom);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700288 updateWindow(false, false);
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700289 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700290 }
291
292 @Override
293 public boolean gatherTransparentRegion(Region region) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700294 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
295 return super.gatherTransparentRegion(region);
296 }
297
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700298 boolean opaque = true;
299 if ((mPrivateFlags & SKIP_DRAW) == 0) {
300 // this view draws, remove it from the transparent region
301 opaque = super.gatherTransparentRegion(region);
302 } else if (region != null) {
303 int w = getWidth();
304 int h = getHeight();
305 if (w>0 && h>0) {
306 getLocationInWindow(mLocation);
307 // otherwise, punch a hole in the whole hierarchy
308 int l = mLocation[0];
309 int t = mLocation[1];
310 region.op(l, t, l+w, t+h, Region.Op.UNION);
311 }
312 }
313 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
314 opaque = false;
315 }
316 return opaque;
317 }
318
319 @Override
320 public void draw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700321 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
322 // draw() is not called when SKIP_DRAW is set
323 if ((mPrivateFlags & SKIP_DRAW) == 0) {
324 // punch a whole in the view-hierarchy below us
325 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
326 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700327 }
328 super.draw(canvas);
329 }
330
331 @Override
332 protected void dispatchDraw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700333 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
334 // if SKIP_DRAW is cleared, draw() has already punched a hole
335 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
336 // punch a whole in the view-hierarchy below us
337 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
338 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700339 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700340 super.dispatchDraw(canvas);
341 }
342
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700343 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700344 * Control whether the surface view's surface is placed on top of another
345 * regular surface view in the window (but still behind the window itself).
346 * This is typically used to place overlays on top of an underlying media
347 * surface view.
348 *
349 * <p>Note that this must be set before the surface view's containing
350 * window is attached to the window manager.
351 *
352 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
353 */
354 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
355 mWindowType = isMediaOverlay
356 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
357 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
358 }
359
360 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700361 * Control whether the surface view's surface is placed on top of its
362 * window. Normally it is placed behind the window, to allow it to
363 * (for the most part) appear to composite with the views in the
364 * hierarchy. By setting this, you cause it to be placed above the
365 * window. This means that none of the contents of the window this
366 * SurfaceView is in will be visible on top of its surface.
367 *
368 * <p>Note that this must be set before the surface view's containing
369 * window is attached to the window manager.
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700370 *
371 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700372 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700373 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500374 if (onTop) {
375 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
376 // ensures the surface is placed below the IME
377 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
378 } else {
379 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
380 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
381 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700382 }
383
384 /**
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700385 * Hack to allow special layering of windows. The type is one of the
386 * types in WindowManager.LayoutParams. This is a hack so:
387 * @hide
388 */
389 public void setWindowType(int type) {
390 mWindowType = type;
391 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700392
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700393 private void updateWindow(boolean force, boolean redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700394 if (!mHaveFrame) {
395 return;
396 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800397 ViewRootImpl viewRoot = getViewRootImpl();
Joe Onorato168173a2009-08-12 21:40:29 -0700398 if (viewRoot != null) {
399 mTranslator = viewRoot.mTranslator;
400 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700401
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700402 if (mTranslator != null) {
403 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700404 }
405
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700406 int myWidth = mRequestedWidth;
407 if (myWidth <= 0) myWidth = getWidth();
408 int myHeight = mRequestedHeight;
409 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700410
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700411 getLocationInWindow(mLocation);
412 final boolean creating = mWindow == null;
413 final boolean formatChanged = mFormat != mRequestedFormat;
414 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800415 final boolean visibleChanged = mVisible != mRequestedVisible;
Mathias Agopiand2112302010-12-07 19:38:17 -0800416
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700417 if (force || creating || formatChanged || sizeChanged || visibleChanged
Mathias Agopiand2112302010-12-07 19:38:17 -0800418 || mLeft != mLocation[0] || mTop != mLocation[1]
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700419 || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700420
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800421 if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700422 + " format=" + formatChanged + " size=" + sizeChanged
423 + " visible=" + visibleChanged
424 + " left=" + (mLeft != mLocation[0])
425 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700426
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700427 try {
428 final boolean visible = mVisible = mRequestedVisible;
429 mLeft = mLocation[0];
430 mTop = mLocation[1];
431 mWidth = myWidth;
432 mHeight = myHeight;
433 mFormat = mRequestedFormat;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700434
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700435 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
436
437 // Places the window relative
438 mLayout.x = mLeft;
439 mLayout.y = mTop;
440 mLayout.width = getWidth();
441 mLayout.height = getHeight();
442 if (mTranslator != null) {
443 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
444 }
445
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700446 mLayout.format = mRequestedFormat;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700447 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
448 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
449 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700450 | WindowManager.LayoutParams.FLAG_SCALED
451 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
452 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
453 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700454 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
455 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
456 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700457
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700458 if (mWindow == null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500459 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700460 mLayout.type = mWindowType;
Fabrice Di Meglioaac0d4e2012-07-19 19:21:26 -0700461 mLayout.gravity = Gravity.START|Gravity.TOP;
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700462 mSession.addWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800463 mVisible ? VISIBLE : GONE, mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700464 }
465
Dianne Hackborn726426e2010-03-31 22:04:36 -0700466 boolean realSizeChanged;
467 boolean reportDrawNeeded;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800468
469 int relayoutResult;
470
Dianne Hackborn726426e2010-03-31 22:04:36 -0700471 mSurfaceLock.lock();
472 try {
473 mUpdateWindowNeeded = false;
474 reportDrawNeeded = mReportDrawNeeded;
475 mReportDrawNeeded = false;
476 mDrawingStopped = !visible;
477
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800478 if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
479
480 relayoutResult = mSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700481 mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800482 visible ? VISIBLE : GONE,
483 WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY,
Dianne Hackborn85afd1b2012-05-13 13:31:06 -0700484 mWinFrame, mContentInsets,
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800485 mVisibleInsets, mConfiguration, mNewSurface);
486 if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700487 mReportDrawNeeded = true;
488 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800489
490 if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
Dianne Hackborn726426e2010-03-31 22:04:36 -0700491 + ", vis=" + visible + ", frame=" + mWinFrame);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800492
Dianne Hackborn726426e2010-03-31 22:04:36 -0700493 mSurfaceFrame.left = 0;
494 mSurfaceFrame.top = 0;
495 if (mTranslator == null) {
496 mSurfaceFrame.right = mWinFrame.width();
497 mSurfaceFrame.bottom = mWinFrame.height();
498 } else {
499 float appInvertedScale = mTranslator.applicationInvertedScale;
500 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
501 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
502 }
503
504 final int surfaceWidth = mSurfaceFrame.right;
505 final int surfaceHeight = mSurfaceFrame.bottom;
506 realSizeChanged = mLastSurfaceWidth != surfaceWidth
507 || mLastSurfaceHeight != surfaceHeight;
508 mLastSurfaceWidth = surfaceWidth;
509 mLastSurfaceHeight = surfaceHeight;
510 } finally {
511 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700512 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700513
514 try {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700515 redrawNeeded |= creating | reportDrawNeeded;
516
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800517 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700518
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800519 final boolean surfaceChanged =
520 (relayoutResult&WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED) != 0;
521 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
522 mSurfaceCreated = false;
523 if (mSurface.isValid()) {
524 if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
525 callbacks = getSurfaceCallbacks();
526 for (SurfaceHolder.Callback c : callbacks) {
527 c.surfaceDestroyed(mSurfaceHolder);
528 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700529 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800530 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700531
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800532 mSurface.transferFrom(mNewSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800533
534 if (visible) {
535 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
536 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700537 mIsCreating = true;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800538 if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
539 if (callbacks == null) {
540 callbacks = getSurfaceCallbacks();
541 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700542 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 Hackborn6d05fd32011-11-19 14:36:15 -0800548 if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
549 + " w=" + myWidth + " h=" + myHeight);
550 if (callbacks == null) {
551 callbacks = getSurfaceCallbacks();
552 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700553 for (SurfaceHolder.Callback c : callbacks) {
554 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
555 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700556 }
557 if (redrawNeeded) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800558 if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
559 if (callbacks == null) {
560 callbacks = getSurfaceCallbacks();
561 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700562 for (SurfaceHolder.Callback c : callbacks) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700563 if (c instanceof SurfaceHolder.Callback2) {
564 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
565 mSurfaceHolder);
566 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700567 }
568 }
569 }
570 } finally {
571 mIsCreating = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700572 if (redrawNeeded) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800573 if (DEBUG) Log.i(TAG, "finishedDrawing");
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700574 mSession.finishDrawing(mWindow);
575 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800576 mSession.performDeferredDestroy(mWindow);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700577 }
578 } catch (RemoteException ex) {
579 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800580 if (DEBUG) Log.v(
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700581 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
582 " w=" + mLayout.width + " h=" + mLayout.height +
583 ", frame=" + mSurfaceFrame);
584 }
585 }
586
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800587 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
588 SurfaceHolder.Callback callbacks[];
589 synchronized (mCallbacks) {
590 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
591 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700592 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800593 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700594 }
595
596 void handleGetNewSurface() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700597 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700598 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800599
Derek Sollenberger7179b812010-03-22 13:41:20 -0400600 /**
601 * Check to see if the surface has fixed size dimensions or if the surface's
602 * dimensions are dimensions are dependent on its current layout.
603 *
604 * @return true if the surface has dimensions that are fixed in size
605 * @hide
606 */
607 public boolean isFixedSize() {
608 return (mRequestedWidth != -1 || mRequestedHeight != -1);
609 }
610
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700611 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700612 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500613
614 public MyWindow(SurfaceView surfaceView) {
615 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
616 }
617
Dianne Hackborn85afd1b2012-05-13 13:31:06 -0700618 public void resized(int w, int h, Rect contentInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800619 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500620 SurfaceView surfaceView = mSurfaceView.get();
621 if (surfaceView != null) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800622 if (DEBUG) Log.v(
Jon Larimer9bdf5762009-01-02 18:55:15 -0500623 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800624 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700625 surfaceView.mSurfaceLock.lock();
626 try {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500627 if (reportDraw) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700628 surfaceView.mUpdateWindowNeeded = true;
629 surfaceView.mReportDrawNeeded = true;
630 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
631 } else if (surfaceView.mWinFrame.width() != w
632 || surfaceView.mWinFrame.height() != h) {
633 surfaceView.mUpdateWindowNeeded = true;
634 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700635 }
Dianne Hackborn726426e2010-03-31 22:04:36 -0700636 } finally {
637 surfaceView.mSurfaceLock.unlock();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700638 }
639 }
640 }
641
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700642 public void dispatchAppVisibility(boolean visible) {
643 // The point of SurfaceView is to let the app control the surface.
644 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800645
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700646 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500647 SurfaceView surfaceView = mSurfaceView.get();
648 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800649 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
650 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500651 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700652 }
653
654 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
655 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
656 }
657
658 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
659 }
660
661 int mCurWidth = -1;
662 int mCurHeight = -1;
663 }
664
665 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
666
667 private static final String LOG_TAG = "SurfaceHolder";
668
669 public boolean isCreating() {
670 return mIsCreating;
671 }
672
673 public void addCallback(Callback callback) {
674 synchronized (mCallbacks) {
675 // This is a linear search, but in practice we'll
676 // have only a couple callbacks, so it doesn't matter.
677 if (mCallbacks.contains(callback) == false) {
678 mCallbacks.add(callback);
679 }
680 }
681 }
682
683 public void removeCallback(Callback callback) {
684 synchronized (mCallbacks) {
685 mCallbacks.remove(callback);
686 }
687 }
688
689 public void setFixedSize(int width, int height) {
690 if (mRequestedWidth != width || mRequestedHeight != height) {
691 mRequestedWidth = width;
692 mRequestedHeight = height;
693 requestLayout();
694 }
695 }
696
697 public void setSizeFromLayout() {
698 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
699 mRequestedWidth = mRequestedHeight = -1;
700 requestLayout();
701 }
702 }
703
704 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700705
706 // for backward compatibility reason, OPAQUE always
707 // means 565 for SurfaceView
708 if (format == PixelFormat.OPAQUE)
709 format = PixelFormat.RGB_565;
710
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700711 mRequestedFormat = format;
712 if (mWindow != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700713 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700714 }
715 }
716
Mathias Agopiand2112302010-12-07 19:38:17 -0800717 /**
718 * @deprecated setType is now ignored.
719 */
720 @Deprecated
721 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700722
723 public void setKeepScreenOn(boolean screenOn) {
724 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
725 msg.arg1 = screenOn ? 1 : 0;
726 mHandler.sendMessage(msg);
727 }
728
729 public Canvas lockCanvas() {
730 return internalLockCanvas(null);
731 }
732
733 public Canvas lockCanvas(Rect dirty) {
734 return internalLockCanvas(dirty);
735 }
736
737 private final Canvas internalLockCanvas(Rect dirty) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700738 mSurfaceLock.lock();
739
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800740 if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700741 + mDrawingStopped + ", win=" + mWindow);
742
743 Canvas c = null;
744 if (!mDrawingStopped && mWindow != null) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800745 if (dirty == null) {
746 if (mTmpDirty == null) {
747 mTmpDirty = new Rect();
748 }
749 mTmpDirty.set(mSurfaceFrame);
750 dirty = mTmpDirty;
751 }
752
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700753 try {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800754 c = mSurface.lockCanvas(dirty);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700755 } catch (Exception e) {
756 Log.e(LOG_TAG, "Exception locking surface", e);
757 }
758 }
759
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800760 if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700761 if (c != null) {
762 mLastLockTime = SystemClock.uptimeMillis();
763 return c;
764 }
765
766 // If the Surface is not ready to be drawn, then return null,
767 // but throttle calls to this function so it isn't called more
768 // than every 100ms.
769 long now = SystemClock.uptimeMillis();
770 long nextTime = mLastLockTime + 100;
771 if (nextTime > now) {
772 try {
773 Thread.sleep(nextTime-now);
774 } catch (InterruptedException e) {
775 }
776 now = SystemClock.uptimeMillis();
777 }
778 mLastLockTime = now;
779 mSurfaceLock.unlock();
780
781 return null;
782 }
783
784 public void unlockCanvasAndPost(Canvas canvas) {
785 mSurface.unlockCanvasAndPost(canvas);
786 mSurfaceLock.unlock();
787 }
788
789 public Surface getSurface() {
790 return mSurface;
791 }
792
793 public Rect getSurfaceFrame() {
794 return mSurfaceFrame;
795 }
796 };
797}