BaseSurfaceHolder.java revision 62bf4a0283e855e2fb5f40f36909501e5b4a09eb
1/*
2 * Copyright (C) 2009 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 com.android.internal.view;
18
19import android.graphics.Canvas;
20import android.graphics.PixelFormat;
21import android.graphics.Rect;
22import android.os.SystemClock;
23import android.util.Log;
24import android.view.Surface;
25import android.view.SurfaceHolder;
26
27import java.util.ArrayList;
28import java.util.concurrent.locks.ReentrantLock;
29
30public abstract class BaseSurfaceHolder implements SurfaceHolder {
31    private static final String TAG = "BaseSurfaceHolder";
32    static final boolean DEBUG = false;
33
34    public final ArrayList<SurfaceHolder.Callback> mCallbacks
35            = new ArrayList<SurfaceHolder.Callback>();
36    SurfaceHolder.Callback[] mGottenCallbacks;
37    boolean mHaveGottenCallbacks;
38
39    public final ReentrantLock mSurfaceLock = new ReentrantLock();
40    public Surface mSurface = new Surface();
41
42    int mRequestedWidth = -1;
43    int mRequestedHeight = -1;
44    /** @hide */
45    protected int mRequestedFormat = PixelFormat.OPAQUE;
46    int mRequestedType = -1;
47
48    long mLastLockTime = 0;
49
50    int mType = -1;
51    final Rect mSurfaceFrame = new Rect();
52
53    public abstract void onUpdateSurface();
54    public abstract void onRelayoutContainer();
55    public abstract boolean onAllowLockCanvas();
56
57    public int getRequestedWidth() {
58        return mRequestedWidth;
59    }
60
61    public int getRequestedHeight() {
62        return mRequestedHeight;
63    }
64
65    public int getRequestedFormat() {
66        return mRequestedFormat;
67    }
68
69    public int getRequestedType() {
70        return mRequestedType;
71    }
72
73    public void addCallback(Callback callback) {
74        synchronized (mCallbacks) {
75            // This is a linear search, but in practice we'll
76            // have only a couple callbacks, so it doesn't matter.
77            if (mCallbacks.contains(callback) == false) {
78                mCallbacks.add(callback);
79            }
80        }
81    }
82
83    public void removeCallback(Callback callback) {
84        synchronized (mCallbacks) {
85            mCallbacks.remove(callback);
86        }
87    }
88
89    public SurfaceHolder.Callback[] getCallbacks() {
90        if (mHaveGottenCallbacks) {
91            return mGottenCallbacks;
92        }
93
94        synchronized (mCallbacks) {
95            final int N = mCallbacks.size();
96            if (N > 0) {
97                if (mGottenCallbacks == null || mGottenCallbacks.length != N) {
98                    mGottenCallbacks = new SurfaceHolder.Callback[N];
99                }
100                mCallbacks.toArray(mGottenCallbacks);
101            } else {
102                mGottenCallbacks = null;
103            }
104            mHaveGottenCallbacks = true;
105        }
106
107        return mGottenCallbacks;
108    }
109
110    public void ungetCallbacks() {
111        mHaveGottenCallbacks = false;
112    }
113
114    public void setFixedSize(int width, int height) {
115        if (mRequestedWidth != width || mRequestedHeight != height) {
116            mRequestedWidth = width;
117            mRequestedHeight = height;
118            onRelayoutContainer();
119        }
120    }
121
122    public void setSizeFromLayout() {
123        if (mRequestedWidth != -1 || mRequestedHeight != -1) {
124            mRequestedWidth = mRequestedHeight = -1;
125            onRelayoutContainer();
126        }
127    }
128
129    public void setFormat(int format) {
130        if (mRequestedFormat != format) {
131            mRequestedFormat = format;
132            onUpdateSurface();
133        }
134    }
135
136    public void setType(int type) {
137        switch (type) {
138        case SURFACE_TYPE_HARDWARE:
139        case SURFACE_TYPE_GPU:
140            // these are deprecated, treat as "NORMAL"
141            type = SURFACE_TYPE_NORMAL;
142            break;
143        }
144        switch (type) {
145        case SURFACE_TYPE_NORMAL:
146        case SURFACE_TYPE_PUSH_BUFFERS:
147            if (mRequestedType != type) {
148                mRequestedType = type;
149                onUpdateSurface();
150            }
151            break;
152        }
153    }
154
155    public Canvas lockCanvas() {
156        return internalLockCanvas(null);
157    }
158
159    public Canvas lockCanvas(Rect dirty) {
160        return internalLockCanvas(dirty);
161    }
162
163    private final Canvas internalLockCanvas(Rect dirty) {
164        if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
165            throw new BadSurfaceTypeException(
166                    "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
167        }
168        mSurfaceLock.lock();
169
170        if (DEBUG) Log.i(TAG, "Locking canvas..,");
171
172        Canvas c = null;
173        if (onAllowLockCanvas()) {
174            Rect frame = dirty != null ? dirty : mSurfaceFrame;
175            try {
176                c = mSurface.lockCanvas(frame);
177            } catch (Exception e) {
178                Log.e(TAG, "Exception locking surface", e);
179            }
180        }
181
182        if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
183        if (c != null) {
184            mLastLockTime = SystemClock.uptimeMillis();
185            return c;
186        }
187
188        // If the Surface is not ready to be drawn, then return null,
189        // but throttle calls to this function so it isn't called more
190        // than every 100ms.
191        long now = SystemClock.uptimeMillis();
192        long nextTime = mLastLockTime + 100;
193        if (nextTime > now) {
194            try {
195                Thread.sleep(nextTime-now);
196            } catch (InterruptedException e) {
197            }
198            now = SystemClock.uptimeMillis();
199        }
200        mLastLockTime = now;
201        mSurfaceLock.unlock();
202
203        return null;
204    }
205
206    public void unlockCanvasAndPost(Canvas canvas) {
207        mSurface.unlockCanvasAndPost(canvas);
208        mSurfaceLock.unlock();
209    }
210
211    public Surface getSurface() {
212        return mSurface;
213    }
214
215    public Rect getSurfaceFrame() {
216        return mSurfaceFrame;
217    }
218};
219