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