blob: 91645e73c0718f4a78411da4a5152a6a3c64ed77 [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
Ashok Bhata0398432014-01-20 20:08:01 +000035 private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
Mathias Agopian29479eb2013-02-14 14:36:04 -080036 throws OutOfResourcesException;
Ashok Bhata0398432014-01-20 20:08:01 +000037 private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject);
Mathias Agopian52800612013-02-14 17:11:20 -080038
Ashok Bhata0398432014-01-20 20:08:01 +000039 private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
Jeff Brownfc0ebd72013-04-30 16:33:00 -070040 throws OutOfResourcesException;
Ashok Bhata0398432014-01-20 20:08:01 +000041 private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
Mathias Agopian29479eb2013-02-14 14:36:04 -080042
Ashok Bhata0398432014-01-20 20:08:01 +000043 private static native void nativeRelease(long nativeObject);
44 private static native boolean nativeIsValid(long nativeObject);
45 private static native boolean nativeIsConsumerRunningBehind(long nativeObject);
46 private static native long nativeReadFromParcel(long nativeObject, Parcel source);
47 private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
Mathias Agopian29479eb2013-02-14 14:36:04 -080048
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;
Ashok Bhata0398432014-01-20 20:08:01 +000074 long mNativeObject; // package scope only for SurfaceControl access
75 private long mLockedObject;
Jeff Brownfc0ebd72013-04-30 16:33:00 -070076 private int mGenerationId; // incremented each time mNativeObject changes
Jeff Brown64a55af2012-08-26 02:47:39 -070077 private final Canvas mCanvas = new CompatibleCanvas();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
Mitsuru Oshima240f8a72009-07-22 20:39:14 -070079 // A matrix to scale the matrix set by application. This is set to null for
80 // non compatibility mode.
81 private Matrix mCompatibleMatrix;
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -070082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 /**
Mathias Agopian29479eb2013-02-14 14:36:04 -080084 * Rotation constant: 0 degree rotation (natural orientation)
85 */
86 public static final int ROTATION_0 = 0;
87
88 /**
89 * Rotation constant: 90 degree rotation.
90 */
91 public static final int ROTATION_90 = 1;
92
93 /**
94 * Rotation constant: 180 degree rotation.
95 */
96 public static final int ROTATION_180 = 2;
97
98 /**
99 * Rotation constant: 270 degree rotation.
100 */
101 public static final int ROTATION_270 = 3;
102
Mathias Agopian29479eb2013-02-14 14:36:04 -0800103 /**
Jeff Brown64a55af2012-08-26 02:47:39 -0700104 * Create an empty surface, which will later be filled in by readFromParcel().
Mathias Agopianb9230662011-08-03 14:44:48 -0700105 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 */
107 public Surface() {
Jeff Brown64a55af2012-08-26 02:47:39 -0700108 }
109
110 /**
111 * Create Surface from a {@link SurfaceTexture}.
112 *
113 * Images drawn to the Surface will be made available to the {@link
114 * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
115 * SurfaceTexture#updateTexImage}.
116 *
117 * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
118 * Surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700119 * @throws OutOfResourcesException if the surface could not be created.
Jeff Brown64a55af2012-08-26 02:47:39 -0700120 */
121 public Surface(SurfaceTexture surfaceTexture) {
122 if (surfaceTexture == null) {
123 throw new IllegalArgumentException("surfaceTexture must not be null");
124 }
125
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700126 synchronized (mLock) {
127 mName = surfaceTexture.toString();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700128 setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
Jeff Brown64a55af2012-08-26 02:47:39 -0700129 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700130 }
131
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700132 /* called from android_view_Surface_createFromIGraphicBufferProducer() */
Ashok Bhata0398432014-01-20 20:08:01 +0000133 private Surface(long nativeObject) {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700134 synchronized (mLock) {
135 setNativeObjectLocked(nativeObject);
136 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800137 }
138
Jeff Brown64a55af2012-08-26 02:47:39 -0700139 @Override
140 protected void finalize() throws Throwable {
141 try {
142 if (mCloseGuard != null) {
143 mCloseGuard.warnIfOpen();
144 }
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700145 release();
Jeff Brown64a55af2012-08-26 02:47:39 -0700146 } finally {
147 super.finalize();
148 }
149 }
150
151 /**
152 * Release the local reference to the server-side surface.
153 * Always call release() when you're done with a Surface.
154 * This will make the surface invalid.
155 */
156 public void release() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700157 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700158 if (mNativeObject != 0) {
159 nativeRelease(mNativeObject);
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700160 setNativeObjectLocked(0);
Mathias Agopian7c116b52013-03-18 20:27:02 -0700161 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800162 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700163 }
164
165 /**
166 * Free all server-side state associated with this surface and
167 * release this object's reference. This method can only be
168 * called from the process that created the service.
169 * @hide
170 */
171 public void destroy() {
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700172 release();
Jeff Brown64a55af2012-08-26 02:47:39 -0700173 }
174
175 /**
176 * Returns true if this object holds a valid surface.
177 *
178 * @return True if it holds a physical surface, so lockCanvas() will succeed.
179 * Otherwise returns false.
180 */
181 public boolean isValid() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700182 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700183 if (mNativeObject == 0) return false;
184 return nativeIsValid(mNativeObject);
185 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700186 }
187
188 /**
189 * Gets the generation number of this surface, incremented each time
190 * the native surface contained within this object changes.
191 *
192 * @return The current generation number.
193 * @hide
194 */
195 public int getGenerationId() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700196 synchronized (mLock) {
197 return mGenerationId;
198 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700199 }
200
201 /**
202 * Returns true if the consumer of this Surface is running behind the producer.
203 *
204 * @return True if the consumer is more than one buffer ahead of the producer.
205 * @hide
206 */
207 public boolean isConsumerRunningBehind() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700208 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700209 checkNotReleasedLocked();
210 return nativeIsConsumerRunningBehind(mNativeObject);
211 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700212 }
213
214 /**
215 * Gets a {@link Canvas} for drawing into this surface.
216 *
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700217 * After drawing into the provided {@link Canvas}, the caller must
Jeff Brown64a55af2012-08-26 02:47:39 -0700218 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
219 *
Mathias Agopian30d7ab92013-02-14 15:38:40 -0800220 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
Jeff Brown64a55af2012-08-26 02:47:39 -0700221 * to redraw. This function may choose to expand the dirty rectangle if for example
222 * the surface has been resized or if the previous contents of the surface were
Mathias Agopian9ddf32a2013-04-17 15:04:47 -0700223 * not available. The caller must redraw the entire dirty region as represented
224 * by the contents of the inOutDirty rectangle upon return from this function.
Jeff Brown64a55af2012-08-26 02:47:39 -0700225 * The caller may also pass <code>null</code> instead, in the case where the
226 * entire surface should be redrawn.
227 * @return A canvas for drawing into the surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700228 *
229 * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
230 * @throws OutOfResourcesException If the canvas cannot be locked.
Jeff Brown64a55af2012-08-26 02:47:39 -0700231 */
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800232 public Canvas lockCanvas(Rect inOutDirty)
Igor Murashkina86ab6402013-08-30 12:58:36 -0700233 throws Surface.OutOfResourcesException, IllegalArgumentException {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700234 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700235 checkNotReleasedLocked();
Andy McFaddened55c8d2013-08-20 10:05:51 -0700236 if (mLockedObject != 0) {
237 // Ideally, nativeLockCanvas() would throw in this situation and prevent the
238 // double-lock, but that won't happen if mNativeObject was updated. We can't
239 // abandon the old mLockedObject because it might still be in use, so instead
240 // we just refuse to re-lock the Surface.
Igor Murashkina86ab6402013-08-30 12:58:36 -0700241 throw new IllegalStateException("Surface was already locked");
Andy McFaddened55c8d2013-08-20 10:05:51 -0700242 }
243 mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700244 return mCanvas;
Mathias Agopian7c116b52013-03-18 20:27:02 -0700245 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700246 }
247
248 /**
249 * Posts the new contents of the {@link Canvas} to the surface and
250 * releases the {@link Canvas}.
251 *
252 * @param canvas The canvas previously obtained from {@link #lockCanvas}.
253 */
254 public void unlockCanvasAndPost(Canvas canvas) {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700255 if (canvas != mCanvas) {
256 throw new IllegalArgumentException("canvas object must be the same instance that "
257 + "was previously returned by lockCanvas");
258 }
259
260 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700261 checkNotReleasedLocked();
Andy McFaddened55c8d2013-08-20 10:05:51 -0700262 if (mNativeObject != mLockedObject) {
263 Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
Ashok Bhata0398432014-01-20 20:08:01 +0000264 Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
265 Long.toHexString(mLockedObject) +")");
Andy McFaddened55c8d2013-08-20 10:05:51 -0700266 }
267 if (mLockedObject == 0) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700268 throw new IllegalStateException("Surface was not locked");
Andy McFaddened55c8d2013-08-20 10:05:51 -0700269 }
270 nativeUnlockCanvasAndPost(mLockedObject, canvas);
271 nativeRelease(mLockedObject);
272 mLockedObject = 0;
Mathias Agopian7c116b52013-03-18 20:27:02 -0700273 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700274 }
275
Andy McFaddened55c8d2013-08-20 10:05:51 -0700276 /**
Jeff Brown64a55af2012-08-26 02:47:39 -0700277 * @deprecated This API has been removed and is not supported. Do not use.
278 */
279 @Deprecated
280 public void unlockCanvas(Canvas canvas) {
281 throw new UnsupportedOperationException();
282 }
283
284 /**
285 * Sets the translator used to scale canvas's width/height in compatibility
286 * mode.
287 */
288 void setCompatibilityTranslator(Translator translator) {
289 if (translator != null) {
290 float appScale = translator.applicationScale;
291 mCompatibleMatrix = new Matrix();
292 mCompatibleMatrix.setScale(appScale, appScale);
293 }
294 }
295
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700296 /**
Mathias Agopianb9230662011-08-03 14:44:48 -0700297 * Copy another surface to this one. This surface now holds a reference
298 * to the same data as the original surface, and is -not- the owner.
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800299 * This is for use by the window manager when returning a window surface
300 * back from a client, converting it from the representation being managed
301 * by the window manager to the representation the client uses to draw
302 * in to it.
Mathias Agopianb9230662011-08-03 14:44:48 -0700303 * @hide
304 */
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800305 public void copyFrom(SurfaceControl other) {
Jeff Brown64a55af2012-08-26 02:47:39 -0700306 if (other == null) {
307 throw new IllegalArgumentException("other must not be null");
308 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700309
Ashok Bhata0398432014-01-20 20:08:01 +0000310 long surfaceControlPtr = other.mNativeObject;
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700311 if (surfaceControlPtr == 0) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800312 throw new NullPointerException(
313 "SurfaceControl native object is null. Are you using a released SurfaceControl?");
Jeff Brown64a55af2012-08-26 02:47:39 -0700314 }
Ashok Bhata0398432014-01-20 20:08:01 +0000315 long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700316
317 synchronized (mLock) {
318 if (mNativeObject != 0) {
319 nativeRelease(mNativeObject);
Mathias Agopian7c116b52013-03-18 20:27:02 -0700320 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700321 setNativeObjectLocked(newNativeObject);
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700322 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700323 }
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800324
325 /**
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700326 * This is intended to be used by {@link SurfaceView#updateWindow} only.
Mathias Agopian7c116b52013-03-18 20:27:02 -0700327 * @param other access is not thread safe
328 * @hide
329 * @deprecated
Dianne Hackborn61566cc2011-12-02 23:31:52 -0800330 */
Mathias Agopian7c116b52013-03-18 20:27:02 -0700331 @Deprecated
Jeff Brown64a55af2012-08-26 02:47:39 -0700332 public void transferFrom(Surface other) {
333 if (other == null) {
334 throw new IllegalArgumentException("other must not be null");
335 }
336 if (other != this) {
Ashok Bhata0398432014-01-20 20:08:01 +0000337 final long newPtr;
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700338 synchronized (other.mLock) {
339 newPtr = other.mNativeObject;
340 other.setNativeObjectLocked(0);
341 }
342
343 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700344 if (mNativeObject != 0) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700345 nativeRelease(mNativeObject);
346 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700347 setNativeObjectLocked(newPtr);
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800348 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700349 }
Mathias Agopianb9230662011-08-03 14:44:48 -0700350 }
351
Jeff Brown64a55af2012-08-26 02:47:39 -0700352 @Override
353 public int describeContents() {
354 return 0;
355 }
356
357 public void readFromParcel(Parcel source) {
358 if (source == null) {
359 throw new IllegalArgumentException("source must not be null");
360 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700361
362 synchronized (mLock) {
Andy McFaddened55c8d2013-08-20 10:05:51 -0700363 // nativeReadFromParcel() will either return mNativeObject, or
364 // create a new native Surface and return it after reducing
365 // the reference count on mNativeObject. Either way, it is
366 // not necessary to call nativeRelease() here.
Mathias Agopian7c116b52013-03-18 20:27:02 -0700367 mName = source.readString();
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700368 setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
Mathias Agopian86e1bc72013-03-13 17:48:22 -0700369 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700370 }
371
372 @Override
373 public void writeToParcel(Parcel dest, int flags) {
374 if (dest == null) {
375 throw new IllegalArgumentException("dest must not be null");
376 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700377 synchronized (mLock) {
Mathias Agopian7c116b52013-03-18 20:27:02 -0700378 dest.writeString(mName);
379 nativeWriteToParcel(mNativeObject, dest);
380 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700381 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
382 release();
383 }
384 }
385
386 @Override
387 public String toString() {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700388 synchronized (mLock) {
Andy McFaddened55c8d2013-08-20 10:05:51 -0700389 return "Surface(name=" + mName + ")/@0x" +
390 Integer.toHexString(System.identityHashCode(this));
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700391 }
392 }
393
Ashok Bhata0398432014-01-20 20:08:01 +0000394 private void setNativeObjectLocked(long ptr) {
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700395 if (mNativeObject != ptr) {
396 if (mNativeObject == 0 && ptr != 0) {
397 mCloseGuard.open("release");
398 } else if (mNativeObject != 0 && ptr == 0) {
399 mCloseGuard.close();
400 }
401 mNativeObject = ptr;
402 mGenerationId += 1;
403 }
404 }
405
406 private void checkNotReleasedLocked() {
407 if (mNativeObject == 0) {
408 throw new IllegalStateException("Surface has already been released.");
409 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700410 }
411
Mathias Agopianc14bacf2012-04-23 18:23:08 -0700412 /**
Igor Murashkina86ab6402013-08-30 12:58:36 -0700413 * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
414 * when a SurfaceTexture could not successfully be allocated.
Jeff Brown64a55af2012-08-26 02:47:39 -0700415 */
Igor Murashkina86ab6402013-08-30 12:58:36 -0700416 @SuppressWarnings("serial")
417 public static class OutOfResourcesException extends RuntimeException {
Jeff Brown64a55af2012-08-26 02:47:39 -0700418 public OutOfResourcesException() {
419 }
Jeff Brown64a55af2012-08-26 02:47:39 -0700420 public OutOfResourcesException(String name) {
421 super(name);
422 }
423 }
424
425 /**
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -0700426 * Returns a human readable representation of a rotation.
427 *
428 * @param rotation The rotation.
429 * @return The rotation symbolic name.
Svetoslav Ganov545252f2012-12-10 18:29:24 -0800430 *
431 * @hide
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -0700432 */
433 public static String rotationToString(int rotation) {
434 switch (rotation) {
435 case Surface.ROTATION_0: {
436 return "ROTATION_0";
437 }
438 case Surface.ROTATION_90: {
439 return "ROATATION_90";
440 }
441 case Surface.ROTATION_180: {
442 return "ROATATION_180";
443 }
444 case Surface.ROTATION_270: {
445 return "ROATATION_270";
446 }
447 default: {
448 throw new IllegalArgumentException("Invalid rotation: " + rotation);
449 }
450 }
451 }
452
453 /**
Jeff Brown64a55af2012-08-26 02:47:39 -0700454 * A Canvas class that can handle the compatibility mode.
455 * This does two things differently.
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700456 * <ul>
Mathias Agopianb9230662011-08-03 14:44:48 -0700457 * <li>Returns the width and height of the target metrics, rather than
458 * native. For example, the canvas returns 320x480 even if an app is running
459 * in WVGA high density.
460 * <li>Scales the matrix in setMatrix by the application scale, except if
461 * the matrix looks like obtained from getMatrix. This is a hack to handle
462 * the case that an application uses getMatrix to keep the original matrix,
463 * set matrix of its own, then set the original matrix back. There is no
464 * perfect solution that works for all cases, and there are a lot of cases
465 * that this model does not work, but we hope this works for many apps.
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700466 * </ul>
467 */
Jeff Brown64a55af2012-08-26 02:47:39 -0700468 private final class CompatibleCanvas extends Canvas {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700469 // A temp matrix to remember what an application obtained via {@link getMatrix}
470 private Matrix mOrigMatrix = null;
471
472 @Override
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700473 public void setMatrix(Matrix matrix) {
474 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
475 // don't scale the matrix if it's not compatibility mode, or
476 // the matrix was obtained from getMatrix.
477 super.setMatrix(matrix);
478 } else {
479 Matrix m = new Matrix(mCompatibleMatrix);
480 m.preConcat(matrix);
481 super.setMatrix(m);
482 }
483 }
484
Romain Guy8b5aa482013-02-28 18:13:54 -0800485 @SuppressWarnings("deprecation")
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700486 @Override
487 public void getMatrix(Matrix m) {
488 super.getMatrix(m);
489 if (mOrigMatrix == null) {
Andy McFaddened55c8d2013-08-20 10:05:51 -0700490 mOrigMatrix = new Matrix();
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700491 }
492 mOrigMatrix.set(m);
493 }
Romain Guyd10cd572010-10-10 13:33:22 -0700494 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495}