blob: 966bd8d47789c2ad78aca3ecc2c0dabb717eaee8 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Romain Guyafc3e112010-06-07 17:04:33 -070019import android.util.DisplayMetrics;
Dianne Hackborn72c82ab2009-08-11 21:13:54 -070020import com.android.internal.view.BaseIWindow;
21
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070022import android.content.Context;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080023import android.content.res.Configuration;
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -070024import android.content.res.Resources;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070025import android.content.res.CompatibilityInfo.Translator;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070026import android.graphics.Canvas;
27import android.graphics.PixelFormat;
28import android.graphics.PorterDuff;
29import android.graphics.Rect;
30import android.graphics.Region;
31import android.os.Handler;
32import android.os.Message;
33import android.os.RemoteException;
34import android.os.SystemClock;
35import android.os.ParcelFileDescriptor;
36import android.util.AttributeSet;
37import android.util.Config;
38import android.util.Log;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070039
Jon Larimer9bdf5762009-01-02 18:55:15 -050040import java.lang.ref.WeakReference;
41import java.util.ArrayList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070042import java.util.concurrent.locks.ReentrantLock;
43
44/**
45 * Provides a dedicated drawing surface embedded inside of a view hierarchy.
46 * You can control the format of this surface and, if you like, its size; the
47 * SurfaceView takes care of placing the surface at the correct location on the
48 * screen
49 *
50 * <p>The surface is Z ordered so that it is behind the window holding its
51 * SurfaceView; the SurfaceView punches a hole in its window to allow its
52 * surface to be displayed. The view hierarchy will take care of correctly
53 * compositing with the Surface any siblings of the SurfaceView that would
54 * normally appear on top of it. This can be used to place overlays such as
55 * buttons on top of the Surface, though note however that it can have an
56 * impact on performance since a full alpha-blended composite will be performed
57 * each time the Surface changes.
58 *
59 * <p>Access to the underlying surface is provided via the SurfaceHolder interface,
60 * which can be retrieved by calling {@link #getHolder}.
61 *
62 * <p>The Surface will be created for you while the SurfaceView's window is
63 * visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
64 * and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
65 * Surface is created and destroyed as the window is shown and hidden.
66 *
67 * <p>One of the purposes of this class is to provide a surface in which a
Glenn Kasten334031c2010-11-09 21:54:38 -080068 * secondary thread can render into the screen. If you are going to use it
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070069 * this way, you need to be aware of some threading semantics:
70 *
71 * <ul>
72 * <li> All SurfaceView and
73 * {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
74 * from the thread running the SurfaceView's window (typically the main thread
75 * of the application). They thus need to correctly synchronize with any
76 * state that is also touched by the drawing thread.
77 * <li> You must ensure that the drawing thread only touches the underlying
78 * Surface while it is valid -- between
79 * {@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
80 * and
81 * {@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
82 * </ul>
83 */
84public class SurfaceView extends View {
85 static private final String TAG = "SurfaceView";
86 static private final boolean DEBUG = false;
87 static private final boolean localLOGV = DEBUG ? true : Config.LOGV;
88
89 final ArrayList<SurfaceHolder.Callback> mCallbacks
90 = new ArrayList<SurfaceHolder.Callback>();
91
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080092 final int[] mLocation = new int[2];
93
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070094 final ReentrantLock mSurfaceLock = new ReentrantLock();
95 final Surface mSurface = new Surface();
96 boolean mDrawingStopped = true;
97
98 final WindowManager.LayoutParams mLayout
99 = new WindowManager.LayoutParams();
100 IWindowSession mSession;
101 MyWindow mWindow;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800102 final Rect mVisibleInsets = new Rect();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700103 final Rect mWinFrame = new Rect();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800104 final Rect mContentInsets = new Rect();
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700105 final Configuration mConfiguration = new Configuration();
106
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700107 static final int KEEP_SCREEN_ON_MSG = 1;
108 static final int GET_NEW_SURFACE_MSG = 2;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700109 static final int UPDATE_WINDOW_MSG = 3;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700110
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700111 int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
112
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700113 boolean mIsCreating = false;
114
115 final Handler mHandler = new Handler() {
116 @Override
117 public void handleMessage(Message msg) {
118 switch (msg.what) {
119 case KEEP_SCREEN_ON_MSG: {
120 setKeepScreenOn(msg.arg1 != 0);
121 } break;
122 case GET_NEW_SURFACE_MSG: {
123 handleGetNewSurface();
124 } break;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700125 case UPDATE_WINDOW_MSG: {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700126 updateWindow(false, false);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700127 } break;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700128 }
129 }
130 };
131
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700132 final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
133 = new ViewTreeObserver.OnScrollChangedListener() {
134 public void onScrollChanged() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700135 updateWindow(false, false);
Dianne Hackborne2af5c82010-03-18 15:44:34 -0700136 }
137 };
138
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700139 boolean mRequestedVisible = false;
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700140 boolean mWindowVisibility = false;
141 boolean mViewVisibility = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700142 int mRequestedWidth = -1;
143 int mRequestedHeight = -1;
Mathias Agopiand6ddcb72010-05-24 19:00:08 -0700144 /* Set SurfaceView's format to 565 by default to maintain backward
145 * compatibility with applications assuming this format.
146 */
147 int mRequestedFormat = PixelFormat.RGB_565;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700148
149 boolean mHaveFrame = false;
150 boolean mDestroyReportNeeded = false;
151 boolean mNewSurfaceNeeded = false;
152 long mLastLockTime = 0;
153
154 boolean mVisible = false;
155 int mLeft = -1;
156 int mTop = -1;
157 int mWidth = -1;
158 int mHeight = -1;
159 int mFormat = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700160 final Rect mSurfaceFrame = new Rect();
Jeff Brown30bc34f2011-01-25 12:56:56 -0800161 Rect mTmpDirty;
Dianne Hackborn726426e2010-03-31 22:04:36 -0700162 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
163 boolean mUpdateWindowNeeded;
164 boolean mReportDrawNeeded;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700165 private Translator mTranslator;
Romain Guyf2499fa2011-01-26 18:31:23 -0800166
167 private final ViewTreeObserver.OnPreDrawListener mDrawListener =
168 new ViewTreeObserver.OnPreDrawListener() {
169 @Override
170 public boolean onPreDraw() {
171 // reposition ourselves where the surface is
Romain Guy0c756222011-01-26 18:45:28 -0800172 mHaveFrame = getWidth() > 0 && getHeight() > 0;
Romain Guyf2499fa2011-01-26 18:31:23 -0800173 updateWindow(false, false);
174 return true;
175 }
176 };
177
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 Guyf2499fa2011-01-26 18:31:23 -0800215 ViewTreeObserver observer = getViewTreeObserver();
216 observer.addOnScrollChangedListener(mScrollChangedListener);
217 observer.addOnPreDrawListener(mDrawListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700218 }
219
220 @Override
221 protected void onWindowVisibilityChanged(int visibility) {
222 super.onWindowVisibilityChanged(visibility);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700223 mWindowVisibility = visibility == VISIBLE;
224 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700225 updateWindow(false, false);
Mathias Agopian6b7f1a62009-09-09 18:32:34 -0700226 }
227
228 @Override
229 public void setVisibility(int visibility) {
230 super.setVisibility(visibility);
231 mViewVisibility = visibility == VISIBLE;
232 mRequestedVisible = mWindowVisibility && mViewVisibility;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700233 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700234 }
Romain Guyafc3e112010-06-07 17:04:33 -0700235
236 /**
237 * This method is not intended for general use. It was created
238 * temporarily to improve performance of 3D layers in Launcher
239 * and should be removed and fixed properly.
240 *
241 * Do not call this method. Ever.
242 *
243 * @hide
244 */
245 protected void showSurface() {
246 if (mSession != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700247 updateWindow(true, false);
Romain Guyafc3e112010-06-07 17:04:33 -0700248 }
249 }
250
251 /**
252 * This method is not intended for general use. It was created
253 * temporarily to improve performance of 3D layers in Launcher
254 * and should be removed and fixed properly.
255 *
256 * Do not call this method. Ever.
257 *
258 * @hide
259 */
260 protected void hideSurface() {
261 if (mSession != null && mWindow != null) {
262 mSurfaceLock.lock();
263 try {
264 DisplayMetrics metrics = getResources().getDisplayMetrics();
265 mLayout.x = metrics.widthPixels * 3;
266 mSession.relayout(mWindow, mLayout, mWidth, mHeight, VISIBLE, false,
267 mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurface);
268 } catch (RemoteException e) {
269 // Ignore
270 } finally {
271 mSurfaceLock.unlock();
272 }
273 }
274 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700275
276 @Override
277 protected void onDetachedFromWindow() {
Romain Guyf2499fa2011-01-26 18:31:23 -0800278 ViewTreeObserver observer = getViewTreeObserver();
279 observer.removeOnScrollChangedListener(mScrollChangedListener);
280 observer.removeOnPreDrawListener(mDrawListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700281 mRequestedVisible = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700282 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700283 mHaveFrame = false;
284 if (mWindow != null) {
285 try {
286 mSession.remove(mWindow);
287 } catch (RemoteException ex) {
288 }
289 mWindow = null;
290 }
291 mSession = null;
292 mLayout.token = null;
293
294 super.onDetachedFromWindow();
295 }
296
297 @Override
298 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800299 int width = mRequestedWidth >= 0
300 ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
301 : getDefaultSize(0, widthMeasureSpec);
302 int height = mRequestedHeight >= 0
303 ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
304 : getDefaultSize(0, heightMeasureSpec);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700305 setMeasuredDimension(width, height);
306 }
307
Mathias Agopianef115302010-10-04 20:15:08 -0700308 /** @hide */
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700309 @Override
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700310 protected boolean setFrame(int left, int top, int right, int bottom) {
311 boolean result = super.setFrame(left, top, right, bottom);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700312 updateWindow(false, false);
Mathias Agopian995bb9d2010-10-04 17:13:15 -0700313 return result;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700314 }
315
316 @Override
317 public boolean gatherTransparentRegion(Region region) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700318 if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
319 return super.gatherTransparentRegion(region);
320 }
321
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700322 boolean opaque = true;
323 if ((mPrivateFlags & SKIP_DRAW) == 0) {
324 // this view draws, remove it from the transparent region
325 opaque = super.gatherTransparentRegion(region);
326 } else if (region != null) {
327 int w = getWidth();
328 int h = getHeight();
329 if (w>0 && h>0) {
330 getLocationInWindow(mLocation);
331 // otherwise, punch a hole in the whole hierarchy
332 int l = mLocation[0];
333 int t = mLocation[1];
334 region.op(l, t, l+w, t+h, Region.Op.UNION);
335 }
336 }
337 if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
338 opaque = false;
339 }
340 return opaque;
341 }
342
343 @Override
344 public void draw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700345 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
346 // draw() is not called when SKIP_DRAW is set
347 if ((mPrivateFlags & SKIP_DRAW) == 0) {
348 // punch a whole in the view-hierarchy below us
349 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
350 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700351 }
352 super.draw(canvas);
353 }
354
355 @Override
356 protected void dispatchDraw(Canvas canvas) {
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700357 if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
358 // if SKIP_DRAW is cleared, draw() has already punched a hole
359 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
360 // punch a whole in the view-hierarchy below us
361 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
362 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700363 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700364 super.dispatchDraw(canvas);
365 }
366
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700367 /**
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700368 * Control whether the surface view's surface is placed on top of another
369 * regular surface view in the window (but still behind the window itself).
370 * This is typically used to place overlays on top of an underlying media
371 * surface view.
372 *
373 * <p>Note that this must be set before the surface view's containing
374 * window is attached to the window manager.
375 *
376 * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
377 */
378 public void setZOrderMediaOverlay(boolean isMediaOverlay) {
379 mWindowType = isMediaOverlay
380 ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
381 : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
382 }
383
384 /**
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700385 * Control whether the surface view's surface is placed on top of its
386 * window. Normally it is placed behind the window, to allow it to
387 * (for the most part) appear to composite with the views in the
388 * hierarchy. By setting this, you cause it to be placed above the
389 * window. This means that none of the contents of the window this
390 * SurfaceView is in will be visible on top of its surface.
391 *
392 * <p>Note that this must be set before the surface view's containing
393 * window is attached to the window manager.
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700394 *
395 * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700396 */
Dianne Hackborn29e4a3c2009-09-30 22:35:40 -0700397 public void setZOrderOnTop(boolean onTop) {
Derek Sollenbergerecde72f2010-03-01 13:44:42 -0500398 if (onTop) {
399 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
400 // ensures the surface is placed below the IME
401 mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
402 } else {
403 mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
404 mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
405 }
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700406 }
407
408 /**
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700409 * Hack to allow special layering of windows. The type is one of the
410 * types in WindowManager.LayoutParams. This is a hack so:
411 * @hide
412 */
413 public void setWindowType(int type) {
414 mWindowType = type;
415 }
Mitsuru Oshima34bf2ee2009-07-17 09:57:28 -0700416
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700417 private void updateWindow(boolean force, boolean redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700418 if (!mHaveFrame) {
419 return;
420 }
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700421 ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
Joe Onorato168173a2009-08-12 21:40:29 -0700422 if (viewRoot != null) {
423 mTranslator = viewRoot.mTranslator;
424 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700425
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700426 Resources res = getContext().getResources();
427 if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700428 mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), 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;
440 final boolean visibleChanged = mVisible != mRequestedVisible
441 || mNewSurfaceNeeded;
Mathias Agopiand2112302010-12-07 19:38:17 -0800442
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700443 if (force || creating || formatChanged || sizeChanged || visibleChanged
Mathias Agopiand2112302010-12-07 19:38:17 -0800444 || mLeft != mLocation[0] || mTop != mLocation[1]
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700445 || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700446
447 if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
448 + " format=" + formatChanged + " size=" + sizeChanged
449 + " visible=" + visibleChanged
450 + " left=" + (mLeft != mLocation[0])
451 + " top=" + (mTop != mLocation[1]));
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700452
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700453 try {
454 final boolean visible = mVisible = mRequestedVisible;
455 mLeft = mLocation[0];
456 mTop = mLocation[1];
457 mWidth = myWidth;
458 mHeight = myHeight;
459 mFormat = mRequestedFormat;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700460
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700461 // Scaling/Translate window's layout here because mLayout is not used elsewhere.
462
463 // Places the window relative
464 mLayout.x = mLeft;
465 mLayout.y = mTop;
466 mLayout.width = getWidth();
467 mLayout.height = getHeight();
468 if (mTranslator != null) {
469 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
470 }
471
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700472 mLayout.format = mRequestedFormat;
Dianne Hackborn1cd403e2009-09-14 22:29:14 -0700473 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
474 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
475 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700476 | WindowManager.LayoutParams.FLAG_SCALED
477 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
478 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
479 ;
Mitsuru Oshima841f13c2009-07-17 17:23:31 -0700480 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
481 mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
482 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700483
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700484 if (mWindow == null) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500485 mWindow = new MyWindow(this);
Dianne Hackbornc4d5d022009-05-21 17:32:42 -0700486 mLayout.type = mWindowType;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700487 mLayout.gravity = Gravity.LEFT|Gravity.TOP;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700488 mSession.addWithoutInputChannel(mWindow, mLayout,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800489 mVisible ? VISIBLE : GONE, mContentInsets);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700490 }
491
492 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
493 reportSurfaceDestroyed();
494 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700495
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700496 mNewSurfaceNeeded = false;
497
Dianne Hackborn726426e2010-03-31 22:04:36 -0700498 boolean realSizeChanged;
499 boolean reportDrawNeeded;
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700500
Dianne Hackborn726426e2010-03-31 22:04:36 -0700501 mSurfaceLock.lock();
502 try {
503 mUpdateWindowNeeded = false;
504 reportDrawNeeded = mReportDrawNeeded;
505 mReportDrawNeeded = false;
506 mDrawingStopped = !visible;
507
508 final int relayoutResult = mSession.relayout(
509 mWindow, mLayout, mWidth, mHeight,
510 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
511 mVisibleInsets, mConfiguration, mSurface);
512 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
513 mReportDrawNeeded = true;
514 }
515
516 if (localLOGV) Log.i(TAG, "New surface: " + mSurface
517 + ", vis=" + visible + ", frame=" + mWinFrame);
518
519 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
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700543 if (visible) {
544 mDestroyReportNeeded = true;
545
546 SurfaceHolder.Callback callbacks[];
547 synchronized (mCallbacks) {
548 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
549 mCallbacks.toArray(callbacks);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700550 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700551
552 if (visibleChanged) {
553 mIsCreating = true;
554 for (SurfaceHolder.Callback c : callbacks) {
555 c.surfaceCreated(mSurfaceHolder);
556 }
557 }
558 if (creating || formatChanged || sizeChanged
Dianne Hackborn726426e2010-03-31 22:04:36 -0700559 || visibleChanged || realSizeChanged) {
Dianne Hackborn251fd432010-07-14 16:56:31 -0700560 for (SurfaceHolder.Callback c : callbacks) {
561 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
562 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700563 }
564 if (redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700565 for (SurfaceHolder.Callback c : callbacks) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700566 if (c instanceof SurfaceHolder.Callback2) {
567 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
568 mSurfaceHolder);
569 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700570 }
571 }
Mathias Agopianf5e32f32010-03-23 16:44:27 -0700572 } else {
573 mSurface.release();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700574 }
575 } finally {
576 mIsCreating = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700577 if (redrawNeeded) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700578 mSession.finishDrawing(mWindow);
579 }
580 }
581 } catch (RemoteException ex) {
582 }
583 if (localLOGV) Log.v(
584 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
585 " w=" + mLayout.width + " h=" + mLayout.height +
586 ", frame=" + mSurfaceFrame);
587 }
588 }
589
590 private void reportSurfaceDestroyed() {
591 if (mDestroyReportNeeded) {
592 mDestroyReportNeeded = false;
593 SurfaceHolder.Callback callbacks[];
594 synchronized (mCallbacks) {
595 callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
596 mCallbacks.toArray(callbacks);
597 }
598 for (SurfaceHolder.Callback c : callbacks) {
599 c.surfaceDestroyed(mSurfaceHolder);
600 }
601 }
602 super.onDetachedFromWindow();
603 }
604
605 void handleGetNewSurface() {
606 mNewSurfaceNeeded = true;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700607 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700608 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800609
Derek Sollenberger7179b812010-03-22 13:41:20 -0400610 /**
611 * Check to see if the surface has fixed size dimensions or if the surface's
612 * dimensions are dimensions are dependent on its current layout.
613 *
614 * @return true if the surface has dimensions that are fixed in size
615 * @hide
616 */
617 public boolean isFixedSize() {
618 return (mRequestedWidth != -1 || mRequestedHeight != -1);
619 }
620
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700621 private static class MyWindow extends BaseIWindow {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700622 private final WeakReference<SurfaceView> mSurfaceView;
Jon Larimer9bdf5762009-01-02 18:55:15 -0500623
624 public MyWindow(SurfaceView surfaceView) {
625 mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
626 }
627
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800628 public void resized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800629 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500630 SurfaceView surfaceView = mSurfaceView.get();
631 if (surfaceView != null) {
632 if (localLOGV) Log.v(
633 "SurfaceView", surfaceView + " got resized: w=" +
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800634 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
Dianne Hackborn726426e2010-03-31 22:04:36 -0700635 surfaceView.mSurfaceLock.lock();
636 try {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500637 if (reportDraw) {
Dianne Hackborn726426e2010-03-31 22:04:36 -0700638 surfaceView.mUpdateWindowNeeded = true;
639 surfaceView.mReportDrawNeeded = true;
640 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
641 } else if (surfaceView.mWinFrame.width() != w
642 || surfaceView.mWinFrame.height() != h) {
643 surfaceView.mUpdateWindowNeeded = true;
644 surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700645 }
Dianne Hackborn726426e2010-03-31 22:04:36 -0700646 } finally {
647 surfaceView.mSurfaceLock.unlock();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700648 }
649 }
650 }
651
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700652 public void dispatchAppVisibility(boolean visible) {
653 // The point of SurfaceView is to let the app control the surface.
654 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800655
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700656 public void dispatchGetNewSurface() {
Jon Larimer9bdf5762009-01-02 18:55:15 -0500657 SurfaceView surfaceView = mSurfaceView.get();
658 if (surfaceView != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800659 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
660 surfaceView.mHandler.sendMessage(msg);
Jon Larimer9bdf5762009-01-02 18:55:15 -0500661 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700662 }
663
664 public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
665 Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
666 }
667
668 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
669 }
670
671 int mCurWidth = -1;
672 int mCurHeight = -1;
673 }
674
675 private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
676
677 private static final String LOG_TAG = "SurfaceHolder";
678
679 public boolean isCreating() {
680 return mIsCreating;
681 }
682
683 public void addCallback(Callback callback) {
684 synchronized (mCallbacks) {
685 // This is a linear search, but in practice we'll
686 // have only a couple callbacks, so it doesn't matter.
687 if (mCallbacks.contains(callback) == false) {
688 mCallbacks.add(callback);
689 }
690 }
691 }
692
693 public void removeCallback(Callback callback) {
694 synchronized (mCallbacks) {
695 mCallbacks.remove(callback);
696 }
697 }
698
699 public void setFixedSize(int width, int height) {
700 if (mRequestedWidth != width || mRequestedHeight != height) {
701 mRequestedWidth = width;
702 mRequestedHeight = height;
703 requestLayout();
704 }
705 }
706
707 public void setSizeFromLayout() {
708 if (mRequestedWidth != -1 || mRequestedHeight != -1) {
709 mRequestedWidth = mRequestedHeight = -1;
710 requestLayout();
711 }
712 }
713
714 public void setFormat(int format) {
Mathias Agopian2d468c52010-06-14 21:50:48 -0700715
716 // for backward compatibility reason, OPAQUE always
717 // means 565 for SurfaceView
718 if (format == PixelFormat.OPAQUE)
719 format = PixelFormat.RGB_565;
720
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700721 mRequestedFormat = format;
722 if (mWindow != null) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700723 updateWindow(false, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700724 }
725 }
726
Mathias Agopiand2112302010-12-07 19:38:17 -0800727 /**
728 * @deprecated setType is now ignored.
729 */
730 @Deprecated
731 public void setType(int type) { }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700732
733 public void setKeepScreenOn(boolean screenOn) {
734 Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
735 msg.arg1 = screenOn ? 1 : 0;
736 mHandler.sendMessage(msg);
737 }
738
739 public Canvas lockCanvas() {
740 return internalLockCanvas(null);
741 }
742
743 public Canvas lockCanvas(Rect dirty) {
744 return internalLockCanvas(dirty);
745 }
746
747 private final Canvas internalLockCanvas(Rect dirty) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700748 mSurfaceLock.lock();
749
750 if (localLOGV) Log.i(TAG, "Locking canvas... stopped="
751 + mDrawingStopped + ", win=" + mWindow);
752
753 Canvas c = null;
754 if (!mDrawingStopped && mWindow != null) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800755 if (dirty == null) {
756 if (mTmpDirty == null) {
757 mTmpDirty = new Rect();
758 }
759 mTmpDirty.set(mSurfaceFrame);
760 dirty = mTmpDirty;
761 }
762
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700763 try {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800764 c = mSurface.lockCanvas(dirty);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700765 } catch (Exception e) {
766 Log.e(LOG_TAG, "Exception locking surface", e);
767 }
768 }
769
770 if (localLOGV) Log.i(TAG, "Returned canvas: " + c);
771 if (c != null) {
772 mLastLockTime = SystemClock.uptimeMillis();
773 return c;
774 }
775
776 // If the Surface is not ready to be drawn, then return null,
777 // but throttle calls to this function so it isn't called more
778 // than every 100ms.
779 long now = SystemClock.uptimeMillis();
780 long nextTime = mLastLockTime + 100;
781 if (nextTime > now) {
782 try {
783 Thread.sleep(nextTime-now);
784 } catch (InterruptedException e) {
785 }
786 now = SystemClock.uptimeMillis();
787 }
788 mLastLockTime = now;
789 mSurfaceLock.unlock();
790
791 return null;
792 }
793
794 public void unlockCanvasAndPost(Canvas canvas) {
795 mSurface.unlockCanvasAndPost(canvas);
796 mSurfaceLock.unlock();
797 }
798
799 public Surface getSurface() {
800 return mSurface;
801 }
802
803 public Rect getSurfaceFrame() {
804 return mSurfaceFrame;
805 }
806 };
807}