blob: e0786f704ed9651f03c98da733757a74aa0d5146 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Mitsuru Oshima240f8a72009-07-22 20:39:14 -070019import android.content.res.CompatibilityInfo.Translator;
Jeff Brown0b722fe2012-08-24 22:40:14 -070020import android.graphics.Canvas;
21import android.graphics.Matrix;
22import android.graphics.Rect;
Jeff Brown0b722fe2012-08-24 22:40:14 -070023import android.graphics.SurfaceTexture;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.os.Parcel;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080025import android.os.Parcelable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.util.Log;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080027import dalvik.system.CloseGuard;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
29/**
Glenn Kasten334031c2010-11-09 21:54:38 -080030 * Handle onto a raw buffer that is being managed by the screen compositor.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031 */
32public class Surface implements Parcelable {
Jeff Brown64a55af2012-08-26 02:47:39 -070033 private static final String TAG = "Surface";
Mathias Agopianb9230662011-08-03 14:44:48 -070034
Mathias Agopian52800612013-02-14 17:11:20 -080035 private static native int nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
Mathias Agopian29479eb2013-02-14 14:36:04 -080036 throws OutOfResourcesException;
Jeff Brownfc0ebd72013-04-30 16:33:00 -070037 private static native int nativeCreateFromSurfaceControl(int surfaceControlNativeObject);
Mathias Agopian52800612013-02-14 17:11:20 -080038
Jeff Brownfc0ebd72013-04-30 16:33:00 -070039 private static native void nativeLockCanvas(int nativeObject, Canvas canvas, Rect dirty)
40 throws OutOfResourcesException;
41 private static native void nativeUnlockCanvasAndPost(int nativeObject, Canvas canvas);
Mathias Agopian29479eb2013-02-14 14:36:04 -080042
43 private static native void nativeRelease(int nativeObject);
Mathias Agopian29479eb2013-02-14 14:36:04 -080044 private static native boolean nativeIsValid(int nativeObject);
45 private static native boolean nativeIsConsumerRunningBehind(int nativeObject);
Mathias Agopian29479eb2013-02-14 14:36:04 -080046 private static native int nativeReadFromParcel(int nativeObject, Parcel source);
47 private static native void nativeWriteToParcel(int nativeObject, Parcel dest);
48
Jeff Brown64a55af2012-08-26 02:47:39 -070049 public static final Parcelable.Creator<Surface> CREATOR =
50 new Parcelable.Creator<Surface>() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -070051 @Override
Jeff Brown64a55af2012-08-26 02:47:39 -070052 public Surface createFromParcel(Parcel source) {
53 try {
54 Surface s = new Surface();
55 s.readFromParcel(source);
56 return s;
57 } catch (Exception e) {
58 Log.e(TAG, "Exception creating surface from parcel", e);
59 return null;
60 }
Kevin Hesterb85c9332012-03-08 17:06:56 -080061 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -070062
63 @Override
Jeff Brown64a55af2012-08-26 02:47:39 -070064 public Surface[] newArray(int size) {
65 return new Surface[size];
66 }
67 };
Kevin Hesterb85c9332012-03-08 17:06:56 -080068
Jeff Brown64a55af2012-08-26 02:47:39 -070069 private final CloseGuard mCloseGuard = CloseGuard.get();
Jeff Brownfc0ebd72013-04-30 16:33:00 -070070
71 // Guarded state.
72 final Object mLock = new Object(); // protects the native state
Jeff Brown64a55af2012-08-26 02:47:39 -070073 private String mName;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080074 int mNativeObject; // package scope only for SurfaceControl access
Jeff Brownfc0ebd72013-04-30 16:33:00 -070075 private int mGenerationId; // incremented each time mNativeObject changes
Jeff Brown64a55af2012-08-26 02:47:39 -070076 private final Canvas mCanvas = new CompatibleCanvas();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077
Mitsuru Oshima240f8a72009-07-22 20:39:14 -070078 // A matrix to scale the matrix set by application. This is set to null for
79 // non compatibility mode.
80 private Matrix mCompatibleMatrix;
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -070081
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 /**
Mathias Agopian29479eb2013-02-14 14:36:04 -080083 * Rotation constant: 0 degree rotation (natural orientation)
84 */
85 public static final int ROTATION_0 = 0;
86
87 /**
88 * Rotation constant: 90 degree rotation.
89 */
90 public static final int ROTATION_90 = 1;
91
92 /**
93 * Rotation constant: 180 degree rotation.
94 */
95 public static final int ROTATION_180 = 2;
96
97 /**
98 * Rotation constant: 270 degree rotation.
99 */
100 public static final int ROTATION_270 = 3;
101
Mathias Agopian29479eb2013-02-14 14:36:04 -0800102 /**
Jeff Brown64a55af2012-08-26 02:47:39 -0700103 * Create an empty surface, which will later be filled in by readFromParcel().
Mathias Agopianb9230662011-08-03 14:44:48 -0700104 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 */
106 public Surface() {
Jeff Brown64a55af2012-08-26 02:47:39 -0700107 }
108
109 /**
110 * Create Surface from a {@link SurfaceTexture}.
111 *
112 * Images drawn to the Surface will be made available to the {@link
113 * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
114 * SurfaceTexture#updateTexImage}.
115 *
116 * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
117 * Surface.
118 */
119 public Surface(SurfaceTexture surfaceTexture) {
120 if (surfaceTexture == null) {
121 throw new IllegalArgumentException("surfaceTexture must not be null");
122 }
123
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700124 synchronized (mLock) {
125 mName = surfaceTexture.toString();
126 try {
127 setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
128 } catch (OutOfResourcesException ex) {
129 // We can't throw OutOfResourcesException because it would be an API change.
130 throw new RuntimeException(ex);
131 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700132 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700133 }
134
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700135 /* called from android_view_Surface_createFromIGraphicBufferProducer() */
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800136 private Surface(int nativeObject) {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700137 synchronized (mLock) {
138 setNativeObjectLocked(nativeObject);
139 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800140 }
141
Jeff Brown64a55af2012-08-26 02:47:39 -0700142 @Override
143 protected void finalize() throws Throwable {
144 try {
145 if (mCloseGuard != null) {
146 mCloseGuard.warnIfOpen();
147 }
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700148 release();
Jeff Brown64a55af2012-08-26 02:47:39 -0700149 } finally {
150 super.finalize();
151 }
152 }
153
154 /**
155 * Release the local reference to the server-side surface.
156 * Always call release() when you're done with a Surface.
157 * This will make the surface invalid.
158 */
159 public void release() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700160 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700161 if (mNativeObject != 0) {
162 nativeRelease(mNativeObject);
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700163 setNativeObjectLocked(0);
Mathias Agopian7c116b52013-03-18 20:27:02 -0700164 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800165 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700166 }
167
168 /**
169 * Free all server-side state associated with this surface and
170 * release this object's reference. This method can only be
171 * called from the process that created the service.
172 * @hide
173 */
174 public void destroy() {
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700175 release();
Jeff Brown64a55af2012-08-26 02:47:39 -0700176 }
177
178 /**
179 * Returns true if this object holds a valid surface.
180 *
181 * @return True if it holds a physical surface, so lockCanvas() will succeed.
182 * Otherwise returns false.
183 */
184 public boolean isValid() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700185 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700186 if (mNativeObject == 0) return false;
187 return nativeIsValid(mNativeObject);
188 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700189 }
190
191 /**
192 * Gets the generation number of this surface, incremented each time
193 * the native surface contained within this object changes.
194 *
195 * @return The current generation number.
196 * @hide
197 */
198 public int getGenerationId() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700199 synchronized (mLock) {
200 return mGenerationId;
201 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700202 }
203
204 /**
205 * Returns true if the consumer of this Surface is running behind the producer.
206 *
207 * @return True if the consumer is more than one buffer ahead of the producer.
208 * @hide
209 */
210 public boolean isConsumerRunningBehind() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700211 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700212 checkNotReleasedLocked();
213 return nativeIsConsumerRunningBehind(mNativeObject);
214 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700215 }
216
217 /**
218 * Gets a {@link Canvas} for drawing into this surface.
219 *
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700220 * After drawing into the provided {@link Canvas}, the caller must
Jeff Brown64a55af2012-08-26 02:47:39 -0700221 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
222 *
Mathias Agopian30d7ab92013-02-14 15:38:40 -0800223 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
Jeff Brown64a55af2012-08-26 02:47:39 -0700224 * to redraw. This function may choose to expand the dirty rectangle if for example
225 * the surface has been resized or if the previous contents of the surface were
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700226 * not available. The caller must redraw the entire dirty region as represented
227 * by the contents of the inOutDirty rectangle upon return from this function.
Jeff Brown64a55af2012-08-26 02:47:39 -0700228 * The caller may also pass <code>null</code> instead, in the case where the
229 * entire surface should be redrawn.
230 * @return A canvas for drawing into the surface.
231 */
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800232 public Canvas lockCanvas(Rect inOutDirty)
Jeff Brown64a55af2012-08-26 02:47:39 -0700233 throws OutOfResourcesException, IllegalArgumentException {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700234 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700235 checkNotReleasedLocked();
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700236 nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
237 return mCanvas;
Mathias Agopian7c116b52013-03-18 20:27:02 -0700238 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700239 }
240
241 /**
242 * Posts the new contents of the {@link Canvas} to the surface and
243 * releases the {@link Canvas}.
244 *
245 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
246 */
247 public void unlockCanvasAndPost(Canvas canvas) {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700248 if (canvas != mCanvas) {
249 throw new IllegalArgumentException("canvas object must be the same instance that "
250 + "was previously returned by lockCanvas");
251 }
252
253 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700254 checkNotReleasedLocked();
255 nativeUnlockCanvasAndPost(mNativeObject, canvas);
256 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700257 }
258
259 /**
260 * @deprecated This API has been removed and is not supported. Do not use.
261 */
262 @Deprecated
263 public void unlockCanvas(Canvas canvas) {
264 throw new UnsupportedOperationException();
265 }
266
267 /**
268 * Sets the translator used to scale canvas's width/height in compatibility
269 * mode.
270 */
271 void setCompatibilityTranslator(Translator translator) {
272 if (translator != null) {
273 float appScale = translator.applicationScale;
274 mCompatibleMatrix = new Matrix();
275 mCompatibleMatrix.setScale(appScale, appScale);
276 }
277 }
278
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700279 /**
Mathias Agopianb9230662011-08-03 14:44:48 -0700280 * Copy another surface to this one. This surface now holds a reference
281 * to the same data as the original surface, and is -not- the owner.
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800282 * This is for use by the window manager when returning a window surface
283 * back from a client, converting it from the representation being managed
284 * by the window manager to the representation the client uses to draw
285 * in to it.
Mathias Agopianb9230662011-08-03 14:44:48 -0700286 * @hide
287 */
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800288 public void copyFrom(SurfaceControl other) {
Jeff Brown64a55af2012-08-26 02:47:39 -0700289 if (other == null) {
290 throw new IllegalArgumentException("other must not be null");
291 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700292
293 int surfaceControlPtr = other.mNativeObject;
294 if (surfaceControlPtr == 0) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800295 throw new NullPointerException(
296 "SurfaceControl native object is null. Are you using a released SurfaceControl?");
Jeff Brown64a55af2012-08-26 02:47:39 -0700297 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700298 int newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
299
300 synchronized (mLock) {
301 if (mNativeObject != 0) {
302 nativeRelease(mNativeObject);
Mathias Agopian7c116b52013-03-18 20:27:02 -0700303 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700304 setNativeObjectLocked(newNativeObject);
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700305 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700306 }
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800307
308 /**
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700309 * This is intended to be used by {@link SurfaceView#updateWindow} only.
Mathias Agopian7c116b52013-03-18 20:27:02 -0700310 * @param other access is not thread safe
311 * @hide
312 * @deprecated
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800313 */
Mathias Agopian7c116b52013-03-18 20:27:02 -0700314 @Deprecated
Jeff Brown64a55af2012-08-26 02:47:39 -0700315 public void transferFrom(Surface other) {
316 if (other == null) {
317 throw new IllegalArgumentException("other must not be null");
318 }
319 if (other != this) {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700320 final int newPtr;
321 synchronized (other.mLock) {
322 newPtr = other.mNativeObject;
323 other.setNativeObjectLocked(0);
324 }
325
326 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700327 if (mNativeObject != 0) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700328 nativeRelease(mNativeObject);
329 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700330 setNativeObjectLocked(newPtr);
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800331 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700332 }
Mathias Agopianb9230662011-08-03 14:44:48 -0700333 }
334
Jeff Brown64a55af2012-08-26 02:47:39 -0700335 @Override
336 public int describeContents() {
337 return 0;
338 }
339
340 public void readFromParcel(Parcel source) {
341 if (source == null) {
342 throw new IllegalArgumentException("source must not be null");
343 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700344
345 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700346 mName = source.readString();
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700347 setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700348 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700349 }
350
351 @Override
352 public void writeToParcel(Parcel dest, int flags) {
353 if (dest == null) {
354 throw new IllegalArgumentException("dest must not be null");
355 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700356 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700357 dest.writeString(mName);
358 nativeWriteToParcel(mNativeObject, dest);
359 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700360 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
361 release();
362 }
363 }
364
365 @Override
366 public String toString() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700367 synchronized (mLock) {
368 return "Surface(name=" + mName + ")";
369 }
370 }
371
372 private void setNativeObjectLocked(int ptr) {
373 if (mNativeObject != ptr) {
374 if (mNativeObject == 0 && ptr != 0) {
375 mCloseGuard.open("release");
376 } else if (mNativeObject != 0 && ptr == 0) {
377 mCloseGuard.close();
378 }
379 mNativeObject = ptr;
380 mGenerationId += 1;
381 }
382 }
383
384 private void checkNotReleasedLocked() {
385 if (mNativeObject == 0) {
386 throw new IllegalStateException("Surface has already been released.");
387 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700388 }
389
Mathias Agopianc14bacf2012-04-23 18:23:08 -0700390 /**
Jeff Brown64a55af2012-08-26 02:47:39 -0700391 * Exception thrown when a surface couldn't be created or resized.
392 */
393 public static class OutOfResourcesException extends Exception {
394 public OutOfResourcesException() {
395 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700396 public OutOfResourcesException(String name) {
397 super(name);
398 }
399 }
400
401 /**
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -0700402 * Returns a human readable representation of a rotation.
403 *
404 * @param rotation The rotation.
405 * @return The rotation symbolic name.
Svetoslav Ganov545252f2012-12-10 18:29:24 -0800406 *
407 * @hide
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -0700408 */
409 public static String rotationToString(int rotation) {
410 switch (rotation) {
411 case Surface.ROTATION_0: {
412 return "ROTATION_0";
413 }
414 case Surface.ROTATION_90: {
415 return "ROATATION_90";
416 }
417 case Surface.ROTATION_180: {
418 return "ROATATION_180";
419 }
420 case Surface.ROTATION_270: {
421 return "ROATATION_270";
422 }
423 default: {
424 throw new IllegalArgumentException("Invalid rotation: " + rotation);
425 }
426 }
427 }
428
429 /**
Jeff Brown64a55af2012-08-26 02:47:39 -0700430 * A Canvas class that can handle the compatibility mode.
431 * This does two things differently.
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700432 * <ul>
Mathias Agopianb9230662011-08-03 14:44:48 -0700433 * <li>Returns the width and height of the target metrics, rather than
434 * native. For example, the canvas returns 320x480 even if an app is running
435 * in WVGA high density.
436 * <li>Scales the matrix in setMatrix by the application scale, except if
437 * the matrix looks like obtained from getMatrix. This is a hack to handle
438 * the case that an application uses getMatrix to keep the original matrix,
439 * set matrix of its own, then set the original matrix back. There is no
440 * perfect solution that works for all cases, and there are a lot of cases
441 * that this model does not work, but we hope this works for many apps.
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700442 * </ul>
443 */
Jeff Brown64a55af2012-08-26 02:47:39 -0700444 private final class CompatibleCanvas extends Canvas {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700445 // A temp matrix to remember what an application obtained via {@link getMatrix}
446 private Matrix mOrigMatrix = null;
447
448 @Override
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700449 public void setMatrix(Matrix matrix) {
450 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
451 // don't scale the matrix if it's not compatibility mode, or
452 // the matrix was obtained from getMatrix.
453 super.setMatrix(matrix);
454 } else {
455 Matrix m = new Matrix(mCompatibleMatrix);
456 m.preConcat(matrix);
457 super.setMatrix(m);
458 }
459 }
460
Romain Guy8b5aa482013-02-28 18:13:54 -0800461 @SuppressWarnings("deprecation")
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700462 @Override
463 public void getMatrix(Matrix m) {
464 super.getMatrix(m);
465 if (mOrigMatrix == null) {
466 mOrigMatrix = new Matrix();
467 }
468 mOrigMatrix.set(m);
469 }
Romain Guyd10cd572010-10-10 13:33:22 -0700470 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471}