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 onUpdateSurface()53 public abstract void onUpdateSurface(); onRelayoutContainer()54 public abstract void onRelayoutContainer(); onAllowLockCanvas()55 public abstract boolean onAllowLockCanvas(); 56 getRequestedWidth()57 public int getRequestedWidth() { 58 return mRequestedWidth; 59 } 60 getRequestedHeight()61 public int getRequestedHeight() { 62 return mRequestedHeight; 63 } 64 getRequestedFormat()65 public int getRequestedFormat() { 66 return mRequestedFormat; 67 } 68 getRequestedType()69 public int getRequestedType() { 70 return mRequestedType; 71 } 72 addCallback(Callback callback)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 removeCallback(Callback callback)83 public void removeCallback(Callback callback) { 84 synchronized (mCallbacks) { 85 mCallbacks.remove(callback); 86 } 87 } 88 getCallbacks()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 ungetCallbacks()110 public void ungetCallbacks() { 111 mHaveGottenCallbacks = false; 112 } 113 setFixedSize(int width, int height)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 setSizeFromLayout()122 public void setSizeFromLayout() { 123 if (mRequestedWidth != -1 || mRequestedHeight != -1) { 124 mRequestedWidth = mRequestedHeight = -1; 125 onRelayoutContainer(); 126 } 127 } 128 setFormat(int format)129 public void setFormat(int format) { 130 if (mRequestedFormat != format) { 131 mRequestedFormat = format; 132 onUpdateSurface(); 133 } 134 } 135 setType(int type)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 lockCanvas()155 public Canvas lockCanvas() { 156 return internalLockCanvas(null); 157 } 158 lockCanvas(Rect dirty)159 public Canvas lockCanvas(Rect dirty) { 160 return internalLockCanvas(dirty); 161 } 162 internalLockCanvas(Rect dirty)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 unlockCanvasAndPost(Canvas canvas)206 public void unlockCanvasAndPost(Canvas canvas) { 207 mSurface.unlockCanvasAndPost(canvas); 208 mSurfaceLock.unlock(); 209 } 210 getSurface()211 public Surface getSurface() { 212 return mSurface; 213 } 214 getSurfaceFrame()215 public Rect getSurfaceFrame() { 216 return mSurfaceFrame; 217 } 218 }; 219