SurfaceViewpublic class SurfaceView extends View Provides a dedicated drawing surface embedded inside of a view hierarchy.
You can control the format of this surface and, if you like, its size; the
SurfaceView takes care of placing the surface at the correct location on the
screen
The surface is Z ordered so that it is behind the window holding its
SurfaceView; the SurfaceView punches a hole in its window to allow its
surface to be displayed. The view hierarchy will take care of correctly
compositing with the Surface any siblings of the SurfaceView that would
normally appear on top of it. This can be used to place overlays such as
buttons on top of the Surface, though note however that it can have an
impact on performance since a full alpha-blended composite will be performed
each time the Surface changes.
Access to the underlying surface is provided via the SurfaceHolder interface,
which can be retrieved by calling {@link #getHolder}.
The Surface will be created for you while the SurfaceView's window is
visible; you should implement {@link SurfaceHolder.Callback#surfaceCreated}
and {@link SurfaceHolder.Callback#surfaceDestroyed} to discover when the
Surface is created and destroyed as the window is shown and hidden.
One of the purposes of this class is to provide a surface in which a
secondary thread can render in to the screen. If you are going to use it
this way, you need to be aware of some threading semantics:
- All SurfaceView and
{@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
from the thread running the SurfaceView's window (typically the main thread
of the application). They thus need to correctly synchronize with any
state that is also touched by the drawing thread.
- You must ensure that the drawing thread only touches the underlying
Surface while it is valid -- between
{@link SurfaceHolder.Callback#surfaceCreated SurfaceHolder.Callback.surfaceCreated()}
and
{@link SurfaceHolder.Callback#surfaceDestroyed SurfaceHolder.Callback.surfaceDestroyed()}.
|
Fields Summary |
---|
private static final String | TAG | private static final boolean | DEBUG | private static final boolean | localLOGV | final ArrayList | mCallbacks | final int[] | mLocation | final ReentrantLock | mSurfaceLock | final Surface | mSurface | boolean | mDrawingStopped | final WindowManager.LayoutParams | mLayout | IWindowSession | mSession | MyWindow | mWindow | final android.graphics.Rect | mVisibleInsets | final android.graphics.Rect | mWinFrame | final android.graphics.Rect | mContentInsets | static final int | KEEP_SCREEN_ON_MSG | static final int | GET_NEW_SURFACE_MSG | boolean | mIsCreating | final android.os.Handler | mHandler | boolean | mRequestedVisible | int | mRequestedWidth | int | mRequestedHeight | int | mRequestedFormat | int | mRequestedType | boolean | mHaveFrame | boolean | mDestroyReportNeeded | boolean | mNewSurfaceNeeded | long | mLastLockTime | boolean | mVisible | int | mLeft | int | mTop | int | mWidth | int | mHeight | int | mFormat | int | mType | final android.graphics.Rect | mSurfaceFrame | private SurfaceHolder | mSurfaceHolder |
Methods Summary |
---|
protected void | dispatchDraw(android.graphics.Canvas canvas)
// if SKIP_DRAW is cleared, draw() has already punched a hole
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
// punch a whole in the view-hierarchy below us
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
}
// reposition ourselves where the surface is
mHaveFrame = true;
updateWindow(false);
super.dispatchDraw(canvas);
| public void | draw(android.graphics.Canvas canvas)
// draw() is not called when SKIP_DRAW is set
if ((mPrivateFlags & SKIP_DRAW) == 0) {
// punch a whole in the view-hierarchy below us
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
}
super.draw(canvas);
| public boolean | gatherTransparentRegion(android.graphics.Region region)
boolean opaque = true;
if ((mPrivateFlags & SKIP_DRAW) == 0) {
// this view draws, remove it from the transparent region
opaque = super.gatherTransparentRegion(region);
} else if (region != null) {
int w = getWidth();
int h = getHeight();
if (w>0 && h>0) {
getLocationInWindow(mLocation);
// otherwise, punch a hole in the whole hierarchy
int l = mLocation[0];
int t = mLocation[1];
region.op(l, t, l+w, t+h, Region.Op.UNION);
}
}
if (PixelFormat.formatHasAlpha(mRequestedFormat)) {
opaque = false;
}
return opaque;
| public SurfaceHolder | getHolder()Return the SurfaceHolder providing access and control over this
SurfaceView's underlying surface.
return mSurfaceHolder;
| void | handleGetNewSurface()
mNewSurfaceNeeded = true;
updateWindow(false);
| protected void | onAttachedToWindow()
super.onAttachedToWindow();
mParent.requestTransparentRegion(this);
mSession = getWindowSession();
mLayout.token = getWindowToken();
mLayout.setTitle("SurfaceView");
| protected void | onDetachedFromWindow()
mRequestedVisible = false;
updateWindow(false);
mHaveFrame = false;
if (mWindow != null) {
try {
mSession.remove(mWindow);
} catch (RemoteException ex) {
}
mWindow = null;
}
mSession = null;
mLayout.token = null;
super.onDetachedFromWindow();
| protected void | onMeasure(int widthMeasureSpec, int heightMeasureSpec)
int width = getDefaultSize(mRequestedWidth, widthMeasureSpec);
int height = getDefaultSize(mRequestedHeight, heightMeasureSpec);
setMeasuredDimension(width, height);
| protected void | onScrollChanged(int l, int t, int oldl, int oldt)
super.onScrollChanged(l, t, oldl, oldt);
updateWindow(false);
| protected void | onSizeChanged(int w, int h, int oldw, int oldh)
super.onSizeChanged(w, h, oldw, oldh);
updateWindow(false);
| protected void | onWindowVisibilityChanged(int visibility)
super.onWindowVisibilityChanged(visibility);
mRequestedVisible = visibility == VISIBLE;
updateWindow(false);
| private void | reportSurfaceDestroyed()
if (mDestroyReportNeeded) {
mDestroyReportNeeded = false;
SurfaceHolder.Callback callbacks[];
synchronized (mCallbacks) {
callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
mCallbacks.toArray(callbacks);
}
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
}
}
super.onDetachedFromWindow();
| private void | updateWindow(boolean force)
if (!mHaveFrame) {
return;
}
int myWidth = mRequestedWidth;
if (myWidth <= 0) myWidth = getWidth();
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
getLocationInWindow(mLocation);
final boolean creating = mWindow == null;
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
final boolean visibleChanged = mVisible != mRequestedVisible
|| mNewSurfaceNeeded;
final boolean typeChanged = mType != mRequestedType;
if (force || creating || formatChanged || sizeChanged || visibleChanged
|| typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]) {
if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ " visible=" + visibleChanged
+ " left=" + (mLeft != mLocation[0])
+ " top=" + (mTop != mLocation[1]));
try {
final boolean visible = mVisible = mRequestedVisible;
mLeft = mLocation[0];
mTop = mLocation[1];
mWidth = myWidth;
mHeight = myHeight;
mFormat = mRequestedFormat;
mType = mRequestedType;
mLayout.x = mLeft;
mLayout.y = mTop;
mLayout.width = getWidth();
mLayout.height = getHeight();
mLayout.format = mRequestedFormat;
mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_SCALED
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
;
mLayout.memoryType = mRequestedType;
if (mWindow == null) {
mWindow = new MyWindow(this);
mLayout.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
mLayout.gravity = Gravity.LEFT|Gravity.TOP;
mSession.add(mWindow, mLayout,
mVisible ? VISIBLE : GONE, mContentInsets);
}
if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
reportSurfaceDestroyed();
}
mNewSurfaceNeeded = false;
mSurfaceLock.lock();
mDrawingStopped = !visible;
final int relayoutResult = mSession.relayout(
mWindow, mLayout, mWidth, mHeight,
visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
mVisibleInsets, mSurface);
if (localLOGV) Log.i(TAG, "New surface: " + mSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
mSurfaceFrame.left = 0;
mSurfaceFrame.top = 0;
mSurfaceFrame.right = mWinFrame.width();
mSurfaceFrame.bottom = mWinFrame.height();
mSurfaceLock.unlock();
try {
if (visible) {
mDestroyReportNeeded = true;
SurfaceHolder.Callback callbacks[];
synchronized (mCallbacks) {
callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
mCallbacks.toArray(callbacks);
}
if (visibleChanged) {
mIsCreating = true;
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder);
}
}
if (creating || formatChanged || sizeChanged
|| visibleChanged) {
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
}
}
}
} finally {
mIsCreating = false;
if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
mSession.finishDrawing(mWindow);
}
}
} catch (RemoteException ex) {
}
if (localLOGV) Log.v(
TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
" w=" + mLayout.width + " h=" + mLayout.height +
", frame=" + mSurfaceFrame);
}
|
|