blob: 9008521e3b1dc05e03d6ac96bd6036c9e73d6d46 [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
Jesse Hallc9f345f2012-09-26 11:55:16 -070049 * surface to be displayed. The view hierarchy will take care of correctly
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070050 * compositing with the Surface any siblings of the SurfaceView that would
Jesse Hallc9f345f2012-09-26 11:55:16 -070051 * normally appear on top of it. This can be used to place overlays such as
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070052 * 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 *
Jesse Hallc9f345f2012-09-26 11:55:16 -070056 * <p> The transparent region that makes the surface visible is based on the
57 * layout positions in the view hierarchy. If the post-layout transform
58 * properties are used to draw a sibling view on top of the SurfaceView, the
59 * view may not be properly composited with the surface.
60 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070061 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
62 * which can be retrieved by calling {@link #getHolder}.
63 *
64 * <p>The Surface will be created for you while the SurfaceView's window is
65 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
66 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
67 * Surface is created and destroyed as the window is shown and hidden.
68 *
69 * <p>One of the purposes of this class is to provide a surface in which a
Jesse Hallc9f345f2012-09-26 11:55:16 -070070 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070071 * this way, you need to be aware of some threading semantics:
72 *
73 * <ul>
74 * <li> All SurfaceView and
75 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
76 * from the thread running the SurfaceView's window (typically the main thread
Jesse Hallc9f345f2012-09-26 11:55:16 -070077 * of the application). They thus need to correctly synchronize with any
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070078 * state that is also touched by the drawing thread.
79 * <li> You must ensure that the drawing thread only touches the underlying
80 * Surface while it is valid -- between
81 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
82 * and
83 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
84 * </ul>
85 */
86public class SurfaceView extends View {
87 static private final String TAG = "SurfaceView";
88 static private final boolean DEBUG = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070089
90 final ArrayList<SurfaceHolder.Callback> mCallbacks
91 = new ArrayList<SurfaceHolder.Callback>();
92
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080093 final int[] mLocation = new int[2];
94
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070095 final ReentrantLock mSurfaceLock = new ReentrantLock();
Dianne Hackborn61566cc2011-12-02 23:31:52 -080096 final Surface mSurface = new Surface(); // Current surface in use
97 final Surface mNewSurface = new Surface(); // New surface we are switching to
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070098 boolean mDrawingStopped = true;
99
100 final WindowManager.LayoutParams mLayout
101 = new WindowManager.LayoutParams();
102 IWindowSession mSession;
103 MyWindow mWindow;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800104 final Rect mVisibleInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700105 final Rect mWinFrame = new Rect();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800106 final Rect mContentInsets = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700107 final Configuration mConfiguration = new Configuration();
108
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700109 static final int KEEP_SCREEN_ON_MSG = 1;
110 static final int GET_NEW_SURFACE_MSG = 2;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700111 static final int UPDATE_WINDOW_MSG = 3;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700112
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700113 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
114
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700115 boolean mIsCreating = false;
116
117 final Handler mHandler = new Handler() {
118 @Override
119 public void handleMessage(Message msg) {
120 switch (msg.what) {
121 case KEEP_SCREEN_ON_MSG: {
122 setKeepScreenOn(msg.arg1 != 0);
123 } break;
124 case GET_NEW_SURFACE_MSG: {
125 handleGetNewSurface();
126 } break;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700127 case UPDATE_WINDOW_MSG: {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700128 updateWindow(false, false);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700129 } break;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700130 }
131 }
132 };
133
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700134 final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
135 = new ViewTreeObserver.OnScrollChangedListener() {
136 public void onScrollChanged() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700137 updateWindow(false, false);
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700138 }
139 };
140
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700141 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700142 boolean mWindowVisibility = false;
143 boolean mViewVisibility = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700144 int mRequestedWidth = -1;
145 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700146 /* Set SurfaceView's format to 565 by default to maintain backward
147 * compatibility with applications assuming this format.
148 */
149 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700150
151 boolean mHaveFrame = false;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800152 boolean mSurfaceCreated = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700153 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;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700161 final Rect mSurfaceFrame = new Rect();
Jeff Brown30bc34f2011-01-25 12:56:56 -0800162 Rect mTmpDirty;
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;
Romain Guyf2499fa2011-01-26 18:31:23 -0800167
168 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
169 new ViewTreeObserver.OnPreDrawListener() {
170 @Override
171 public boolean onPreDraw() {
172 // reposition ourselves where the surface is
Romain Guy0c756222011-01-26 18:45:28 -0800173 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Romain Guyf2499fa2011-01-26 18:31:23 -0800174 updateWindow(false, false);
175 return true;
176 }
177 };
Romain Guy01d5edc2011-01-28 11:28:53 -0800178 private boolean mGlobalListenersAdded;
Romain Guyf2499fa2011-01-26 18:31:23 -0800179
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700180 public SurfaceView(Context context) {
181 super(context);
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) {
186 super(context, attrs);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700187 init();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700188 }
189
190 public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
191 super(context, attrs, defStyle);
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700192 init();
193 }
194
195 private void init() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700196 setWillNotDraw(true);
197 }
198
199 /**
200 * Return the SurfaceHolder providing access and control over this
201 * SurfaceView's underlying surface.
202 *
203 * @return SurfaceHolder The holder of the surface.
204 */
205 public SurfaceHolder getHolder() {
206 return mSurfaceHolder;
207 }
208
209 @Override
210 protected void onAttachedToWindow() {
211 super.onAttachedToWindow();
212 mParent.requestTransparentRegion(this);
213 mSession = getWindowSession();
214 mLayout.token = getWindowToken();
215 mLayout.setTitle("SurfaceView");
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700216 mViewVisibility = getVisibility() == VISIBLE;
Romain Guy01d5edc2011-01-28 11:28:53 -0800217
218 if (!mGlobalListenersAdded) {
219 ViewTreeObserver observer = getViewTreeObserver();
220 observer.addOnScrollChangedListener(mScrollChangedListener);
221 observer.addOnPreDrawListener(mDrawListener);
222 mGlobalListenersAdded = true;
223 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700224 }
225
226 @Override
227 protected void onWindowVisibilityChanged(int visibility) {
228 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700229 mWindowVisibility = visibility == VISIBLE;
230 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700231 updateWindow(false, false);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700232 }
233
234 @Override
235 public void setVisibility(int visibility) {
236 super.setVisibility(visibility);
237 mViewVisibility = visibility == VISIBLE;
Mathias Agopiancbeb3322012-05-12 19:57:07 -0700238 boolean newRequestedVisible = mWindowVisibility && mViewVisibility;
239 if (newRequestedVisible != mRequestedVisible) {
240 // our base class (View) invalidates the layout only when
241 // we go from/to the GONE state. However, SurfaceView needs
242 // to request a re-layout when the visibility changes at all.
243 // This is needed because the transparent region is computed
244 // as part of the layout phase, and it changes (obviously) when
245 // the visibility changes.
246 requestLayout();
247 }
248 mRequestedVisible = newRequestedVisible;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700249 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700250 }
Romain Guyafc3e112010-06-07 17:04:33 -0700251
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700252 @Override
253 protected void onDetachedFromWindow() {
Romain Guy01d5edc2011-01-28 11:28:53 -0800254 if (mGlobalListenersAdded) {
255 ViewTreeObserver observer = getViewTreeObserver();
256 observer.removeOnScrollChangedListener(mScrollChangedListener);
257 observer.removeOnPreDrawListener(mDrawListener);
258 mGlobalListenersAdded = false;
259 }
260
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700261 mRequestedVisible = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700262 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700263 mHaveFrame = false;
264 if (mWindow != null) {
265 try {
266 mSession.remove(mWindow);
267 } catch (RemoteException ex) {
Romain Guy01d5edc2011-01-28 11:28:53 -0800268 // Not much we can do here...
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700269 }
270 mWindow = null;
271 }
272 mSession = null;
273 mLayout.token = null;
274
275 super.onDetachedFromWindow();
276 }
277
278 @Override
279 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800280 int width = mRequestedWidth >= 0
281 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
282 : getDefaultSize(0, widthMeasureSpec);
283 int height = mRequestedHeight >= 0
284 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
285 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700286 setMeasuredDimension(width, height);
287 }
288
Mathias Agopianef115302010-10-04 20:15:08 -0700289 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700290 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700291 protected boolean setFrame(int left, int top, int right, int bottom) {
292 boolean result = super.setFrame(left, top, right, bottom);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700293 updateWindow(false, false);
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700294 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700295 }
296
297 @Override
298 public boolean gatherTransparentRegion(Region region) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700299 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
300 return super.gatherTransparentRegion(region);
301 }
302
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700303 boolean opaque = true;
Dianne Hackborn4702a852012-08-17 15:18:29 -0700304 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700305 // this view draws, remove it from the transparent region
306 opaque = super.gatherTransparentRegion(region);
307 } else if (region != null) {
308 int w = getWidth();
309 int h = getHeight();
310 if (w>0 && h>0) {
311 getLocationInWindow(mLocation);
312 // otherwise, punch a hole in the whole hierarchy
313 int l = mLocation[0];
314 int t = mLocation[1];
315 region.op(l, t, l+w, t+h, Region.Op.UNION);
316 }
317 }
318 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
319 opaque = false;
320 }
321 return opaque;
322 }
323
324 @Override
325 public void draw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700326 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
327 // draw() is not called when SKIP_DRAW is set
Dianne Hackborn4702a852012-08-17 15:18:29 -0700328 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700329 // punch a whole in the view-hierarchy below us
330 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
331 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700332 }
333 super.draw(canvas);
334 }
335
336 @Override
337 protected void dispatchDraw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700338 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
339 // if SKIP_DRAW is cleared, draw() has already punched a hole
Dianne Hackborn4702a852012-08-17 15:18:29 -0700340 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700341 // punch a whole in the view-hierarchy below us
342 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
343 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700344 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700345 super.dispatchDraw(canvas);
346 }
347
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700348 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700349 * Control whether the surface view's surface is placed on top of another
350 * regular surface view in the window (but still behind the window itself).
351 * This is typically used to place overlays on top of an underlying media
352 * surface view.
353 *
354 * <p>Note that this must be set before the surface view's containing
355 * window is attached to the window manager.
356 *
357 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
358 */
359 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
360 mWindowType = isMediaOverlay
361 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
362 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
363 }
364
365 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700366 * Control whether the surface view's surface is placed on top of its
367 * window. Normally it is placed behind the window, to allow it to
368 * (for the most part) appear to composite with the views in the
369 * hierarchy. By setting this, you cause it to be placed above the
370 * window. This means that none of the contents of the window this
371 * SurfaceView is in will be visible on top of its surface.
372 *
373 * <p>Note that this must be set before the surface view's containing
374 * window is attached to the window manager.
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700375 *
376 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700377 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700378 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500379 if (onTop) {
380 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
381 // ensures the surface is placed below the IME
382 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
383 } else {
384 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
385 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
386 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700387 }
Jeff Brownf0681b32012-10-23 17:35:57 -0700388
389 /**
390 * Control whether the surface view's content should be treated as secure,
391 * preventing it from appearing in screenshots or from being viewed on
392 * non-secure displays.
393 *
394 * <p>Note that this must be set before the surface view's containing
395 * window is attached to the window manager.
396 *
397 * <p>See {@link android.view.Display#FLAG_SECURE} for details.
398 *
399 * @param isSecure True if the surface view is secure.
400 */
401 public void setSecure(boolean isSecure) {
402 if (isSecure) {
403 mLayout.flags |= WindowManager.LayoutParams.FLAG_SECURE;
404 } else {
405 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
406 }
407 }
408
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700409 /**
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700410 * Hack to allow special layering of windows. The type is one of the
411 * types in WindowManager.LayoutParams. This is a hack so:
412 * @hide
413 */
414 public void setWindowType(int type) {
415 mWindowType = type;
416 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700417
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700418 private void updateWindow(boolean force, boolean redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700419 if (!mHaveFrame) {
420 return;
421 }
Jeff Browna175a5b2012-02-15 19:18:31 -0800422 ViewRootImpl viewRoot = getViewRootImpl();
Joe Onorato168173a2009-08-12 21:40:29 -0700423 if (viewRoot != null) {
424 mTranslator = viewRoot.mTranslator;
425 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700426
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700427 if (mTranslator != null) {
428 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700429 }
430
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700431 int myWidth = mRequestedWidth;
432 if (myWidth <= 0) myWidth = getWidth();
433 int myHeight = mRequestedHeight;
434 if (myHeight <= 0) myHeight = getHeight();
Mitsuru Oshima001a6e522009-05-11 21:14:03 -0700435
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700436 getLocationInWindow(mLocation);
437 final boolean creating = mWindow == null;
438 final boolean formatChanged = mFormat != mRequestedFormat;
439 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800440 final boolean visibleChanged = mVisible != mRequestedVisible;
Mathias Agopiand2112302010-12-07 19:38:17 -0800441
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700442 if (force || creating || formatChanged || sizeChanged || visibleChanged
Mathias Agopiand2112302010-12-07 19:38:17 -0800443 || mLeft != mLocation[0] || mTop != mLocation[1]
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700444 || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700445
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800446 if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700447 + " format=" + formatChanged + " size=" + sizeChanged
448 + " visible=" + visibleChanged
449 + " left=" + (mLeft != mLocation[0])
450 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700451
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700452 try {
453 final boolean visible = mVisible = mRequestedVisible;
454 mLeft = mLocation[0];
455 mTop = mLocation[1];
456 mWidth = myWidth;
457 mHeight = myHeight;
458 mFormat = mRequestedFormat;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700459
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700460 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
461
462 // Places the window relative
463 mLayout.x = mLeft;
464 mLayout.y = mTop;
465 mLayout.width = getWidth();
466 mLayout.height = getHeight();
467 if (mTranslator != null) {
468 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
469 }
470
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700471 mLayout.format = mRequestedFormat;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700472 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
473 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
474 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700475 | WindowManager.LayoutParams.FLAG_SCALED
476 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
477 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
478 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700479 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
480 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
481 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700482
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700483 if (mWindow == null) {
Jeff Brown8d0243a2012-09-24 15:01:47 -0700484 Display display = getDisplay();
Jon Larimer9bdf5762009-01-02 18:55:15 -0500485 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700486 mLayout.type = mWindowType;
Fabrice Di Meglioaac0d4e2012-07-19 19:21:26 -0700487 mLayout.gravity = Gravity.START|Gravity.TOP;
Craig Mautner6881a102012-07-27 13:04:51 -0700488 mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
Jeff Brown8d0243a2012-09-24 15:01:47 -0700489 mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700490 }
491
Dianne Hackborn726426e2010-03-31 22:04:36 -0700492 boolean realSizeChanged;
493 boolean reportDrawNeeded;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800494
495 int relayoutResult;
496
Dianne Hackborn726426e2010-03-31 22:04:36 -0700497 mSurfaceLock.lock();
498 try {
499 mUpdateWindowNeeded = false;
500 reportDrawNeeded = mReportDrawNeeded;
501 mReportDrawNeeded = false;
502 mDrawingStopped = !visible;
503
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800504 if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
505
506 relayoutResult = mSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700507 mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800508 visible ? VISIBLE : GONE,
Jeff Brown98365d72012-08-19 20:30:52 -0700509 WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
Dianne Hackborn85afd1b2012-05-13 13:31:06 -0700510 mWinFrame, mContentInsets,
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800511 mVisibleInsets, mConfiguration, mNewSurface);
Jeff Brown98365d72012-08-19 20:30:52 -0700512 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700513 mReportDrawNeeded = true;
514 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800515
516 if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
Dianne Hackborn726426e2010-03-31 22:04:36 -0700517 + ", vis=" + visible + ", frame=" + mWinFrame);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800518
Dianne Hackborn726426e2010-03-31 22:04:36 -0700519 mSurfaceFrame.left = 0;
520 mSurfaceFrame.top = 0;
521 if (mTranslator == null) {
522 mSurfaceFrame.right = mWinFrame.width();
523 mSurfaceFrame.bottom = mWinFrame.height();
524 } else {
525 float appInvertedScale = mTranslator.applicationInvertedScale;
526 mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
527 mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
528 }
529
530 final int surfaceWidth = mSurfaceFrame.right;
531 final int surfaceHeight = mSurfaceFrame.bottom;
532 realSizeChanged = mLastSurfaceWidth != surfaceWidth
533 || mLastSurfaceHeight != surfaceHeight;
534 mLastSurfaceWidth = surfaceWidth;
535 mLastSurfaceHeight = surfaceHeight;
536 } finally {
537 mSurfaceLock.unlock();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700538 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700539
540 try {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700541 redrawNeeded |= creating | reportDrawNeeded;
542
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800543 SurfaceHolder.Callback callbacks[] = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700544
Jeff Brown98365d72012-08-19 20:30:52 -0700545 final boolean surfaceChanged = (relayoutResult
546 & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800547 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
548 mSurfaceCreated = false;
549 if (mSurface.isValid()) {
550 if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
551 callbacks = getSurfaceCallbacks();
552 for (SurfaceHolder.Callback c : callbacks) {
553 c.surfaceDestroyed(mSurfaceHolder);
554 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700555 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800556 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700557
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800558 mSurface.transferFrom(mNewSurface);
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800559
Andreas Röhlf750b8c2012-07-02 13:06:26 +0200560 if (visible && mSurface.isValid()) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800561 if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
562 mSurfaceCreated = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700563 mIsCreating = true;
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800564 if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
565 if (callbacks == null) {
566 callbacks = getSurfaceCallbacks();
567 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700568 for (SurfaceHolder.Callback c : callbacks) {
569 c.surfaceCreated(mSurfaceHolder);
570 }
571 }
572 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700573 || visibleChanged || realSizeChanged) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800574 if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
575 + " w=" + myWidth + " h=" + myHeight);
576 if (callbacks == null) {
577 callbacks = getSurfaceCallbacks();
578 }
Dianne Hackborn251fd432010-07-14 16:56:31 -0700579 for (SurfaceHolder.Callback c : callbacks) {
580 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
581 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700582 }
583 if (redrawNeeded) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800584 if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
585 if (callbacks == null) {
586 callbacks = getSurfaceCallbacks();
587 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700588 for (SurfaceHolder.Callback c : callbacks) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700589 if (c instanceof SurfaceHolder.Callback2) {
590 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
591 mSurfaceHolder);
592 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700593 }
594 }
595 }
596 } finally {
597 mIsCreating = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700598 if (redrawNeeded) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800599 if (DEBUG) Log.i(TAG, "finishedDrawing");
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700600 mSession.finishDrawing(mWindow);
601 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800602 mSession.performDeferredDestroy(mWindow);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700603 }
604 } catch (RemoteException ex) {
605 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800606 if (DEBUG) Log.v(
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700607 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
608 " w=" + mLayout.width + " h=" + mLayout.height +
609 ", frame=" + mSurfaceFrame);
610 }
611 }
612
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800613 private SurfaceHolder.Callback[] getSurfaceCallbacks() {
614 SurfaceHolder.Callback callbacks[];
615 synchronized (mCallbacks) {
616 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
617 mCallbacks.toArray(callbacks);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700618 }
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800619 return callbacks;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700620 }
621
622 void handleGetNewSurface() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700623 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700624 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800625
Derek Sollenberger7179b812010-03-22 13:41:20 -0400626 /**
627 * Check to see if the surface has fixed size dimensions or if the surface's
628 * dimensions are dimensions are dependent on its current layout.
629 *
630 * @return true if the surface has dimensions that are fixed in size
631 * @hide
632 */
633 public boolean isFixedSize() {
634 return (mRequestedWidth != -1 || mRequestedHeight != -1);
635 }
636
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700637 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700638 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500639
640 public MyWindow(SurfaceView surfaceView) {
641 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
642 }
643
Craig Mautner656e3af2012-09-06 15:04:22 -0700644 @Override
645 public void resized(Rect frame, Rect contentInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800646 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500647 SurfaceView surfaceView = mSurfaceView.get();
648 if (surfaceView != null) {
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800649 if (DEBUG) Log.v(
Craig Mautner656e3af2012-09-06 15:04:22 -0700650 "SurfaceView", surfaceView + " got resized: w=" + frame.width()
651 + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700652 surfaceView.mSurfaceLock.lock();
653 try {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500654 if (reportDraw) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700655 surfaceView.mUpdateWindowNeeded = true;
656 surfaceView.mReportDrawNeeded = true;
657 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
Craig Mautner656e3af2012-09-06 15:04:22 -0700658 } else if (surfaceView.mWinFrame.width() != frame.width()
659 || surfaceView.mWinFrame.height() != frame.height()) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700660 surfaceView.mUpdateWindowNeeded = true;
661 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700662 }
Dianne Hackborn726426e2010-03-31 22:04:36 -0700663 } finally {
664 surfaceView.mSurfaceLock.unlock();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700665 }
666 }
667 }
668
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700669 public void dispatchAppVisibility(boolean visible) {
670 // The point of SurfaceView is to let the app control the surface.
671 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800672
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700673 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500674 SurfaceView surfaceView = mSurfaceView.get();
675 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800676 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
677 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500678 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700679 }
680
681 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
682 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
683 }
684
685 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
686 }
687
688 int mCurWidth = -1;
689 int mCurHeight = -1;
690 }
691
692 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
693
694 private static final String LOG_TAG = "SurfaceHolder";
695
696 public boolean isCreating() {
697 return mIsCreating;
698 }
699
700 public void addCallback(Callback callback) {
701 synchronized (mCallbacks) {
702 // This is a linear search, but in practice we'll
703 // have only a couple callbacks, so it doesn't matter.
704 if (mCallbacks.contains(callback) == false) {
705 mCallbacks.add(callback);
706 }
707 }
708 }
709
710 public void removeCallback(Callback callback) {
711 synchronized (mCallbacks) {
712 mCallbacks.remove(callback);
713 }
714 }
715
716 public void setFixedSize(int width, int height) {
717 if (mRequestedWidth != width || mRequestedHeight != height) {
718 mRequestedWidth = width;
719 mRequestedHeight = height;
720 requestLayout();
721 }
722 }
723
724 public void setSizeFromLayout() {
725 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
726 mRequestedWidth = mRequestedHeight = -1;
727 requestLayout();
728 }
729 }
730
731 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700732
733 // for backward compatibility reason, OPAQUE always
734 // means 565 for SurfaceView
735 if (format == PixelFormat.OPAQUE)
736 format = PixelFormat.RGB_565;
737
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700738 mRequestedFormat = format;
739 if (mWindow != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700740 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700741 }
742 }
743
Mathias Agopiand2112302010-12-07 19:38:17 -0800744 /**
745 * @deprecated setType is now ignored.
746 */
747 @Deprecated
748 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700749
750 public void setKeepScreenOn(boolean screenOn) {
751 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
752 msg.arg1 = screenOn ? 1 : 0;
753 mHandler.sendMessage(msg);
754 }
755
756 public Canvas lockCanvas() {
757 return internalLockCanvas(null);
758 }
759
760 public Canvas lockCanvas(Rect dirty) {
761 return internalLockCanvas(dirty);
762 }
763
764 private final Canvas internalLockCanvas(Rect dirty) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700765 mSurfaceLock.lock();
766
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800767 if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700768 + mDrawingStopped + ", win=" + mWindow);
769
770 Canvas c = null;
771 if (!mDrawingStopped && mWindow != null) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800772 if (dirty == null) {
773 if (mTmpDirty == null) {
774 mTmpDirty = new Rect();
775 }
776 mTmpDirty.set(mSurfaceFrame);
777 dirty = mTmpDirty;
778 }
779
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700780 try {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800781 c = mSurface.lockCanvas(dirty);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700782 } catch (Exception e) {
783 Log.e(LOG_TAG, "Exception locking surface", e);
784 }
785 }
786
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800787 if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700788 if (c != null) {
789 mLastLockTime = SystemClock.uptimeMillis();
790 return c;
791 }
792
793 // If the Surface is not ready to be drawn, then return null,
794 // but throttle calls to this function so it isn't called more
795 // than every 100ms.
796 long now = SystemClock.uptimeMillis();
797 long nextTime = mLastLockTime + 100;
798 if (nextTime > now) {
799 try {
800 Thread.sleep(nextTime-now);
801 } catch (InterruptedException e) {
802 }
803 now = SystemClock.uptimeMillis();
804 }
805 mLastLockTime = now;
806 mSurfaceLock.unlock();
807
808 return null;
809 }
810
811 public void unlockCanvasAndPost(Canvas canvas) {
812 mSurface.unlockCanvasAndPost(canvas);
813 mSurfaceLock.unlock();
814 }
815
816 public Surface getSurface() {
817 return mSurface;
818 }
819
820 public Rect getSurfaceFrame() {
821 return mSurfaceFrame;
822 }
823 };
824}