blob: fdaae01ee27a9e7a3145638fefb9e4ef2254b1b9 [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
Tor Norbyed9273d62013-05-30 15:59:53 -070019import android.annotation.IntDef;
Mitsuru Oshima240f8a72009-07-22 20:39:14 -070020import android.content.res.CompatibilityInfo.Translator;
Jeff Brown0b722fe2012-08-24 22:40:14 -070021import android.graphics.Canvas;
22import android.graphics.Matrix;
23import android.graphics.Rect;
Jeff Brown0b722fe2012-08-24 22:40:14 -070024import android.graphics.SurfaceTexture;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.os.Parcel;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080026import android.os.Parcelable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.util.Log;
Tor Norbyed9273d62013-05-30 15:59:53 -070028
29import java.lang.annotation.Retention;
30import java.lang.annotation.RetentionPolicy;
31
Mathias Agopian3866f0d2013-02-11 22:08:48 -080032import dalvik.system.CloseGuard;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
34/**
Glenn Kasten334031c2010-11-09 21:54:38 -080035 * Handle onto a raw buffer that is being managed by the screen compositor.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 */
37public class Surface implements Parcelable {
Jeff Brown64a55af2012-08-26 02:47:39 -070038 private static final String TAG = "Surface";
Mathias Agopianb9230662011-08-03 14:44:48 -070039
Ashok Bhat36bef0b2014-01-20 20:08:01 +000040 private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
Mathias Agopian29479eb2013-02-14 14:36:04 -080041 throws OutOfResourcesException;
Ashok Bhat36bef0b2014-01-20 20:08:01 +000042 private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject);
Mathias Agopian52800612013-02-14 17:11:20 -080043
Ashok Bhat36bef0b2014-01-20 20:08:01 +000044 private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
Jeff Brownfc0ebd72013-04-30 16:33:00 -070045 throws OutOfResourcesException;
Ashok Bhat36bef0b2014-01-20 20:08:01 +000046 private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
Mathias Agopian29479eb2013-02-14 14:36:04 -080047
Ashok Bhat36bef0b2014-01-20 20:08:01 +000048 private static native void nativeRelease(long nativeObject);
49 private static native boolean nativeIsValid(long nativeObject);
50 private static native boolean nativeIsConsumerRunningBehind(long nativeObject);
51 private static native long nativeReadFromParcel(long nativeObject, Parcel source);
52 private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
Mathias Agopian29479eb2013-02-14 14:36:04 -080053
Jeff Brown64a55af2012-08-26 02:47:39 -070054 public static final Parcelable.Creator<Surface> CREATOR =
55 new Parcelable.Creator<Surface>() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -070056 @Override
Jeff Brown64a55af2012-08-26 02:47:39 -070057 public Surface createFromParcel(Parcel source) {
58 try {
59 Surface s = new Surface();
60 s.readFromParcel(source);
61 return s;
62 } catch (Exception e) {
63 Log.e(TAG, "Exception creating surface from parcel", e);
64 return null;
65 }
Kevin Hesterb85c9332012-03-08 17:06:56 -080066 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -070067
68 @Override
Jeff Brown64a55af2012-08-26 02:47:39 -070069 public Surface[] newArray(int size) {
70 return new Surface[size];
71 }
72 };
Kevin Hesterb85c9332012-03-08 17:06:56 -080073
Jeff Brown64a55af2012-08-26 02:47:39 -070074 private final CloseGuard mCloseGuard = CloseGuard.get();
Jeff Brownfc0ebd72013-04-30 16:33:00 -070075
76 // Guarded state.
77 final Object mLock = new Object(); // protects the native state
Jeff Brown64a55af2012-08-26 02:47:39 -070078 private String mName;
Ashok Bhat36bef0b2014-01-20 20:08:01 +000079 long mNativeObject; // package scope only for SurfaceControl access
80 private long mLockedObject;
Jeff Brownfc0ebd72013-04-30 16:33:00 -070081 private int mGenerationId; // incremented each time mNativeObject changes
Jeff Brown64a55af2012-08-26 02:47:39 -070082 private final Canvas mCanvas = new CompatibleCanvas();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
Mitsuru Oshima240f8a72009-07-22 20:39:14 -070084 // A matrix to scale the matrix set by application. This is set to null for
85 // non compatibility mode.
86 private Matrix mCompatibleMatrix;
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -070087
Tor Norbyed9273d62013-05-30 15:59:53 -070088 /** @hide */
89 @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
90 @Retention(RetentionPolicy.SOURCE)
91 public @interface Rotation {}
92
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 /**
Mathias Agopian29479eb2013-02-14 14:36:04 -080094 * Rotation constant: 0 degree rotation (natural orientation)
95 */
96 public static final int ROTATION_0 = 0;
97
98 /**
99 * Rotation constant: 90 degree rotation.
100 */
101 public static final int ROTATION_90 = 1;
102
103 /**
104 * Rotation constant: 180 degree rotation.
105 */
106 public static final int ROTATION_180 = 2;
107
108 /**
109 * Rotation constant: 270 degree rotation.
110 */
111 public static final int ROTATION_270 = 3;
112
Mathias Agopian29479eb2013-02-14 14:36:04 -0800113 /**
Jeff Brown64a55af2012-08-26 02:47:39 -0700114 * Create an empty surface, which will later be filled in by readFromParcel().
Mathias Agopianb9230662011-08-03 14:44:48 -0700115 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 */
117 public Surface() {
Jeff Brown64a55af2012-08-26 02:47:39 -0700118 }
119
120 /**
121 * Create Surface from a {@link SurfaceTexture}.
122 *
123 * Images drawn to the Surface will be made available to the {@link
124 * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
125 * SurfaceTexture#updateTexImage}.
126 *
127 * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
128 * Surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700129 * @throws OutOfResourcesException if the surface could not be created.
Jeff Brown64a55af2012-08-26 02:47:39 -0700130 */
131 public Surface(SurfaceTexture surfaceTexture) {
132 if (surfaceTexture == null) {
133 throw new IllegalArgumentException("surfaceTexture must not be null");
134 }
135
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700136 synchronized (mLock) {
137 mName = surfaceTexture.toString();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700138 setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
Jeff Brown64a55af2012-08-26 02:47:39 -0700139 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700140 }
141
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700142 /* called from android_view_Surface_createFromIGraphicBufferProducer() */
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000143 private Surface(long nativeObject) {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700144 synchronized (mLock) {
145 setNativeObjectLocked(nativeObject);
146 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800147 }
148
Jeff Brown64a55af2012-08-26 02:47:39 -0700149 @Override
150 protected void finalize() throws Throwable {
151 try {
152 if (mCloseGuard != null) {
153 mCloseGuard.warnIfOpen();
154 }
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700155 release();
Jeff Brown64a55af2012-08-26 02:47:39 -0700156 } finally {
157 super.finalize();
158 }
159 }
160
161 /**
162 * Release the local reference to the server-side surface.
163 * Always call release() when you're done with a Surface.
164 * This will make the surface invalid.
165 */
166 public void release() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700167 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700168 if (mNativeObject != 0) {
169 nativeRelease(mNativeObject);
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700170 setNativeObjectLocked(0);
Mathias Agopian7c116b52013-03-18 20:27:02 -0700171 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800172 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700173 }
174
175 /**
176 * Free all server-side state associated with this surface and
177 * release this object's reference. This method can only be
178 * called from the process that created the service.
179 * @hide
180 */
181 public void destroy() {
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700182 release();
Jeff Brown64a55af2012-08-26 02:47:39 -0700183 }
184
185 /**
186 * Returns true if this object holds a valid surface.
187 *
188 * @return True if it holds a physical surface, so lockCanvas() will succeed.
189 * Otherwise returns false.
190 */
191 public boolean isValid() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700192 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700193 if (mNativeObject == 0) return false;
194 return nativeIsValid(mNativeObject);
195 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700196 }
197
198 /**
199 * Gets the generation number of this surface, incremented each time
200 * the native surface contained within this object changes.
201 *
202 * @return The current generation number.
203 * @hide
204 */
205 public int getGenerationId() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700206 synchronized (mLock) {
207 return mGenerationId;
208 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700209 }
210
211 /**
212 * Returns true if the consumer of this Surface is running behind the producer.
213 *
214 * @return True if the consumer is more than one buffer ahead of the producer.
215 * @hide
216 */
217 public boolean isConsumerRunningBehind() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700218 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700219 checkNotReleasedLocked();
220 return nativeIsConsumerRunningBehind(mNativeObject);
221 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700222 }
223
224 /**
225 * Gets a {@link Canvas} for drawing into this surface.
226 *
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700227 * After drawing into the provided {@link Canvas}, the caller must
Jeff Brown64a55af2012-08-26 02:47:39 -0700228 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
229 *
Mathias Agopian30d7ab92013-02-14 15:38:40 -0800230 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
Jeff Brown64a55af2012-08-26 02:47:39 -0700231 * to redraw. This function may choose to expand the dirty rectangle if for example
232 * the surface has been resized or if the previous contents of the surface were
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700233 * not available. The caller must redraw the entire dirty region as represented
234 * by the contents of the inOutDirty rectangle upon return from this function.
Jeff Brown64a55af2012-08-26 02:47:39 -0700235 * The caller may also pass <code>null</code> instead, in the case where the
236 * entire surface should be redrawn.
237 * @return A canvas for drawing into the surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700238 *
239 * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
240 * @throws OutOfResourcesException If the canvas cannot be locked.
Jeff Brown64a55af2012-08-26 02:47:39 -0700241 */
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800242 public Canvas lockCanvas(Rect inOutDirty)
Igor Murashkina86ab6402013-08-30 12:58:36 -0700243 throws Surface.OutOfResourcesException, IllegalArgumentException {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700244 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700245 checkNotReleasedLocked();
Andy McFaddened55c8d2013-08-20 10:05:51 -0700246 if (mLockedObject != 0) {
247 // Ideally, nativeLockCanvas() would throw in this situation and prevent the
248 // double-lock, but that won't happen if mNativeObject was updated. We can't
249 // abandon the old mLockedObject because it might still be in use, so instead
250 // we just refuse to re-lock the Surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700251 throw new IllegalStateException("Surface was already locked");
Andy McFaddened55c8d2013-08-20 10:05:51 -0700252 }
253 mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700254 return mCanvas;
Mathias Agopian7c116b52013-03-18 20:27:02 -0700255 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700256 }
257
258 /**
259 * Posts the new contents of the {@link Canvas} to the surface and
260 * releases the {@link Canvas}.
261 *
262 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
263 */
264 public void unlockCanvasAndPost(Canvas canvas) {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700265 if (canvas != mCanvas) {
266 throw new IllegalArgumentException("canvas object must be the same instance that "
267 + "was previously returned by lockCanvas");
268 }
269
270 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700271 checkNotReleasedLocked();
Andy McFaddened55c8d2013-08-20 10:05:51 -0700272 if (mNativeObject != mLockedObject) {
273 Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000274 Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
275 Long.toHexString(mLockedObject) +")");
Andy McFaddened55c8d2013-08-20 10:05:51 -0700276 }
277 if (mLockedObject == 0) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700278 throw new IllegalStateException("Surface was not locked");
Andy McFaddened55c8d2013-08-20 10:05:51 -0700279 }
280 nativeUnlockCanvasAndPost(mLockedObject, canvas);
281 nativeRelease(mLockedObject);
282 mLockedObject = 0;
Mathias Agopian7c116b52013-03-18 20:27:02 -0700283 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700284 }
285
Andy McFaddened55c8d2013-08-20 10:05:51 -0700286 /**
Jeff Brown64a55af2012-08-26 02:47:39 -0700287 * @deprecated This API has been removed and is not supported. Do not use.
288 */
289 @Deprecated
290 public void unlockCanvas(Canvas canvas) {
291 throw new UnsupportedOperationException();
292 }
293
294 /**
295 * Sets the translator used to scale canvas's width/height in compatibility
296 * mode.
297 */
298 void setCompatibilityTranslator(Translator translator) {
299 if (translator != null) {
300 float appScale = translator.applicationScale;
301 mCompatibleMatrix = new Matrix();
302 mCompatibleMatrix.setScale(appScale, appScale);
303 }
304 }
305
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700306 /**
Mathias Agopianb9230662011-08-03 14:44:48 -0700307 * Copy another surface to this one. This surface now holds a reference
308 * to the same data as the original surface, and is -not- the owner.
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800309 * This is for use by the window manager when returning a window surface
310 * back from a client, converting it from the representation being managed
311 * by the window manager to the representation the client uses to draw
312 * in to it.
Mathias Agopianb9230662011-08-03 14:44:48 -0700313 * @hide
314 */
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800315 public void copyFrom(SurfaceControl other) {
Jeff Brown64a55af2012-08-26 02:47:39 -0700316 if (other == null) {
317 throw new IllegalArgumentException("other must not be null");
318 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700319
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000320 long surfaceControlPtr = other.mNativeObject;
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700321 if (surfaceControlPtr == 0) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800322 throw new NullPointerException(
323 "SurfaceControl native object is null. Are you using a released SurfaceControl?");
Jeff Brown64a55af2012-08-26 02:47:39 -0700324 }
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000325 long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700326
327 synchronized (mLock) {
328 if (mNativeObject != 0) {
329 nativeRelease(mNativeObject);
Mathias Agopian7c116b52013-03-18 20:27:02 -0700330 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700331 setNativeObjectLocked(newNativeObject);
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700332 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700333 }
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800334
335 /**
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700336 * This is intended to be used by {@link SurfaceView#updateWindow} only.
Mathias Agopian7c116b52013-03-18 20:27:02 -0700337 * @param other access is not thread safe
338 * @hide
339 * @deprecated
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800340 */
Mathias Agopian7c116b52013-03-18 20:27:02 -0700341 @Deprecated
Jeff Brown64a55af2012-08-26 02:47:39 -0700342 public void transferFrom(Surface other) {
343 if (other == null) {
344 throw new IllegalArgumentException("other must not be null");
345 }
346 if (other != this) {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000347 final long newPtr;
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700348 synchronized (other.mLock) {
349 newPtr = other.mNativeObject;
350 other.setNativeObjectLocked(0);
351 }
352
353 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700354 if (mNativeObject != 0) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700355 nativeRelease(mNativeObject);
356 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700357 setNativeObjectLocked(newPtr);
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800358 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700359 }
Mathias Agopianb9230662011-08-03 14:44:48 -0700360 }
361
Jeff Brown64a55af2012-08-26 02:47:39 -0700362 @Override
363 public int describeContents() {
364 return 0;
365 }
366
367 public void readFromParcel(Parcel source) {
368 if (source == null) {
369 throw new IllegalArgumentException("source must not be null");
370 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700371
372 synchronized (mLock) {
Andy McFaddened55c8d2013-08-20 10:05:51 -0700373 // nativeReadFromParcel() will either return mNativeObject, or
374 // create a new native Surface and return it after reducing
375 // the reference count on mNativeObject. Either way, it is
376 // not necessary to call nativeRelease() here.
Mathias Agopian7c116b52013-03-18 20:27:02 -0700377 mName = source.readString();
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700378 setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700379 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700380 }
381
382 @Override
383 public void writeToParcel(Parcel dest, int flags) {
384 if (dest == null) {
385 throw new IllegalArgumentException("dest must not be null");
386 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700387 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700388 dest.writeString(mName);
389 nativeWriteToParcel(mNativeObject, dest);
390 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700391 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
392 release();
393 }
394 }
395
396 @Override
397 public String toString() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700398 synchronized (mLock) {
Andy McFaddened55c8d2013-08-20 10:05:51 -0700399 return "Surface(name=" + mName + ")/@0x" +
400 Integer.toHexString(System.identityHashCode(this));
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700401 }
402 }
403
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000404 private void setNativeObjectLocked(long ptr) {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700405 if (mNativeObject != ptr) {
406 if (mNativeObject == 0 && ptr != 0) {
407 mCloseGuard.open("release");
408 } else if (mNativeObject != 0 && ptr == 0) {
409 mCloseGuard.close();
410 }
411 mNativeObject = ptr;
412 mGenerationId += 1;
413 }
414 }
415
416 private void checkNotReleasedLocked() {
417 if (mNativeObject == 0) {
418 throw new IllegalStateException("Surface has already been released.");
419 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700420 }
421
Mathias Agopianc14bacf2012-04-23 18:23:08 -0700422 /**
Igor Murashkina86ab6402013-08-30 12:58:36 -0700423 * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
424 * when a SurfaceTexture could not successfully be allocated.
Jeff Brown64a55af2012-08-26 02:47:39 -0700425 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700426 @SuppressWarnings("serial")
427 public static class OutOfResourcesException extends RuntimeException {
Jeff Brown64a55af2012-08-26 02:47:39 -0700428 public OutOfResourcesException() {
429 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700430 public OutOfResourcesException(String name) {
431 super(name);
432 }
433 }
434
435 /**
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -0700436 * Returns a human readable representation of a rotation.
437 *
438 * @param rotation The rotation.
439 * @return The rotation symbolic name.
Svetoslav Ganov545252f2012-12-10 18:29:24 -0800440 *
441 * @hide
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -0700442 */
443 public static String rotationToString(int rotation) {
444 switch (rotation) {
445 case Surface.ROTATION_0: {
446 return "ROTATION_0";
447 }
448 case Surface.ROTATION_90: {
449 return "ROATATION_90";
450 }
451 case Surface.ROTATION_180: {
452 return "ROATATION_180";
453 }
454 case Surface.ROTATION_270: {
455 return "ROATATION_270";
456 }
457 default: {
458 throw new IllegalArgumentException("Invalid rotation: " + rotation);
459 }
460 }
461 }
462
463 /**
Jeff Brown64a55af2012-08-26 02:47:39 -0700464 * A Canvas class that can handle the compatibility mode.
465 * This does two things differently.
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700466 * <ul>
Mathias Agopianb9230662011-08-03 14:44:48 -0700467 * <li>Returns the width and height of the target metrics, rather than
468 * native. For example, the canvas returns 320x480 even if an app is running
469 * in WVGA high density.
470 * <li>Scales the matrix in setMatrix by the application scale, except if
471 * the matrix looks like obtained from getMatrix. This is a hack to handle
472 * the case that an application uses getMatrix to keep the original matrix,
473 * set matrix of its own, then set the original matrix back. There is no
474 * perfect solution that works for all cases, and there are a lot of cases
475 * that this model does not work, but we hope this works for many apps.
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700476 * </ul>
477 */
Jeff Brown64a55af2012-08-26 02:47:39 -0700478 private final class CompatibleCanvas extends Canvas {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700479 // A temp matrix to remember what an application obtained via {@link getMatrix}
480 private Matrix mOrigMatrix = null;
481
482 @Override
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700483 public void setMatrix(Matrix matrix) {
484 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
485 // don't scale the matrix if it's not compatibility mode, or
486 // the matrix was obtained from getMatrix.
487 super.setMatrix(matrix);
488 } else {
489 Matrix m = new Matrix(mCompatibleMatrix);
490 m.preConcat(matrix);
491 super.setMatrix(m);
492 }
493 }
494
Romain Guy8b5aa482013-02-28 18:13:54 -0800495 @SuppressWarnings("deprecation")
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700496 @Override
497 public void getMatrix(Matrix m) {
498 super.getMatrix(m);
499 if (mOrigMatrix == null) {
Andy McFaddened55c8d2013-08-20 10:05:51 -0700500 mOrigMatrix = new Matrix();
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700501 }
502 mOrigMatrix.set(m);
503 }
Romain Guyd10cd572010-10-10 13:33:22 -0700504 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505}