BaseSurfaceHolder.java revision 15a4d2ffd04dc6c70f2cd17dae12ac6bc14c69ab
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
37    public final ReentrantLock mSurfaceLock = new ReentrantLock();
38    public final Surface mSurface = new Surface();
39
40    int mRequestedWidth = -1;
41    int mRequestedHeight = -1;
42    int mRequestedFormat = PixelFormat.OPAQUE;
43    int mRequestedType = -1;
44
45    long mLastLockTime = 0;
46
47    int mType = -1;
48    final Rect mSurfaceFrame = new Rect();
49
50    public abstract void onUpdateSurface();
51    public abstract void onRelayoutContainer();
52    public abstract boolean onAllowLockCanvas();
53
54    public int getRequestedWidth() {
55        return mRequestedWidth;
56    }
57
58    public int getRequestedHeight() {
59        return mRequestedHeight;
60    }
61
62    public int getRequestedFormat() {
63        return mRequestedFormat;
64    }
65
66    public int getRequestedType() {
67        return mRequestedType;
68    }
69
70    public void addCallback(Callback callback) {
71        synchronized (mCallbacks) {
72            // This is a linear search, but in practice we'll
73            // have only a couple callbacks, so it doesn't matter.
74            if (mCallbacks.contains(callback) == false) {
75                mCallbacks.add(callback);
76            }
77        }
78    }
79
80    public void removeCallback(Callback callback) {
81        synchronized (mCallbacks) {
82            mCallbacks.remove(callback);
83        }
84    }
85
86    public void setFixedSize(int width, int height) {
87        if (mRequestedWidth != width || mRequestedHeight != height) {
88            mRequestedWidth = width;
89            mRequestedHeight = height;
90            onRelayoutContainer();
91        }
92    }
93
94    public void setSizeFromLayout() {
95        if (mRequestedWidth != -1 || mRequestedHeight != -1) {
96            mRequestedWidth = mRequestedHeight = -1;
97            onRelayoutContainer();
98        }
99    }
100
101    public void setFormat(int format) {
102        if (mRequestedFormat != format) {
103            mRequestedFormat = format;
104            onUpdateSurface();
105        }
106    }
107
108    public void setType(int type) {
109        switch (type) {
110        case SURFACE_TYPE_HARDWARE:
111        case SURFACE_TYPE_GPU:
112            // these are deprecated, treat as "NORMAL"
113            type = SURFACE_TYPE_NORMAL;
114            break;
115        }
116        switch (type) {
117        case SURFACE_TYPE_NORMAL:
118        case SURFACE_TYPE_PUSH_BUFFERS:
119            if (mRequestedType != type) {
120                mRequestedType = type;
121                onUpdateSurface();
122            }
123            break;
124        }
125    }
126
127    public Canvas lockCanvas() {
128        return internalLockCanvas(null);
129    }
130
131    public Canvas lockCanvas(Rect dirty) {
132        return internalLockCanvas(dirty);
133    }
134
135    private final Canvas internalLockCanvas(Rect dirty) {
136        if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
137            throw new BadSurfaceTypeException(
138                    "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
139        }
140        mSurfaceLock.lock();
141
142        if (DEBUG) Log.i(TAG, "Locking canvas..,");
143
144        Canvas c = null;
145        if (onAllowLockCanvas()) {
146            Rect frame = dirty != null ? dirty : mSurfaceFrame;
147            try {
148                c = mSurface.lockCanvas(frame);
149            } catch (Exception e) {
150                Log.e(TAG, "Exception locking surface", e);
151            }
152        }
153
154        if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
155        if (c != null) {
156            mLastLockTime = SystemClock.uptimeMillis();
157            return c;
158        }
159
160        // If the Surface is not ready to be drawn, then return null,
161        // but throttle calls to this function so it isn't called more
162        // than every 100ms.
163        long now = SystemClock.uptimeMillis();
164        long nextTime = mLastLockTime + 100;
165        if (nextTime > now) {
166            try {
167                Thread.sleep(nextTime-now);
168            } catch (InterruptedException e) {
169            }
170            now = SystemClock.uptimeMillis();
171        }
172        mLastLockTime = now;
173        mSurfaceLock.unlock();
174
175        return null;
176    }
177
178    public void unlockCanvasAndPost(Canvas canvas) {
179        mSurface.unlockCanvasAndPost(canvas);
180        mSurfaceLock.unlock();
181    }
182
183    public Surface getSurface() {
184        return mSurface;
185    }
186
187    public Rect getSurfaceFrame() {
188        return mSurfaceFrame;
189    }
190};
191