1 /*
2  * Copyright (C) 2013 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.graphics.Canvas;
20 import android.graphics.PixelFormat;
21 import android.graphics.Rect;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 /**
26  * Simple wrapper for the native GraphicBuffer class.
27  *
28  * @hide
29  */
30 @SuppressWarnings("UnusedDeclaration")
31 public class GraphicBuffer implements Parcelable {
32     // Note: keep usage flags in sync with GraphicBuffer.h and gralloc.h
33     public static final int USAGE_SW_READ_NEVER = 0x0;
34     public static final int USAGE_SW_READ_RARELY = 0x2;
35     public static final int USAGE_SW_READ_OFTEN = 0x3;
36     public static final int USAGE_SW_READ_MASK = 0xF;
37 
38     public static final int USAGE_SW_WRITE_NEVER = 0x0;
39     public static final int USAGE_SW_WRITE_RARELY = 0x20;
40     public static final int USAGE_SW_WRITE_OFTEN = 0x30;
41     public static final int USAGE_SW_WRITE_MASK = 0xF0;
42 
43     public static final int USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK | USAGE_SW_WRITE_MASK;
44 
45     public static final int USAGE_PROTECTED = 0x4000;
46 
47     public static final int USAGE_HW_TEXTURE = 0x100;
48     public static final int USAGE_HW_RENDER = 0x200;
49     public static final int USAGE_HW_2D = 0x400;
50     public static final int USAGE_HW_COMPOSER = 0x800;
51     public static final int USAGE_HW_VIDEO_ENCODER = 0x10000;
52     public static final int USAGE_HW_MASK = 0x71F00;
53 
54     private final int mWidth;
55     private final int mHeight;
56     private final int mFormat;
57     private final int mUsage;
58     // Note: do not rename, this field is used by native code
59     private final long mNativeObject;
60 
61     // These two fields are only used by lock/unlockCanvas()
62     private Canvas mCanvas;
63     private int mSaveCount;
64 
65     // If set to true, this GraphicBuffer instance cannot be used anymore
66     private boolean mDestroyed;
67 
68     /**
69      * Creates new <code>GraphicBuffer</code> instance. This method will return null
70      * if the buffer cannot be created.
71      *
72      * @param width The width in pixels of the buffer
73      * @param height The height in pixels of the buffer
74      * @param format The format of each pixel as specified in {@link PixelFormat}
75      * @param usage Hint indicating how the buffer will be used
76      *
77      * @return A <code>GraphicBuffer</code> instance or null
78      */
create(int width, int height, int format, int usage)79     public static GraphicBuffer create(int width, int height, int format, int usage) {
80         long nativeObject = nCreateGraphicBuffer(width, height, format, usage);
81         if (nativeObject != 0) {
82             return new GraphicBuffer(width, height, format, usage, nativeObject);
83         }
84         return null;
85     }
86 
87     /**
88      * Private use only. See {@link #create(int, int, int, int)}.
89      */
GraphicBuffer(int width, int height, int format, int usage, long nativeObject)90     private GraphicBuffer(int width, int height, int format, int usage, long nativeObject) {
91         mWidth = width;
92         mHeight = height;
93         mFormat = format;
94         mUsage = usage;
95         mNativeObject = nativeObject;
96     }
97 
98     /**
99      * Returns the width of this buffer in pixels.
100      */
getWidth()101     public int getWidth() {
102         return mWidth;
103     }
104 
105     /**
106      * Returns the height of this buffer in pixels.
107      */
getHeight()108     public int getHeight() {
109         return mHeight;
110     }
111 
112     /**
113      * Returns the pixel format of this buffer. The pixel format must be one of
114      * the formats defined in {@link PixelFormat}.
115      */
getFormat()116     public int getFormat() {
117         return mFormat;
118     }
119 
120     /**
121      * Returns the usage hint set on this buffer.
122      */
getUsage()123     public int getUsage() {
124         return mUsage;
125     }
126 
127     /**
128      * <p>Start editing the pixels in the buffer. A null is returned if the buffer
129      * cannot be locked for editing.</p>
130      *
131      * <p>The content of the buffer is preserved between unlockCanvas()
132      * and lockCanvas().</p>
133      *
134      * <p>If this method is called after {@link #destroy()}, the return value will
135      * always be null.</p>
136      *
137      * @return A Canvas used to draw into the buffer, or null.
138      *
139      * @see #lockCanvas(android.graphics.Rect)
140      * @see #unlockCanvasAndPost(android.graphics.Canvas)
141      * @see #isDestroyed()
142      */
lockCanvas()143     public Canvas lockCanvas() {
144         return lockCanvas(null);
145     }
146 
147     /**
148      * Just like {@link #lockCanvas()} but allows specification of a dirty
149      * rectangle.
150      *
151      * <p>If this method is called after {@link #destroy()}, the return value will
152      * always be null.</p>
153      *
154      * @param dirty Area of the buffer that may be modified.
155 
156      * @return A Canvas used to draw into the surface, or null.
157      *
158      * @see #lockCanvas()
159      * @see #unlockCanvasAndPost(android.graphics.Canvas)
160      * @see #isDestroyed()
161      */
lockCanvas(Rect dirty)162     public Canvas lockCanvas(Rect dirty) {
163         if (mDestroyed) {
164             return null;
165         }
166 
167         if (mCanvas == null) {
168             mCanvas = new Canvas();
169         }
170 
171         if (nLockCanvas(mNativeObject, mCanvas, dirty)) {
172             mSaveCount = mCanvas.save();
173             return mCanvas;
174         }
175 
176         return null;
177     }
178 
179     /**
180      * Finish editing pixels in the buffer.
181      *
182      * <p>This method doesn't do anything if {@link #destroy()} was
183      * previously called.</p>
184      *
185      * @param canvas The Canvas previously returned by lockCanvas()
186      *
187      * @see #lockCanvas()
188      * @see #lockCanvas(android.graphics.Rect)
189      * @see #isDestroyed()
190      */
unlockCanvasAndPost(Canvas canvas)191     public void unlockCanvasAndPost(Canvas canvas) {
192         if (!mDestroyed && mCanvas != null && canvas == mCanvas) {
193             canvas.restoreToCount(mSaveCount);
194             mSaveCount = 0;
195 
196             nUnlockCanvasAndPost(mNativeObject, mCanvas);
197         }
198     }
199 
200     /**
201      * Destroyes this buffer immediately. Calling this method frees up any
202      * underlying native resources. After calling this method, this buffer
203      * must not be used in any way ({@link #lockCanvas()} must not be called,
204      * etc.)
205      *
206      * @see #isDestroyed()
207      */
destroy()208     public void destroy() {
209         if (!mDestroyed) {
210             mDestroyed = true;
211             nDestroyGraphicBuffer(mNativeObject);
212         }
213     }
214 
215     /**
216      * Indicates whether this buffer has been destroyed. A destroyed buffer
217      * cannot be used in any way: locking a Canvas will return null, the buffer
218      * cannot be written to a parcel, etc.
219      *
220      * @return True if this <code>GraphicBuffer</code> is in a destroyed state,
221      *         false otherwise.
222      *
223      * @see #destroy()
224      */
isDestroyed()225     public boolean isDestroyed() {
226         return mDestroyed;
227     }
228 
229     @Override
finalize()230     protected void finalize() throws Throwable {
231         try {
232             if (!mDestroyed) nDestroyGraphicBuffer(mNativeObject);
233         } finally {
234             super.finalize();
235         }
236     }
237 
238     @Override
describeContents()239     public int describeContents() {
240         return 0;
241     }
242 
243     /**
244      * Flatten this object in to a Parcel.
245      *
246      * <p>Calling this method will throw an <code>IllegalStateException</code> if
247      * {@link #destroy()} has been previously called.</p>
248      *
249      * @param dest The Parcel in which the object should be written.
250      * @param flags Additional flags about how the object should be written.
251      *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
252      */
253     @Override
writeToParcel(Parcel dest, int flags)254     public void writeToParcel(Parcel dest, int flags) {
255         if (mDestroyed) {
256             throw new IllegalStateException("This GraphicBuffer has been destroyed and cannot be "
257                     + "written to a parcel.");
258         }
259 
260         dest.writeInt(mWidth);
261         dest.writeInt(mHeight);
262         dest.writeInt(mFormat);
263         dest.writeInt(mUsage);
264         nWriteGraphicBufferToParcel(mNativeObject, dest);
265     }
266 
267     public static final Parcelable.Creator<GraphicBuffer> CREATOR =
268             new Parcelable.Creator<GraphicBuffer>() {
269         public GraphicBuffer createFromParcel(Parcel in) {
270             int width = in.readInt();
271             int height = in.readInt();
272             int format = in.readInt();
273             int usage = in.readInt();
274             long nativeObject = nReadGraphicBufferFromParcel(in);
275             if (nativeObject != 0) {
276                 return new GraphicBuffer(width, height, format, usage, nativeObject);
277             }
278             return null;
279         }
280 
281         public GraphicBuffer[] newArray(int size) {
282             return new GraphicBuffer[size];
283         }
284     };
285 
nCreateGraphicBuffer(int width, int height, int format, int usage)286     private static native long nCreateGraphicBuffer(int width, int height, int format, int usage);
nDestroyGraphicBuffer(long nativeObject)287     private static native void nDestroyGraphicBuffer(long nativeObject);
nWriteGraphicBufferToParcel(long nativeObject, Parcel dest)288     private static native void nWriteGraphicBufferToParcel(long nativeObject, Parcel dest);
nReadGraphicBufferFromParcel(Parcel in)289     private static native long nReadGraphicBufferFromParcel(Parcel in);
nLockCanvas(long nativeObject, Canvas canvas, Rect dirty)290     private static native boolean nLockCanvas(long nativeObject, Canvas canvas, Rect dirty);
nUnlockCanvasAndPost(long nativeObject, Canvas canvas)291     private static native boolean nUnlockCanvasAndPost(long nativeObject, Canvas canvas);
292 }
293