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 54 public abstract void onUpdateSurface(); 55 public abstract void onRelayoutContainer(); 56 public abstract boolean onAllowLockCanvas(); 57 58 public int getRequestedWidth() { 59 return mRequestedWidth; 60 } 61 62 public int getRequestedHeight() { 63 return mRequestedHeight; 64 } 65 66 public int getRequestedFormat() { 67 return mRequestedFormat; 68 } 69 70 public int getRequestedType() { 71 return mRequestedType; 72 } 73 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 84 public void removeCallback(Callback callback) { 85 synchronized (mCallbacks) { 86 mCallbacks.remove(callback); 87 } 88 } 89 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 111 public void ungetCallbacks() { 112 mHaveGottenCallbacks = false; 113 } 114 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 123 public void setSizeFromLayout() { 124 if (mRequestedWidth != -1 || mRequestedHeight != -1) { 125 mRequestedWidth = mRequestedHeight = -1; 126 onRelayoutContainer(); 127 } 128 } 129 130 public void setFormat(int format) { 131 if (mRequestedFormat != format) { 132 mRequestedFormat = format; 133 onUpdateSurface(); 134 } 135 } 136 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 public Canvas lockCanvas() { 157 return internalLockCanvas(null); 158 } 159 160 public Canvas lockCanvas(Rect dirty) { 161 return internalLockCanvas(dirty); 162 } 163 164 private final Canvas internalLockCanvas(Rect dirty) { 165 if (mType == SURFACE_TYPE_PUSH_BUFFERS) { 166 throw new BadSurfaceTypeException( 167 "Surface type is SURFACE_TYPE_PUSH_BUFFERS"); 168 } 169 mSurfaceLock.lock(); 170 171 if (DEBUG) Log.i(TAG, "Locking canvas..,"); 172 173 Canvas c = null; 174 if (onAllowLockCanvas()) { 175 if (dirty == null) { 176 if (mTmpDirty == null) { 177 mTmpDirty = new Rect(); 178 } 179 mTmpDirty.set(mSurfaceFrame); 180 dirty = mTmpDirty; 181 } 182 183 try { 184 c = mSurface.lockCanvas(dirty); 185 } catch (Exception e) { 186 Log.e(TAG, "Exception locking surface", e); 187 } 188 } 189 190 if (DEBUG) Log.i(TAG, "Returned canvas: " + c); 191 if (c != null) { 192 mLastLockTime = SystemClock.uptimeMillis(); 193 return c; 194 } 195 196 // If the Surface is not ready to be drawn, then return null, 197 // but throttle calls to this function so it isn't called more 198 // than every 100ms. 199 long now = SystemClock.uptimeMillis(); 200 long nextTime = mLastLockTime + 100; 201 if (nextTime > now) { 202 try { 203 Thread.sleep(nextTime-now); 204 } catch (InterruptedException e) { 205 } 206 now = SystemClock.uptimeMillis(); 207 } 208 mLastLockTime = now; 209 mSurfaceLock.unlock(); 210 211 return null; 212 } 213 214 public void unlockCanvasAndPost(Canvas canvas) { 215 mSurface.unlockCanvasAndPost(canvas); 216 mSurfaceLock.unlock(); 217 } 218 219 public Surface getSurface() { 220 return mSurface; 221 } 222 223 public Rect getSurfaceFrame() { 224 return mSurfaceFrame; 225 } 226 227 public void setSurfaceFrameSize(int width, int height) { 228 mSurfaceFrame.top = 0; 229 mSurfaceFrame.left = 0; 230 mSurfaceFrame.right = width; 231 mSurfaceFrame.bottom = height; 232 } 233 }; 234