• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.view;
18 
19 import com.android.internal.view.BaseIWindow;
20 
21 import android.content.Context;
22 import android.content.res.Configuration;
23 import android.content.res.CompatibilityInfo.Translator;
24 import android.graphics.Canvas;
25 import android.graphics.PixelFormat;
26 import android.graphics.PorterDuff;
27 import android.graphics.Rect;
28 import android.graphics.Region;
29 import android.os.Handler;
30 import android.os.Message;
31 import android.os.RemoteException;
32 import android.os.SystemClock;
33 import android.os.ParcelFileDescriptor;
34 import android.util.AttributeSet;
35 import android.util.Log;
36 
37 import java.lang.ref.WeakReference;
38 import java.util.ArrayList;
39 import 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
65  * secondary thread can render into the screen.  If you are going to use it
66  * 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  */
81 public class SurfaceView extends View {
82     static private final String TAG = "SurfaceView";
83     static private final boolean DEBUG = false;
84 
85     final ArrayList<SurfaceHolder.Callback> mCallbacks
86             = new ArrayList<SurfaceHolder.Callback>();
87 
88     final int[] mLocation = new int[2];
89 
90     final ReentrantLock mSurfaceLock = new ReentrantLock();
91     final Surface mSurface = new Surface();       // Current surface in use
92     final Surface mNewSurface = new Surface();    // New surface we are switching to
93     boolean mDrawingStopped = true;
94 
95     final WindowManager.LayoutParams mLayout
96             = new WindowManager.LayoutParams();
97     IWindowSession mSession;
98     MyWindow mWindow;
99     final Rect mVisibleInsets = new Rect();
100     final Rect mWinFrame = new Rect();
101     final Rect mContentInsets = new Rect();
102     final Configuration mConfiguration = new Configuration();
103 
104     static final int KEEP_SCREEN_ON_MSG = 1;
105     static final int GET_NEW_SURFACE_MSG = 2;
106     static final int UPDATE_WINDOW_MSG = 3;
107 
108     int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
109 
110     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;
122                 case UPDATE_WINDOW_MSG: {
123                     updateWindow(false, false);
124                 } break;
125             }
126         }
127     };
128 
129     final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
130             = new ViewTreeObserver.OnScrollChangedListener() {
131                     public void onScrollChanged() {
132                         updateWindow(false, false);
133                     }
134             };
135 
136     boolean mRequestedVisible = false;
137     boolean mWindowVisibility = false;
138     boolean mViewVisibility = false;
139     int mRequestedWidth = -1;
140     int mRequestedHeight = -1;
141     /* 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;
145 
146     boolean mHaveFrame = false;
147     boolean mSurfaceCreated = false;
148     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;
156     final Rect mSurfaceFrame = new Rect();
157     Rect mTmpDirty;
158     int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
159     boolean mUpdateWindowNeeded;
160     boolean mReportDrawNeeded;
161     private Translator mTranslator;
162 
163     private final ViewTreeObserver.OnPreDrawListener mDrawListener =
164             new ViewTreeObserver.OnPreDrawListener() {
165                 @Override
166                 public boolean onPreDraw() {
167                     // reposition ourselves where the surface is
168                     mHaveFrame = getWidth() > 0 && getHeight() > 0;
169                     updateWindow(false, false);
170                     return true;
171                 }
172             };
173     private boolean mGlobalListenersAdded;
174 
SurfaceView(Context context)175     public SurfaceView(Context context) {
176         super(context);
177         init();
178     }
179 
SurfaceView(Context context, AttributeSet attrs)180     public SurfaceView(Context context, AttributeSet attrs) {
181         super(context, attrs);
182         init();
183     }
184 
SurfaceView(Context context, AttributeSet attrs, int defStyle)185     public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
186         super(context, attrs, defStyle);
187         init();
188     }
189 
init()190     private void init() {
191         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      */
getHolder()200     public SurfaceHolder getHolder() {
201         return mSurfaceHolder;
202     }
203 
204     @Override
onAttachedToWindow()205     protected void onAttachedToWindow() {
206         super.onAttachedToWindow();
207         mParent.requestTransparentRegion(this);
208         mSession = getWindowSession();
209         mLayout.token = getWindowToken();
210         mLayout.setTitle("SurfaceView");
211         mViewVisibility = getVisibility() == VISIBLE;
212 
213         if (!mGlobalListenersAdded) {
214             ViewTreeObserver observer = getViewTreeObserver();
215             observer.addOnScrollChangedListener(mScrollChangedListener);
216             observer.addOnPreDrawListener(mDrawListener);
217             mGlobalListenersAdded = true;
218         }
219     }
220 
221     @Override
onWindowVisibilityChanged(int visibility)222     protected void onWindowVisibilityChanged(int visibility) {
223         super.onWindowVisibilityChanged(visibility);
224         mWindowVisibility = visibility == VISIBLE;
225         mRequestedVisible = mWindowVisibility && mViewVisibility;
226         updateWindow(false, false);
227     }
228 
229     @Override
setVisibility(int visibility)230     public void setVisibility(int visibility) {
231         super.setVisibility(visibility);
232         mViewVisibility = visibility == VISIBLE;
233         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;
244         updateWindow(false, false);
245     }
246 
247     @Override
onDetachedFromWindow()248     protected void onDetachedFromWindow() {
249         if (mGlobalListenersAdded) {
250             ViewTreeObserver observer = getViewTreeObserver();
251             observer.removeOnScrollChangedListener(mScrollChangedListener);
252             observer.removeOnPreDrawListener(mDrawListener);
253             mGlobalListenersAdded = false;
254         }
255 
256         mRequestedVisible = false;
257         updateWindow(false, false);
258         mHaveFrame = false;
259         if (mWindow != null) {
260             try {
261                 mSession.remove(mWindow);
262             } catch (RemoteException ex) {
263                 // Not much we can do here...
264             }
265             mWindow = null;
266         }
267         mSession = null;
268         mLayout.token = null;
269 
270         super.onDetachedFromWindow();
271     }
272 
273     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)274     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
275         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);
281         setMeasuredDimension(width, height);
282     }
283 
284     /** @hide */
285     @Override
setFrame(int left, int top, int right, int bottom)286     protected boolean setFrame(int left, int top, int right, int bottom) {
287         boolean result = super.setFrame(left, top, right, bottom);
288         updateWindow(false, false);
289         return result;
290     }
291 
292     @Override
gatherTransparentRegion(Region region)293     public boolean gatherTransparentRegion(Region region) {
294         if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
295             return super.gatherTransparentRegion(region);
296         }
297 
298         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
draw(Canvas canvas)320     public void draw(Canvas canvas) {
321         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             }
327         }
328         super.draw(canvas);
329     }
330 
331     @Override
dispatchDraw(Canvas canvas)332     protected void dispatchDraw(Canvas canvas) {
333         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             }
339         }
340         super.dispatchDraw(canvas);
341     }
342 
343     /**
344      * 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      */
setZOrderMediaOverlay(boolean isMediaOverlay)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     /**
361      * 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.
370      *
371      * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
372      */
setZOrderOnTop(boolean onTop)373     public void setZOrderOnTop(boolean onTop) {
374         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         }
382     }
383 
384     /**
385      * 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      */
setWindowType(int type)389     public void setWindowType(int type) {
390         mWindowType = type;
391     }
392 
updateWindow(boolean force, boolean redrawNeeded)393     private void updateWindow(boolean force, boolean redrawNeeded) {
394         if (!mHaveFrame) {
395             return;
396         }
397         ViewRootImpl viewRoot = getViewRootImpl();
398         if (viewRoot != null) {
399             mTranslator = viewRoot.mTranslator;
400         }
401 
402         if (mTranslator != null) {
403             mSurface.setCompatibilityTranslator(mTranslator);
404         }
405 
406         int myWidth = mRequestedWidth;
407         if (myWidth <= 0) myWidth = getWidth();
408         int myHeight = mRequestedHeight;
409         if (myHeight <= 0) myHeight = getHeight();
410 
411         getLocationInWindow(mLocation);
412         final boolean creating = mWindow == null;
413         final boolean formatChanged = mFormat != mRequestedFormat;
414         final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
415         final boolean visibleChanged = mVisible != mRequestedVisible;
416 
417         if (force || creating || formatChanged || sizeChanged || visibleChanged
418             || mLeft != mLocation[0] || mTop != mLocation[1]
419             || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
420 
421             if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
422                     + " format=" + formatChanged + " size=" + sizeChanged
423                     + " visible=" + visibleChanged
424                     + " left=" + (mLeft != mLocation[0])
425                     + " top=" + (mTop != mLocation[1]));
426 
427             try {
428                 final boolean visible = mVisible = mRequestedVisible;
429                 mLeft = mLocation[0];
430                 mTop = mLocation[1];
431                 mWidth = myWidth;
432                 mHeight = myHeight;
433                 mFormat = mRequestedFormat;
434 
435                 // 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 
446                 mLayout.format = mRequestedFormat;
447                 mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
448                               | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
449                               | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
450                               | WindowManager.LayoutParams.FLAG_SCALED
451                               | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
452                               | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
453                               ;
454                 if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
455                     mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
456                 }
457 
458                 if (mWindow == null) {
459                     mWindow = new MyWindow(this);
460                     mLayout.type = mWindowType;
461                     mLayout.gravity = Gravity.LEFT|Gravity.TOP;
462                     mSession.addWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
463                             mVisible ? VISIBLE : GONE, mContentInsets);
464                 }
465 
466                 boolean realSizeChanged;
467                 boolean reportDrawNeeded;
468 
469                 int relayoutResult;
470 
471                 mSurfaceLock.lock();
472                 try {
473                     mUpdateWindowNeeded = false;
474                     reportDrawNeeded = mReportDrawNeeded;
475                     mReportDrawNeeded = false;
476                     mDrawingStopped = !visible;
477 
478                     if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
479 
480                     relayoutResult = mSession.relayout(
481                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
482                             visible ? VISIBLE : GONE,
483                             WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY,
484                             mWinFrame, mContentInsets,
485                             mVisibleInsets, mConfiguration, mNewSurface);
486                     if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
487                         mReportDrawNeeded = true;
488                     }
489 
490                     if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
491                             + ", vis=" + visible + ", frame=" + mWinFrame);
492 
493                     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();
512                 }
513 
514                 try {
515                     redrawNeeded |= creating | reportDrawNeeded;
516 
517                     SurfaceHolder.Callback callbacks[] = null;
518 
519                     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                             }
529                         }
530                     }
531 
532                     mSurface.transferFrom(mNewSurface);
533 
534                     if (visible) {
535                         if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
536                             mSurfaceCreated = true;
537                             mIsCreating = true;
538                             if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
539                             if (callbacks == null) {
540                                 callbacks = getSurfaceCallbacks();
541                             }
542                             for (SurfaceHolder.Callback c : callbacks) {
543                                 c.surfaceCreated(mSurfaceHolder);
544                             }
545                         }
546                         if (creating || formatChanged || sizeChanged
547                                 || visibleChanged || realSizeChanged) {
548                             if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
549                                     + " w=" + myWidth + " h=" + myHeight);
550                             if (callbacks == null) {
551                                 callbacks = getSurfaceCallbacks();
552                             }
553                             for (SurfaceHolder.Callback c : callbacks) {
554                                 c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
555                             }
556                         }
557                         if (redrawNeeded) {
558                             if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
559                             if (callbacks == null) {
560                                 callbacks = getSurfaceCallbacks();
561                             }
562                             for (SurfaceHolder.Callback c : callbacks) {
563                                 if (c instanceof SurfaceHolder.Callback2) {
564                                     ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
565                                             mSurfaceHolder);
566                                 }
567                             }
568                         }
569                     }
570                 } finally {
571                     mIsCreating = false;
572                     if (redrawNeeded) {
573                         if (DEBUG) Log.i(TAG, "finishedDrawing");
574                         mSession.finishDrawing(mWindow);
575                     }
576                     mSession.performDeferredDestroy(mWindow);
577                 }
578             } catch (RemoteException ex) {
579             }
580             if (DEBUG) Log.v(
581                 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
582                 " w=" + mLayout.width + " h=" + mLayout.height +
583                 ", frame=" + mSurfaceFrame);
584         }
585     }
586 
getSurfaceCallbacks()587     private SurfaceHolder.Callback[] getSurfaceCallbacks() {
588         SurfaceHolder.Callback callbacks[];
589         synchronized (mCallbacks) {
590             callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
591             mCallbacks.toArray(callbacks);
592         }
593         return callbacks;
594     }
595 
handleGetNewSurface()596     void handleGetNewSurface() {
597         updateWindow(false, false);
598     }
599 
600     /**
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      */
isFixedSize()607     public boolean isFixedSize() {
608         return (mRequestedWidth != -1 || mRequestedHeight != -1);
609     }
610 
611     private static class MyWindow extends BaseIWindow {
612         private final WeakReference<SurfaceView> mSurfaceView;
613 
MyWindow(SurfaceView surfaceView)614         public MyWindow(SurfaceView surfaceView) {
615             mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
616         }
617 
resized(int w, int h, Rect contentInsets, Rect visibleInsets, boolean reportDraw, Configuration newConfig)618         public void resized(int w, int h, Rect contentInsets,
619                 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
620             SurfaceView surfaceView = mSurfaceView.get();
621             if (surfaceView != null) {
622                 if (DEBUG) Log.v(
623                         "SurfaceView", surfaceView + " got resized: w=" +
624                                 w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
625                 surfaceView.mSurfaceLock.lock();
626                 try {
627                     if (reportDraw) {
628                         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);
635                     }
636                 } finally {
637                     surfaceView.mSurfaceLock.unlock();
638                 }
639             }
640         }
641 
dispatchAppVisibility(boolean visible)642         public void dispatchAppVisibility(boolean visible) {
643             // The point of SurfaceView is to let the app control the surface.
644         }
645 
dispatchGetNewSurface()646         public void dispatchGetNewSurface() {
647             SurfaceView surfaceView = mSurfaceView.get();
648             if (surfaceView != null) {
649                 Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
650                 surfaceView.mHandler.sendMessage(msg);
651             }
652         }
653 
windowFocusChanged(boolean hasFocus, boolean touchEnabled)654         public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
655             Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
656         }
657 
executeCommand(String command, String parameters, ParcelFileDescriptor out)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) {
705 
706             // for backward compatibility reason, OPAQUE always
707             // means 565 for SurfaceView
708             if (format == PixelFormat.OPAQUE)
709                 format = PixelFormat.RGB_565;
710 
711             mRequestedFormat = format;
712             if (mWindow != null) {
713                 updateWindow(false, false);
714             }
715         }
716 
717         /**
718          * @deprecated setType is now ignored.
719          */
720         @Deprecated
721         public void setType(int type) { }
722 
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) {
738             mSurfaceLock.lock();
739 
740             if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
741                     + mDrawingStopped + ", win=" + mWindow);
742 
743             Canvas c = null;
744             if (!mDrawingStopped && mWindow != null) {
745                 if (dirty == null) {
746                     if (mTmpDirty == null) {
747                         mTmpDirty = new Rect();
748                     }
749                     mTmpDirty.set(mSurfaceFrame);
750                     dirty = mTmpDirty;
751                 }
752 
753                 try {
754                     c = mSurface.lockCanvas(dirty);
755                 } catch (Exception e) {
756                     Log.e(LOG_TAG, "Exception locking surface", e);
757                 }
758             }
759 
760             if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
761             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 }
798