BaseSurfaceHolder.java revision 4c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3
1package com.android.internal.view;
2
3import android.graphics.Canvas;
4import android.graphics.PixelFormat;
5import android.graphics.Rect;
6import android.os.SystemClock;
7import android.util.Log;
8import android.view.Surface;
9import android.view.SurfaceHolder;
10
11import java.util.ArrayList;
12import java.util.concurrent.locks.ReentrantLock;
13
14public abstract class BaseSurfaceHolder implements SurfaceHolder {
15    private static final String TAG = "BaseSurfaceHolder";
16    static final boolean DEBUG = false;
17
18    public final ArrayList<SurfaceHolder.Callback> mCallbacks
19            = new ArrayList<SurfaceHolder.Callback>();
20
21    public final ReentrantLock mSurfaceLock = new ReentrantLock();
22    public final Surface mSurface = new Surface();
23
24    int mRequestedWidth = -1;
25    int mRequestedHeight = -1;
26    int mRequestedFormat = PixelFormat.OPAQUE;
27    int mRequestedType = -1;
28
29    long mLastLockTime = 0;
30
31    int mType = -1;
32    final Rect mSurfaceFrame = new Rect();
33
34    public abstract void onUpdateSurface();
35    public abstract void onRelayoutContainer();
36    public abstract boolean onAllowLockCanvas();
37
38    public int getRequestedWidth() {
39        return mRequestedWidth;
40    }
41
42    public int getRequestedHeight() {
43        return mRequestedHeight;
44    }
45
46    public int getRequestedFormat() {
47        return mRequestedFormat;
48    }
49
50    public int getRequestedType() {
51        return mRequestedType;
52    }
53
54    public void addCallback(Callback callback) {
55        synchronized (mCallbacks) {
56            // This is a linear search, but in practice we'll
57            // have only a couple callbacks, so it doesn't matter.
58            if (mCallbacks.contains(callback) == false) {
59                mCallbacks.add(callback);
60            }
61        }
62    }
63
64    public void removeCallback(Callback callback) {
65        synchronized (mCallbacks) {
66            mCallbacks.remove(callback);
67        }
68    }
69
70    public void setFixedSize(int width, int height) {
71        if (mRequestedWidth != width || mRequestedHeight != height) {
72            mRequestedWidth = width;
73            mRequestedHeight = height;
74            onRelayoutContainer();
75        }
76    }
77
78    public void setSizeFromLayout() {
79        if (mRequestedWidth != -1 || mRequestedHeight != -1) {
80            mRequestedWidth = mRequestedHeight = -1;
81            onRelayoutContainer();
82        }
83    }
84
85    public void setFormat(int format) {
86        if (mRequestedFormat != format) {
87            mRequestedFormat = format;
88            onUpdateSurface();
89        }
90    }
91
92    public void setType(int type) {
93        switch (type) {
94        case SURFACE_TYPE_NORMAL:
95        case SURFACE_TYPE_HARDWARE:
96        case SURFACE_TYPE_GPU:
97        case SURFACE_TYPE_PUSH_BUFFERS:
98            if (mRequestedType != type) {
99                mRequestedType = type;
100                onUpdateSurface();
101            }
102            break;
103        }
104    }
105
106    public Canvas lockCanvas() {
107        return internalLockCanvas(null);
108    }
109
110    public Canvas lockCanvas(Rect dirty) {
111        return internalLockCanvas(dirty);
112    }
113
114    private final Canvas internalLockCanvas(Rect dirty) {
115        if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
116            throw new BadSurfaceTypeException(
117                    "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
118        }
119        mSurfaceLock.lock();
120
121        if (DEBUG) Log.i(TAG, "Locking canvas..,");
122
123        Canvas c = null;
124        if (onAllowLockCanvas()) {
125            Rect frame = dirty != null ? dirty : mSurfaceFrame;
126            try {
127                c = mSurface.lockCanvas(frame);
128            } catch (Exception e) {
129                Log.e(TAG, "Exception locking surface", e);
130            }
131        }
132
133        if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
134        if (c != null) {
135            mLastLockTime = SystemClock.uptimeMillis();
136            return c;
137        }
138
139        // If the Surface is not ready to be drawn, then return null,
140        // but throttle calls to this function so it isn't called more
141        // than every 100ms.
142        long now = SystemClock.uptimeMillis();
143        long nextTime = mLastLockTime + 100;
144        if (nextTime > now) {
145            try {
146                Thread.sleep(nextTime-now);
147            } catch (InterruptedException e) {
148            }
149            now = SystemClock.uptimeMillis();
150        }
151        mLastLockTime = now;
152        mSurfaceLock.unlock();
153
154        return null;
155    }
156
157    public void unlockCanvasAndPost(Canvas canvas) {
158        mSurface.unlockCanvasAndPost(canvas);
159        mSurfaceLock.unlock();
160    }
161
162    public Surface getSurface() {
163        return mSurface;
164    }
165
166    public Rect getSurfaceFrame() {
167        return mSurfaceFrame;
168    }
169};
170