Surface.java revision 0233b6ee33e743602198cef7fb80f1e4619bb035
1/* 2 * Copyright (C) 2007 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 android.view; 18 19import android.content.res.CompatibilityInfo.Translator; 20import android.graphics.Canvas; 21import android.graphics.Matrix; 22import android.graphics.Rect; 23import android.graphics.SurfaceTexture; 24import android.os.Parcel; 25import android.os.Parcelable; 26import android.util.Log; 27import dalvik.system.CloseGuard; 28 29/** 30 * Handle onto a raw buffer that is being managed by the screen compositor. 31 */ 32public class Surface implements Parcelable { 33 private static final String TAG = "Surface"; 34 35 public static final Parcelable.Creator<Surface> CREATOR = 36 new Parcelable.Creator<Surface>() { 37 public Surface createFromParcel(Parcel source) { 38 try { 39 Surface s = new Surface(); 40 s.readFromParcel(source); 41 return s; 42 } catch (Exception e) { 43 Log.e(TAG, "Exception creating surface from parcel", e); 44 return null; 45 } 46 } 47 48 public Surface[] newArray(int size) { 49 return new Surface[size]; 50 } 51 }; 52 53 /** 54 * Rotation constant: 0 degree rotation (natural orientation) 55 */ 56 public static final int ROTATION_0 = 0; 57 58 /** 59 * Rotation constant: 90 degree rotation. 60 */ 61 public static final int ROTATION_90 = 1; 62 63 /** 64 * Rotation constant: 180 degree rotation. 65 */ 66 public static final int ROTATION_180 = 2; 67 68 /** 69 * Rotation constant: 270 degree rotation. 70 */ 71 public static final int ROTATION_270 = 3; 72 73 74 private final CloseGuard mCloseGuard = CloseGuard.get(); 75 private String mName; 76 77 // Note: These fields are accessed by native code. 78 // The mSurfaceControl will only be present for Surfaces used by the window 79 // server or system processes. When this class is parceled we defer to the 80 // mSurfaceControl to do the parceling. Otherwise we parcel the 81 // mNativeSurface. 82 int mNativeObject; // package scope only for SurfaceControl access 83 84 private int mGenerationId; // incremented each time mNativeSurface changes 85 private final Canvas mCanvas = new CompatibleCanvas(); 86 87 // The Translator for density compatibility mode. This is used for scaling 88 // the canvas to perform the appropriate density transformation. 89 private Translator mCompatibilityTranslator; 90 91 // A matrix to scale the matrix set by application. This is set to null for 92 // non compatibility mode. 93 private Matrix mCompatibleMatrix; 94 95 96 /** 97 * Create an empty surface, which will later be filled in by readFromParcel(). 98 * @hide 99 */ 100 public Surface() { 101 mCloseGuard.open("release"); 102 } 103 104 /** 105 * Create Surface from a {@link SurfaceTexture}. 106 * 107 * Images drawn to the Surface will be made available to the {@link 108 * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link 109 * SurfaceTexture#updateTexImage}. 110 * 111 * @param surfaceTexture The {@link SurfaceTexture} that is updated by this 112 * Surface. 113 */ 114 public Surface(SurfaceTexture surfaceTexture) { 115 if (surfaceTexture == null) { 116 throw new IllegalArgumentException("surfaceTexture must not be null"); 117 } 118 119 mName = surfaceTexture.toString(); 120 try { 121 mNativeObject = nativeCreateFromSurfaceTexture(surfaceTexture); 122 } catch (OutOfResourcesException ex) { 123 // We can't throw OutOfResourcesException because it would be an API change. 124 throw new RuntimeException(ex); 125 } 126 127 mCloseGuard.open("release"); 128 } 129 130 private Surface(int nativeObject) { 131 mNativeObject = nativeObject; 132 mCloseGuard.open("release"); 133 } 134 135 @Override 136 protected void finalize() throws Throwable { 137 try { 138 if (mCloseGuard != null) { 139 mCloseGuard.warnIfOpen(); 140 } 141 if (mNativeObject != 0) { 142 nativeRelease(mNativeObject); 143 } 144 } finally { 145 super.finalize(); 146 } 147 } 148 149 /** 150 * Release the local reference to the server-side surface. 151 * Always call release() when you're done with a Surface. 152 * This will make the surface invalid. 153 */ 154 public void release() { 155 if (mNativeObject != 0) { 156 nativeRelease(mNativeObject); 157 mNativeObject = 0; 158 } 159 mCloseGuard.close(); 160 } 161 162 /** 163 * Free all server-side state associated with this surface and 164 * release this object's reference. This method can only be 165 * called from the process that created the service. 166 * @hide 167 */ 168 public void destroy() { 169 if (mNativeObject != 0) { 170 nativeDestroy(mNativeObject); 171 mNativeObject = 0; 172 } 173 mCloseGuard.close(); 174 } 175 176 /** 177 * Returns true if this object holds a valid surface. 178 * 179 * @return True if it holds a physical surface, so lockCanvas() will succeed. 180 * Otherwise returns false. 181 */ 182 public boolean isValid() { 183 if (mNativeObject == 0) return false; 184 return nativeIsValid(mNativeObject); 185 } 186 187 /** 188 * Gets the generation number of this surface, incremented each time 189 * the native surface contained within this object changes. 190 * 191 * @return The current generation number. 192 * @hide 193 */ 194 public int getGenerationId() { 195 return mGenerationId; 196 } 197 198 /** 199 * Returns true if the consumer of this Surface is running behind the producer. 200 * 201 * @return True if the consumer is more than one buffer ahead of the producer. 202 * @hide 203 */ 204 public boolean isConsumerRunningBehind() { 205 checkNotReleased(); 206 return nativeIsConsumerRunningBehind(mNativeObject); 207 } 208 209 /** 210 * Gets a {@link Canvas} for drawing into this surface. 211 * 212 * After drawing into the provided {@link Canvas}, the caller should 213 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 214 * 215 * @param inOutDirty A rectangle that represents the dirty region that the caller wants 216 * to redraw. This function may choose to expand the dirty rectangle if for example 217 * the surface has been resized or if the previous contents of the surface were 218 * not available. The caller should redraw the entire dirty region as represented 219 * by the contents of the dirty rect upon return from this function. 220 * The caller may also pass <code>null</code> instead, in the case where the 221 * entire surface should be redrawn. 222 * @return A canvas for drawing into the surface. 223 */ 224 public Canvas lockCanvas(Rect inOutDirty) 225 throws OutOfResourcesException, IllegalArgumentException { 226 checkNotReleased(); 227 return nativeLockCanvas(mNativeObject, inOutDirty); 228 } 229 230 /** 231 * Posts the new contents of the {@link Canvas} to the surface and 232 * releases the {@link Canvas}. 233 * 234 * @param canvas The canvas previously obtained from {@link #lockCanvas}. 235 */ 236 public void unlockCanvasAndPost(Canvas canvas) { 237 checkNotReleased(); 238 nativeUnlockCanvasAndPost(mNativeObject, canvas); 239 } 240 241 /** 242 * @deprecated This API has been removed and is not supported. Do not use. 243 */ 244 @Deprecated 245 public void unlockCanvas(Canvas canvas) { 246 throw new UnsupportedOperationException(); 247 } 248 249 /** 250 * Sets the translator used to scale canvas's width/height in compatibility 251 * mode. 252 */ 253 void setCompatibilityTranslator(Translator translator) { 254 if (translator != null) { 255 float appScale = translator.applicationScale; 256 mCompatibleMatrix = new Matrix(); 257 mCompatibleMatrix.setScale(appScale, appScale); 258 } 259 } 260 261 262 /** 263 * Copy another surface to this one. This surface now holds a reference 264 * to the same data as the original surface, and is -not- the owner. 265 * This is for use by the window manager when returning a window surface 266 * back from a client, converting it from the representation being managed 267 * by the window manager to the representation the client uses to draw 268 * in to it. 269 * @hide 270 */ 271 public void copyFrom(SurfaceControl other) { 272 if (other == null) { 273 throw new IllegalArgumentException("other must not be null"); 274 } 275 if (other.mNativeObject == 0) { 276 throw new NullPointerException( 277 "SurfaceControl native object is null. Are you using a released SurfaceControl?"); 278 } 279 mNativeObject = nativeCopyFrom(mNativeObject, other.mNativeObject); 280 } 281 282 /** 283 * Transfer the native state from 'other' to this surface, releasing it 284 * from 'other'. This is for use in the client side for drawing into a 285 * surface; not guaranteed to work on the window manager side. 286 * This is for use by the client to move the underlying surface from 287 * one Surface object to another, in particular in SurfaceFlinger. 288 * @hide. 289 */ 290 public void transferFrom(Surface other) { 291 if (other == null) { 292 throw new IllegalArgumentException("other must not be null"); 293 } 294 if (other != this) { 295 if (mNativeObject != 0) { 296 // release our reference to our native object 297 nativeRelease(mNativeObject); 298 } 299 // transfer the reference from other to us 300 mNativeObject = other.mNativeObject; 301 other.mNativeObject = 0; 302 } 303 } 304 305 @Override 306 public int describeContents() { 307 return 0; 308 } 309 310 public void readFromParcel(Parcel source) { 311 if (source == null) { 312 throw new IllegalArgumentException("source must not be null"); 313 } 314 mName = source.readString(); 315 mNativeObject = nativeReadFromParcel(mNativeObject, source); 316 } 317 318 @Override 319 public void writeToParcel(Parcel dest, int flags) { 320 if (dest == null) { 321 throw new IllegalArgumentException("dest must not be null"); 322 } 323 dest.writeString(mName); 324 nativeWriteToParcel(mNativeObject, dest); 325 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { 326 release(); 327 } 328 } 329 330 @Override 331 public String toString() { 332 return "Surface(name=" + mName + ")"; 333 } 334 335 /** 336 * Exception thrown when a surface couldn't be created or resized. 337 */ 338 public static class OutOfResourcesException extends Exception { 339 public OutOfResourcesException() { 340 } 341 public OutOfResourcesException(String name) { 342 super(name); 343 } 344 } 345 346 /** 347 * Returns a human readable representation of a rotation. 348 * 349 * @param rotation The rotation. 350 * @return The rotation symbolic name. 351 * 352 * @hide 353 */ 354 public static String rotationToString(int rotation) { 355 switch (rotation) { 356 case Surface.ROTATION_0: { 357 return "ROTATION_0"; 358 } 359 case Surface.ROTATION_90: { 360 return "ROATATION_90"; 361 } 362 case Surface.ROTATION_180: { 363 return "ROATATION_180"; 364 } 365 case Surface.ROTATION_270: { 366 return "ROATATION_270"; 367 } 368 default: { 369 throw new IllegalArgumentException("Invalid rotation: " + rotation); 370 } 371 } 372 } 373 374 /** 375 * A Canvas class that can handle the compatibility mode. 376 * This does two things differently. 377 * <ul> 378 * <li>Returns the width and height of the target metrics, rather than 379 * native. For example, the canvas returns 320x480 even if an app is running 380 * in WVGA high density. 381 * <li>Scales the matrix in setMatrix by the application scale, except if 382 * the matrix looks like obtained from getMatrix. This is a hack to handle 383 * the case that an application uses getMatrix to keep the original matrix, 384 * set matrix of its own, then set the original matrix back. There is no 385 * perfect solution that works for all cases, and there are a lot of cases 386 * that this model does not work, but we hope this works for many apps. 387 * </ul> 388 */ 389 private final class CompatibleCanvas extends Canvas { 390 // A temp matrix to remember what an application obtained via {@link getMatrix} 391 private Matrix mOrigMatrix = null; 392 393 @Override 394 public int getWidth() { 395 int w = super.getWidth(); 396 if (mCompatibilityTranslator != null) { 397 w = (int)(w * mCompatibilityTranslator.applicationInvertedScale + .5f); 398 } 399 return w; 400 } 401 402 @Override 403 public int getHeight() { 404 int h = super.getHeight(); 405 if (mCompatibilityTranslator != null) { 406 h = (int)(h * mCompatibilityTranslator.applicationInvertedScale + .5f); 407 } 408 return h; 409 } 410 411 @Override 412 public void setMatrix(Matrix matrix) { 413 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) { 414 // don't scale the matrix if it's not compatibility mode, or 415 // the matrix was obtained from getMatrix. 416 super.setMatrix(matrix); 417 } else { 418 Matrix m = new Matrix(mCompatibleMatrix); 419 m.preConcat(matrix); 420 super.setMatrix(m); 421 } 422 } 423 424 @Override 425 public void getMatrix(Matrix m) { 426 super.getMatrix(m); 427 if (mOrigMatrix == null) { 428 mOrigMatrix = new Matrix(); 429 } 430 mOrigMatrix.set(m); 431 } 432 } 433 434 private void checkNotReleased() { 435 if (mNativeObject == 0) throw new NullPointerException( 436 "mNativeObject is null. Have you called release() already?"); 437 } 438 439 private native int nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture) 440 throws OutOfResourcesException; 441 442 private native void nativeRelease(int nativeObject); 443 private native void nativeDestroy(int nativeObject); 444 private native boolean nativeIsValid(int nativeObject); 445 446 private native boolean nativeIsConsumerRunningBehind(int nativeObject); 447 448 private native Canvas nativeLockCanvas(int nativeObject, Rect dirty); 449 private native void nativeUnlockCanvasAndPost(int nativeObject, Canvas canvas); 450 451 private native int nativeCopyFrom(int nativeObject, int surfaceControlNativeObject); 452 private native int nativeReadFromParcel(int nativeObject, Parcel source); 453 private native void nativeWriteToParcel(int nativeObject, Parcel dest); 454} 455