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