• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.res.CompatibilityInfo.Translator;
20 import android.graphics.Canvas;
21 import android.graphics.Matrix;
22 import android.graphics.Rect;
23 import android.graphics.SurfaceTexture;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.util.Log;
27 import dalvik.system.CloseGuard;
28 
29 /**
30  * Handle onto a raw buffer that is being managed by the screen compositor.
31  */
32 public class Surface implements Parcelable {
33     private static final String TAG = "Surface";
34 
nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)35     private static native int nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
36             throws OutOfResourcesException;
nativeCreateFromSurfaceControl(int surfaceControlNativeObject)37     private static native int nativeCreateFromSurfaceControl(int surfaceControlNativeObject);
38 
nativeLockCanvas(int nativeObject, Canvas canvas, Rect dirty)39     private static native void nativeLockCanvas(int nativeObject, Canvas canvas, Rect dirty)
40             throws OutOfResourcesException;
nativeUnlockCanvasAndPost(int nativeObject, Canvas canvas)41     private static native void nativeUnlockCanvasAndPost(int nativeObject, Canvas canvas);
42 
nativeRelease(int nativeObject)43     private static native void nativeRelease(int nativeObject);
nativeIsValid(int nativeObject)44     private static native boolean nativeIsValid(int nativeObject);
nativeIsConsumerRunningBehind(int nativeObject)45     private static native boolean nativeIsConsumerRunningBehind(int nativeObject);
nativeReadFromParcel(int nativeObject, Parcel source)46     private static native int nativeReadFromParcel(int nativeObject, Parcel source);
nativeWriteToParcel(int nativeObject, Parcel dest)47     private static native void nativeWriteToParcel(int nativeObject, Parcel dest);
48 
49     public static final Parcelable.Creator<Surface> CREATOR =
50             new Parcelable.Creator<Surface>() {
51         @Override
52         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             }
61         }
62 
63         @Override
64         public Surface[] newArray(int size) {
65             return new Surface[size];
66         }
67     };
68 
69     private final CloseGuard mCloseGuard = CloseGuard.get();
70 
71     // Guarded state.
72     final Object mLock = new Object(); // protects the native state
73     private String mName;
74     int mNativeSurface; // package scope only for SurfaceControl access
75     private int mGenerationId; // incremented each time mNativeSurface changes
76     private final Canvas mCanvas = new CompatibleCanvas();
77 
78     // A matrix to scale the matrix set by application. This is set to null for
79     // non compatibility mode.
80     private Matrix mCompatibleMatrix;
81 
82     /**
83      * 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 
102     /**
103      * Create an empty surface, which will later be filled in by readFromParcel().
104      * @hide
105      */
Surface()106     public Surface() {
107     }
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      */
Surface(SurfaceTexture surfaceTexture)119     public Surface(SurfaceTexture surfaceTexture) {
120         if (surfaceTexture == null) {
121             throw new IllegalArgumentException("surfaceTexture must not be null");
122         }
123 
124         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             }
132         }
133     }
134 
135     /* called from android_view_Surface_createFromIGraphicBufferProducer() */
Surface(int nativeObject)136     private Surface(int nativeObject) {
137         synchronized (mLock) {
138             setNativeObjectLocked(nativeObject);
139         }
140     }
141 
142     @Override
finalize()143     protected void finalize() throws Throwable {
144         try {
145             if (mCloseGuard != null) {
146                 mCloseGuard.warnIfOpen();
147             }
148             release();
149         } 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      */
release()159     public void release() {
160         synchronized (mLock) {
161             if (mNativeSurface != 0) {
162                 nativeRelease(mNativeSurface);
163                 setNativeObjectLocked(0);
164             }
165         }
166     }
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      */
destroy()174     public void destroy() {
175         release();
176     }
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      */
isValid()184     public boolean isValid() {
185         synchronized (mLock) {
186             if (mNativeSurface == 0) return false;
187             return nativeIsValid(mNativeSurface);
188         }
189     }
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      */
getGenerationId()198     public int getGenerationId() {
199         synchronized (mLock) {
200             return mGenerationId;
201         }
202     }
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      */
isConsumerRunningBehind()210     public boolean isConsumerRunningBehind() {
211         synchronized (mLock) {
212             checkNotReleasedLocked();
213             return nativeIsConsumerRunningBehind(mNativeSurface);
214         }
215     }
216 
217     /**
218      * Gets a {@link Canvas} for drawing into this surface.
219      *
220      * After drawing into the provided {@link Canvas}, the caller must
221      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
222      *
223      * @param inOutDirty A rectangle that represents the dirty region that the caller wants
224      * 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
226      * 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.
228      * 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      */
lockCanvas(Rect inOutDirty)232     public Canvas lockCanvas(Rect inOutDirty)
233             throws OutOfResourcesException, IllegalArgumentException {
234         synchronized (mLock) {
235             checkNotReleasedLocked();
236             nativeLockCanvas(mNativeSurface, mCanvas, inOutDirty);
237             return mCanvas;
238         }
239     }
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      */
unlockCanvasAndPost(Canvas canvas)247     public void unlockCanvasAndPost(Canvas canvas) {
248         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) {
254             checkNotReleasedLocked();
255             nativeUnlockCanvasAndPost(mNativeSurface, canvas);
256         }
257     }
258 
259     /**
260      * @deprecated This API has been removed and is not supported.  Do not use.
261      */
262     @Deprecated
unlockCanvas(Canvas canvas)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      */
setCompatibilityTranslator(Translator translator)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 
279     /**
280      * 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.
282      * 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.
286      * @hide
287      */
copyFrom(SurfaceControl other)288     public void copyFrom(SurfaceControl other) {
289         if (other == null) {
290             throw new IllegalArgumentException("other must not be null");
291         }
292 
293         int surfaceControlPtr = other.mNativeObject;
294         if (surfaceControlPtr == 0) {
295             throw new NullPointerException(
296                     "SurfaceControl native object is null. Are you using a released SurfaceControl?");
297         }
298         int newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
299 
300         synchronized (mLock) {
301             if (mNativeSurface != 0) {
302                 nativeRelease(mNativeSurface);
303             }
304             setNativeObjectLocked(newNativeObject);
305         }
306     }
307 
308     /**
309      * This is intended to be used by {@link SurfaceView#updateWindow} only.
310      * @param other access is not thread safe
311      * @hide
312      * @deprecated
313      */
314     @Deprecated
transferFrom(Surface other)315     public void transferFrom(Surface other) {
316         if (other == null) {
317             throw new IllegalArgumentException("other must not be null");
318         }
319         if (other != this) {
320             final int newPtr;
321             synchronized (other.mLock) {
322                 newPtr = other.mNativeSurface;
323                 other.setNativeObjectLocked(0);
324             }
325 
326             synchronized (mLock) {
327                 if (mNativeSurface != 0) {
328                     nativeRelease(mNativeSurface);
329                 }
330                 setNativeObjectLocked(newPtr);
331             }
332         }
333     }
334 
335     @Override
describeContents()336     public int describeContents() {
337         return 0;
338     }
339 
readFromParcel(Parcel source)340     public void readFromParcel(Parcel source) {
341         if (source == null) {
342             throw new IllegalArgumentException("source must not be null");
343         }
344 
345         synchronized (mLock) {
346             mName = source.readString();
347             setNativeObjectLocked(nativeReadFromParcel(mNativeSurface, source));
348         }
349     }
350 
351     @Override
writeToParcel(Parcel dest, int flags)352     public void writeToParcel(Parcel dest, int flags) {
353         if (dest == null) {
354             throw new IllegalArgumentException("dest must not be null");
355         }
356         synchronized (mLock) {
357             dest.writeString(mName);
358             nativeWriteToParcel(mNativeSurface, dest);
359         }
360         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
361             release();
362         }
363     }
364 
365     @Override
toString()366     public String toString() {
367         synchronized (mLock) {
368             return "Surface(name=" + mName + ")";
369         }
370     }
371 
setNativeObjectLocked(int ptr)372     private void setNativeObjectLocked(int ptr) {
373         if (mNativeSurface != ptr) {
374             if (mNativeSurface == 0 && ptr != 0) {
375                 mCloseGuard.open("release");
376             } else if (mNativeSurface != 0 && ptr == 0) {
377                 mCloseGuard.close();
378             }
379             mNativeSurface = ptr;
380             mGenerationId += 1;
381         }
382     }
383 
checkNotReleasedLocked()384     private void checkNotReleasedLocked() {
385         if (mNativeSurface == 0) {
386             throw new IllegalStateException("Surface has already been released.");
387         }
388     }
389 
390     /**
391      * Exception thrown when a surface couldn't be created or resized.
392      */
393     public static class OutOfResourcesException extends Exception {
OutOfResourcesException()394         public OutOfResourcesException() {
395         }
OutOfResourcesException(String name)396         public OutOfResourcesException(String name) {
397             super(name);
398         }
399     }
400 
401     /**
402      * Returns a human readable representation of a rotation.
403      *
404      * @param rotation The rotation.
405      * @return The rotation symbolic name.
406      *
407      * @hide
408      */
rotationToString(int rotation)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     /**
430      * A Canvas class that can handle the compatibility mode.
431      * This does two things differently.
432      * <ul>
433      * <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.
442      * </ul>
443      */
444     private final class CompatibleCanvas extends Canvas {
445         // A temp matrix to remember what an application obtained via {@link getMatrix}
446         private Matrix mOrigMatrix = null;
447 
448         @Override
setMatrix(Matrix matrix)449         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 
461         @SuppressWarnings("deprecation")
462         @Override
getMatrix(Matrix m)463         public void getMatrix(Matrix m) {
464             super.getMatrix(m);
465             if (mOrigMatrix == null) {
466                 mOrigMatrix = new Matrix();
467             }
468             mOrigMatrix.set(m);
469         }
470     }
471 }
472