OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / core / java / android / view / Surface.java
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
17 package android.view;
18
19 import android.annotation.IntDef;
20 import android.content.res.CompatibilityInfo.Translator;
21 import android.graphics.Canvas;
22 import android.graphics.Matrix;
23 import android.graphics.Rect;
24 import android.graphics.SurfaceTexture;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.util.Log;
28
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31
32 import dalvik.system.CloseGuard;
33
34 /**
35  * Handle onto a raw buffer that is being managed by the screen compositor.
36  */
37 public class Surface implements Parcelable {
38     private static final String TAG = "Surface";
39
40     private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
41             throws OutOfResourcesException;
42     private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject);
43
44     private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
45             throws OutOfResourcesException;
46     private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
47
48     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);
53
54     private static native void nativeAllocateBuffers(long nativeObject);
55
56     private static native int nativeGetWidth(long nativeObject);
57     private static native int nativeGetHeight(long nativeObject);
58
59     private static native long nativeGetNextFrameNumber(long nativeObject);
60     private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
61     private static native void nativeSetBuffersTransform(long nativeObject, long transform);
62
63     public static final Parcelable.Creator<Surface> CREATOR =
64             new Parcelable.Creator<Surface>() {
65         @Override
66         public Surface createFromParcel(Parcel source) {
67             try {
68                 Surface s = new Surface();
69                 s.readFromParcel(source);
70                 return s;
71             } catch (Exception e) {
72                 Log.e(TAG, "Exception creating surface from parcel", e);
73                 return null;
74             }
75         }
76
77         @Override
78         public Surface[] newArray(int size) {
79             return new Surface[size];
80         }
81     };
82
83     private final CloseGuard mCloseGuard = CloseGuard.get();
84
85     // Guarded state.
86     final Object mLock = new Object(); // protects the native state
87     private String mName;
88     long mNativeObject; // package scope only for SurfaceControl access
89     private long mLockedObject;
90     private int mGenerationId; // incremented each time mNativeObject changes
91     private final Canvas mCanvas = new CompatibleCanvas();
92
93     // A matrix to scale the matrix set by application. This is set to null for
94     // non compatibility mode.
95     private Matrix mCompatibleMatrix;
96
97     private HwuiContext mHwuiContext;
98
99     /** @hide */
100     @Retention(RetentionPolicy.SOURCE)
101     @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
102                     SCALING_MODE_SCALE_CROP, SCALING_MODE_NO_SCALE_CROP})
103     public @interface ScalingMode {}
104     // From system/window.h
105     /** @hide */
106     public static final int SCALING_MODE_FREEZE = 0;
107     /** @hide */
108     public static final int SCALING_MODE_SCALE_TO_WINDOW = 1;
109     /** @hide */
110     public static final int SCALING_MODE_SCALE_CROP = 2;
111     /** @hide */
112     public static final int SCALING_MODE_NO_SCALE_CROP = 3;
113
114     /** @hide */
115     @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
116     @Retention(RetentionPolicy.SOURCE)
117     public @interface Rotation {}
118
119     /**
120      * Rotation constant: 0 degree rotation (natural orientation)
121      */
122     public static final int ROTATION_0 = 0;
123
124     /**
125      * Rotation constant: 90 degree rotation.
126      */
127     public static final int ROTATION_90 = 1;
128
129     /**
130      * Rotation constant: 180 degree rotation.
131      */
132     public static final int ROTATION_180 = 2;
133
134     /**
135      * Rotation constant: 270 degree rotation.
136      */
137     public static final int ROTATION_270 = 3;
138
139     /**
140      * Create an empty surface, which will later be filled in by readFromParcel().
141      * @hide
142      */
143     public Surface() {
144     }
145
146     /**
147      * Create Surface from a {@link SurfaceTexture}.
148      *
149      * Images drawn to the Surface will be made available to the {@link
150      * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
151      * SurfaceTexture#updateTexImage}.
152      *
153      * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
154      * Surface.
155      * @throws OutOfResourcesException if the surface could not be created.
156      */
157     public Surface(SurfaceTexture surfaceTexture) {
158         if (surfaceTexture == null) {
159             throw new IllegalArgumentException("surfaceTexture must not be null");
160         }
161
162         synchronized (mLock) {
163             mName = surfaceTexture.toString();
164             setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
165         }
166     }
167
168     /* called from android_view_Surface_createFromIGraphicBufferProducer() */
169     private Surface(long nativeObject) {
170         synchronized (mLock) {
171             setNativeObjectLocked(nativeObject);
172         }
173     }
174
175     @Override
176     protected void finalize() throws Throwable {
177         try {
178             if (mCloseGuard != null) {
179                 mCloseGuard.warnIfOpen();
180             }
181             release();
182         } finally {
183             super.finalize();
184         }
185     }
186
187     /**
188      * Release the local reference to the server-side surface.
189      * Always call release() when you're done with a Surface.
190      * This will make the surface invalid.
191      */
192     public void release() {
193         synchronized (mLock) {
194             if (mNativeObject != 0) {
195                 nativeRelease(mNativeObject);
196                 setNativeObjectLocked(0);
197             }
198             if (mHwuiContext != null) {
199                 mHwuiContext.destroy();
200                 mHwuiContext = null;
201             }
202         }
203     }
204
205     /**
206      * Free all server-side state associated with this surface and
207      * release this object's reference.  This method can only be
208      * called from the process that created the service.
209      * @hide
210      */
211     public void destroy() {
212         release();
213     }
214
215     /**
216      * Returns true if this object holds a valid surface.
217      *
218      * @return True if it holds a physical surface, so lockCanvas() will succeed.
219      * Otherwise returns false.
220      */
221     public boolean isValid() {
222         synchronized (mLock) {
223             if (mNativeObject == 0) return false;
224             return nativeIsValid(mNativeObject);
225         }
226     }
227
228     /**
229      * Gets the generation number of this surface, incremented each time
230      * the native surface contained within this object changes.
231      *
232      * @return The current generation number.
233      * @hide
234      */
235     public int getGenerationId() {
236         synchronized (mLock) {
237             return mGenerationId;
238         }
239     }
240
241     /**
242      * Returns the next frame number which will be dequeued for rendering.
243      * Intended for use with SurfaceFlinger's deferred transactions API.
244      *
245      * @hide
246      */
247     public long getNextFrameNumber() {
248         synchronized (mLock) {
249             return nativeGetNextFrameNumber(mNativeObject);
250         }
251     }
252
253     /**
254      * Returns true if the consumer of this Surface is running behind the producer.
255      *
256      * @return True if the consumer is more than one buffer ahead of the producer.
257      * @hide
258      */
259     public boolean isConsumerRunningBehind() {
260         synchronized (mLock) {
261             checkNotReleasedLocked();
262             return nativeIsConsumerRunningBehind(mNativeObject);
263         }
264     }
265
266     /**
267      * Gets a {@link Canvas} for drawing into this surface.
268      *
269      * After drawing into the provided {@link Canvas}, the caller must
270      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
271      *
272      * @param inOutDirty A rectangle that represents the dirty region that the caller wants
273      * to redraw.  This function may choose to expand the dirty rectangle if for example
274      * the surface has been resized or if the previous contents of the surface were
275      * not available.  The caller must redraw the entire dirty region as represented
276      * by the contents of the inOutDirty rectangle upon return from this function.
277      * The caller may also pass <code>null</code> instead, in the case where the
278      * entire surface should be redrawn.
279      * @return A canvas for drawing into the surface.
280      *
281      * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
282      * @throws OutOfResourcesException If the canvas cannot be locked.
283      */
284     public Canvas lockCanvas(Rect inOutDirty)
285             throws Surface.OutOfResourcesException, IllegalArgumentException {
286         synchronized (mLock) {
287             checkNotReleasedLocked();
288             if (mLockedObject != 0) {
289                 // Ideally, nativeLockCanvas() would throw in this situation and prevent the
290                 // double-lock, but that won't happen if mNativeObject was updated.  We can't
291                 // abandon the old mLockedObject because it might still be in use, so instead
292                 // we just refuse to re-lock the Surface.
293                 throw new IllegalArgumentException("Surface was already locked");
294             }
295             mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
296             return mCanvas;
297         }
298     }
299
300     /**
301      * Posts the new contents of the {@link Canvas} to the surface and
302      * releases the {@link Canvas}.
303      *
304      * @param canvas The canvas previously obtained from {@link #lockCanvas}.
305      */
306     public void unlockCanvasAndPost(Canvas canvas) {
307         synchronized (mLock) {
308             checkNotReleasedLocked();
309
310             if (mHwuiContext != null) {
311                 mHwuiContext.unlockAndPost(canvas);
312             } else {
313                 unlockSwCanvasAndPost(canvas);
314             }
315         }
316     }
317
318     private void unlockSwCanvasAndPost(Canvas canvas) {
319         if (canvas != mCanvas) {
320             throw new IllegalArgumentException("canvas object must be the same instance that "
321                     + "was previously returned by lockCanvas");
322         }
323         if (mNativeObject != mLockedObject) {
324             Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
325                     Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
326                     Long.toHexString(mLockedObject) +")");
327         }
328         if (mLockedObject == 0) {
329             throw new IllegalStateException("Surface was not locked");
330         }
331         try {
332             nativeUnlockCanvasAndPost(mLockedObject, canvas);
333         } finally {
334             nativeRelease(mLockedObject);
335             mLockedObject = 0;
336         }
337     }
338
339     /**
340      * Gets a {@link Canvas} for drawing into this surface.
341      *
342      * After drawing into the provided {@link Canvas}, the caller must
343      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
344      *
345      * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
346      * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
347      * unsupported drawing operations</a> for a list of what is and isn't
348      * supported in a hardware-accelerated canvas. It is also required to
349      * fully cover the surface every time {@link #lockHardwareCanvas()} is
350      * called as the buffer is not preserved between frames. Partial updates
351      * are not supported.
352      *
353      * @return A canvas for drawing into the surface.
354      *
355      * @throws IllegalStateException If the canvas cannot be locked.
356      */
357     public Canvas lockHardwareCanvas() {
358         synchronized (mLock) {
359             checkNotReleasedLocked();
360             if (mHwuiContext == null) {
361                 mHwuiContext = new HwuiContext();
362             }
363             return mHwuiContext.lockCanvas(
364                     nativeGetWidth(mNativeObject),
365                     nativeGetHeight(mNativeObject));
366         }
367     }
368
369     /**
370      * @deprecated This API has been removed and is not supported.  Do not use.
371      */
372     @Deprecated
373     public void unlockCanvas(Canvas canvas) {
374         throw new UnsupportedOperationException();
375     }
376
377     /**
378      * Sets the translator used to scale canvas's width/height in compatibility
379      * mode.
380      */
381     void setCompatibilityTranslator(Translator translator) {
382         if (translator != null) {
383             float appScale = translator.applicationScale;
384             mCompatibleMatrix = new Matrix();
385             mCompatibleMatrix.setScale(appScale, appScale);
386         }
387     }
388
389     /**
390      * Copy another surface to this one.  This surface now holds a reference
391      * to the same data as the original surface, and is -not- the owner.
392      * This is for use by the window manager when returning a window surface
393      * back from a client, converting it from the representation being managed
394      * by the window manager to the representation the client uses to draw
395      * in to it.
396      * @hide
397      */
398     public void copyFrom(SurfaceControl other) {
399         if (other == null) {
400             throw new IllegalArgumentException("other must not be null");
401         }
402
403         long surfaceControlPtr = other.mNativeObject;
404         if (surfaceControlPtr == 0) {
405             throw new NullPointerException(
406                     "SurfaceControl native object is null. Are you using a released SurfaceControl?");
407         }
408         long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
409
410         synchronized (mLock) {
411             if (mNativeObject != 0) {
412                 nativeRelease(mNativeObject);
413             }
414             setNativeObjectLocked(newNativeObject);
415         }
416     }
417
418     /**
419      * This is intended to be used by {@link SurfaceView#updateWindow} only.
420      * @param other access is not thread safe
421      * @hide
422      * @deprecated
423      */
424     @Deprecated
425     public void transferFrom(Surface other) {
426         if (other == null) {
427             throw new IllegalArgumentException("other must not be null");
428         }
429         if (other != this) {
430             final long newPtr;
431             synchronized (other.mLock) {
432                 newPtr = other.mNativeObject;
433                 other.setNativeObjectLocked(0);
434             }
435
436             synchronized (mLock) {
437                 if (mNativeObject != 0) {
438                     nativeRelease(mNativeObject);
439                 }
440                 setNativeObjectLocked(newPtr);
441             }
442         }
443     }
444
445     @Override
446     public int describeContents() {
447         return 0;
448     }
449
450     public void readFromParcel(Parcel source) {
451         if (source == null) {
452             throw new IllegalArgumentException("source must not be null");
453         }
454
455         synchronized (mLock) {
456             // nativeReadFromParcel() will either return mNativeObject, or
457             // create a new native Surface and return it after reducing
458             // the reference count on mNativeObject.  Either way, it is
459             // not necessary to call nativeRelease() here.
460             mName = source.readString();
461             setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
462         }
463     }
464
465     @Override
466     public void writeToParcel(Parcel dest, int flags) {
467         if (dest == null) {
468             throw new IllegalArgumentException("dest must not be null");
469         }
470         synchronized (mLock) {
471             dest.writeString(mName);
472             nativeWriteToParcel(mNativeObject, dest);
473         }
474         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
475             release();
476         }
477     }
478
479     @Override
480     public String toString() {
481         synchronized (mLock) {
482             return "Surface(name=" + mName + ")/@0x" +
483                     Integer.toHexString(System.identityHashCode(this));
484         }
485     }
486
487     private void setNativeObjectLocked(long ptr) {
488         if (mNativeObject != ptr) {
489             if (mNativeObject == 0 && ptr != 0) {
490                 mCloseGuard.open("release");
491             } else if (mNativeObject != 0 && ptr == 0) {
492                 mCloseGuard.close();
493             }
494             mNativeObject = ptr;
495             mGenerationId += 1;
496             if (mHwuiContext != null) {
497                 mHwuiContext.updateSurface();
498             }
499         }
500     }
501
502     private void checkNotReleasedLocked() {
503         if (mNativeObject == 0) {
504             throw new IllegalStateException("Surface has already been released.");
505         }
506     }
507
508     /**
509      * Allocate buffers ahead of time to avoid allocation delays during rendering
510      * @hide
511      */
512     public void allocateBuffers() {
513         synchronized (mLock) {
514             checkNotReleasedLocked();
515             nativeAllocateBuffers(mNativeObject);
516         }
517     }
518
519     /**
520      * Set the scaling mode to be used for this surfaces buffers
521      * @hide
522      */
523     void setScalingMode(@ScalingMode int scalingMode) {
524         synchronized (mLock) {
525             checkNotReleasedLocked();
526             int err = nativeSetScalingMode(mNativeObject, scalingMode);
527             if (err != 0) {
528                 throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode);
529             }
530         }
531     }
532
533     /**
534      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
535      * when a SurfaceTexture could not successfully be allocated.
536      */
537     @SuppressWarnings("serial")
538     public static class OutOfResourcesException extends RuntimeException {
539         public OutOfResourcesException() {
540         }
541         public OutOfResourcesException(String name) {
542             super(name);
543         }
544     }
545
546     /**
547      * Returns a human readable representation of a rotation.
548      *
549      * @param rotation The rotation.
550      * @return The rotation symbolic name.
551      *
552      * @hide
553      */
554     public static String rotationToString(int rotation) {
555         switch (rotation) {
556             case Surface.ROTATION_0: {
557                 return "ROTATION_0";
558             }
559             case Surface.ROTATION_90: {
560                 return "ROATATION_90";
561             }
562             case Surface.ROTATION_180: {
563                 return "ROATATION_180";
564             }
565             case Surface.ROTATION_270: {
566                 return "ROATATION_270";
567             }
568             default: {
569                 throw new IllegalArgumentException("Invalid rotation: " + rotation);
570             }
571         }
572     }
573
574     /**
575      * A Canvas class that can handle the compatibility mode.
576      * This does two things differently.
577      * <ul>
578      * <li>Returns the width and height of the target metrics, rather than
579      * native. For example, the canvas returns 320x480 even if an app is running
580      * in WVGA high density.
581      * <li>Scales the matrix in setMatrix by the application scale, except if
582      * the matrix looks like obtained from getMatrix. This is a hack to handle
583      * the case that an application uses getMatrix to keep the original matrix,
584      * set matrix of its own, then set the original matrix back. There is no
585      * perfect solution that works for all cases, and there are a lot of cases
586      * that this model does not work, but we hope this works for many apps.
587      * </ul>
588      */
589     private final class CompatibleCanvas extends Canvas {
590         // A temp matrix to remember what an application obtained via {@link getMatrix}
591         private Matrix mOrigMatrix = null;
592
593         @Override
594         public void setMatrix(Matrix matrix) {
595             if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
596                 // don't scale the matrix if it's not compatibility mode, or
597                 // the matrix was obtained from getMatrix.
598                 super.setMatrix(matrix);
599             } else {
600                 Matrix m = new Matrix(mCompatibleMatrix);
601                 m.preConcat(matrix);
602                 super.setMatrix(m);
603             }
604         }
605
606         @SuppressWarnings("deprecation")
607         @Override
608         public void getMatrix(Matrix m) {
609             super.getMatrix(m);
610             if (mOrigMatrix == null) {
611                 mOrigMatrix = new Matrix();
612             }
613             mOrigMatrix.set(m);
614         }
615     }
616
617     private final class HwuiContext {
618         private final RenderNode mRenderNode;
619         private long mHwuiRenderer;
620         private DisplayListCanvas mCanvas;
621
622         HwuiContext() {
623             mRenderNode = RenderNode.create("HwuiCanvas", null);
624             mRenderNode.setClipToBounds(false);
625             mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject);
626         }
627
628         Canvas lockCanvas(int width, int height) {
629             if (mCanvas != null) {
630                 throw new IllegalStateException("Surface was already locked!");
631             }
632             mCanvas = mRenderNode.start(width, height);
633             return mCanvas;
634         }
635
636         void unlockAndPost(Canvas canvas) {
637             if (canvas != mCanvas) {
638                 throw new IllegalArgumentException("canvas object must be the same instance that "
639                         + "was previously returned by lockCanvas");
640             }
641             mRenderNode.end(mCanvas);
642             mCanvas = null;
643             nHwuiDraw(mHwuiRenderer);
644         }
645
646         void updateSurface() {
647             nHwuiSetSurface(mHwuiRenderer, mNativeObject);
648         }
649
650         void destroy() {
651             if (mHwuiRenderer != 0) {
652                 nHwuiDestroy(mHwuiRenderer);
653                 mHwuiRenderer = 0;
654             }
655         }
656     }
657
658     private static native long nHwuiCreate(long rootNode, long surface);
659     private static native void nHwuiSetSurface(long renderer, long surface);
660     private static native void nHwuiDraw(long renderer);
661     private static native void nHwuiDestroy(long renderer);
662 }