SurfaceControl.java revision 36bef0bf30d6bae48cf3837df351075ca4fce654
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
17package android.view;
18
19import dalvik.system.CloseGuard;
20import android.graphics.Bitmap;
21import android.graphics.Rect;
22import android.graphics.Region;
23import android.view.Surface;
24import android.os.IBinder;
25import android.util.Log;
26import android.view.Surface.OutOfResourcesException;
27
28/**
29 * SurfaceControl
30 *  @hide
31 */
32public class SurfaceControl {
33    private static final String TAG = "SurfaceControl";
34
35    private static native long nativeCreate(SurfaceSession session, String name,
36            int w, int h, int format, int flags)
37            throws OutOfResourcesException;
38    private static native void nativeRelease(long nativeObject);
39    private static native void nativeDestroy(long nativeObject);
40
41    private static native Bitmap nativeScreenshot(IBinder displayToken,
42            int width, int height, int minLayer, int maxLayer, boolean allLayers);
43    private static native void nativeScreenshot(IBinder displayToken, Surface consumer,
44            int width, int height, int minLayer, int maxLayer, boolean allLayers);
45
46    private static native void nativeOpenTransaction();
47    private static native void nativeCloseTransaction();
48    private static native void nativeSetAnimationTransaction();
49
50    private static native void nativeSetLayer(long nativeObject, int zorder);
51    private static native void nativeSetPosition(long nativeObject, float x, float y);
52    private static native void nativeSetSize(long nativeObject, int w, int h);
53    private static native void nativeSetTransparentRegionHint(long nativeObject, Region region);
54    private static native void nativeSetAlpha(long nativeObject, float alpha);
55    private static native void nativeSetMatrix(long nativeObject, float dsdx, float dtdx, float dsdy, float dtdy);
56    private static native void nativeSetFlags(long nativeObject, int flags, int mask);
57    private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b);
58    private static native void nativeSetLayerStack(long nativeObject, int layerStack);
59
60    private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
61    private static native IBinder nativeCreateDisplay(String name, boolean secure);
62    private static native void nativeDestroyDisplay(IBinder displayToken);
63    private static native void nativeSetDisplaySurface(
64            IBinder displayToken, long nativeSurfaceObject);
65    private static native void nativeSetDisplayLayerStack(
66            IBinder displayToken, int layerStack);
67    private static native void nativeSetDisplayProjection(
68            IBinder displayToken, int orientation,
69            int l, int t, int r, int b,
70            int L, int T, int R, int B);
71    private static native boolean nativeGetDisplayInfo(
72            IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo);
73    private static native void nativeBlankDisplay(IBinder displayToken);
74    private static native void nativeUnblankDisplay(IBinder displayToken);
75
76
77    private final CloseGuard mCloseGuard = CloseGuard.get();
78    private final String mName;
79    long mNativeObject; // package visibility only for Surface.java access
80
81    /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
82
83    /**
84     * Surface creation flag: Surface is created hidden
85     */
86    public static final int HIDDEN = 0x00000004;
87
88    /**
89     * Surface creation flag: The surface contains secure content, special
90     * measures will be taken to disallow the surface's content to be copied
91     * from another process. In particular, screenshots and VNC servers will
92     * be disabled, but other measures can take place, for instance the
93     * surface might not be hardware accelerated.
94     *
95     */
96    public static final int SECURE = 0x00000080;
97
98    /**
99     * Surface creation flag: Creates a surface where color components are interpreted
100     * as "non pre-multiplied" by their alpha channel. Of course this flag is
101     * meaningless for surfaces without an alpha channel. By default
102     * surfaces are pre-multiplied, which means that each color component is
103     * already multiplied by its alpha value. In this case the blending
104     * equation used is:
105     *
106     *    DEST = SRC + DEST * (1-SRC_ALPHA)
107     *
108     * By contrast, non pre-multiplied surfaces use the following equation:
109     *
110     *    DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA)
111     *
112     * pre-multiplied surfaces must always be used if transparent pixels are
113     * composited on top of each-other into the surface. A pre-multiplied
114     * surface can never lower the value of the alpha component of a given
115     * pixel.
116     *
117     * In some rare situations, a non pre-multiplied surface is preferable.
118     *
119     */
120    public static final int NON_PREMULTIPLIED = 0x00000100;
121
122    /**
123     * Surface creation flag: Indicates that the surface must be considered opaque,
124     * even if its pixel format is set to translucent. This can be useful if an
125     * application needs full RGBA 8888 support for instance but will
126     * still draw every pixel opaque.
127     *
128     */
129    public static final int OPAQUE = 0x00000400;
130
131    /**
132     * Surface creation flag: Application requires a hardware-protected path to an
133     * external display sink. If a hardware-protected path is not available,
134     * then this surface will not be displayed on the external sink.
135     *
136     */
137    public static final int PROTECTED_APP = 0x00000800;
138
139    // 0x1000 is reserved for an independent DRM protected flag in framework
140
141    /**
142     * Surface creation flag: Creates a normal surface.
143     * This is the default.
144     *
145     */
146    public static final int FX_SURFACE_NORMAL   = 0x00000000;
147
148    /**
149     * Surface creation flag: Creates a Dim surface.
150     * Everything behind this surface is dimmed by the amount specified
151     * in {@link #setAlpha}.  It is an error to lock a Dim surface, since it
152     * doesn't have a backing store.
153     *
154     */
155    public static final int FX_SURFACE_DIM = 0x00020000;
156
157    /**
158     * Mask used for FX values above.
159     *
160     */
161    public static final int FX_SURFACE_MASK = 0x000F0000;
162
163    /* flags used with setFlags() (keep in sync with ISurfaceComposer.h) */
164
165    /**
166     * Surface flag: Hide the surface.
167     * Equivalent to calling hide().
168     */
169    public static final int SURFACE_HIDDEN = 0x01;
170
171
172    /* built-in physical display ids (keep in sync with ISurfaceComposer.h)
173     * these are different from the logical display ids used elsewhere in the framework */
174
175    /**
176     * Built-in physical display id: Main display.
177     * Use only with {@link SurfaceControl#getBuiltInDisplay()}.
178     */
179    public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
180
181    /**
182     * Built-in physical display id: Attached HDMI display.
183     * Use only with {@link SurfaceControl#getBuiltInDisplay()}.
184     */
185    public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
186
187
188
189    /**
190     * Create a surface with a name.
191     *
192     * The surface creation flags specify what kind of surface to create and
193     * certain options such as whether the surface can be assumed to be opaque
194     * and whether it should be initially hidden.  Surfaces should always be
195     * created with the {@link #HIDDEN} flag set to ensure that they are not
196     * made visible prematurely before all of the surface's properties have been
197     * configured.
198     *
199     * Good practice is to first create the surface with the {@link #HIDDEN} flag
200     * specified, open a transaction, set the surface layer, layer stack, alpha,
201     * and position, call {@link #show} if appropriate, and close the transaction.
202     *
203     * @param session The surface session, must not be null.
204     * @param name The surface name, must not be null.
205     * @param w The surface initial width.
206     * @param h The surface initial height.
207     * @param flags The surface creation flags.  Should always include {@link #HIDDEN}
208     * in the creation flags.
209     *
210     * @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
211     */
212    public SurfaceControl(SurfaceSession session,
213            String name, int w, int h, int format, int flags)
214                    throws OutOfResourcesException {
215        if (session == null) {
216            throw new IllegalArgumentException("session must not be null");
217        }
218        if (name == null) {
219            throw new IllegalArgumentException("name must not be null");
220        }
221
222        if ((flags & SurfaceControl.HIDDEN) == 0) {
223            Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set "
224                    + "to ensure that they are not made visible prematurely before "
225                    + "all of the surface's properties have been configured.  "
226                    + "Set the other properties and make the surface visible within "
227                    + "a transaction.  New surface name: " + name,
228                    new Throwable());
229        }
230
231        mName = name;
232        mNativeObject = nativeCreate(session, name, w, h, format, flags);
233        if (mNativeObject == 0) {
234            throw new OutOfResourcesException(
235                    "Couldn't allocate SurfaceControl native object");
236        }
237
238        mCloseGuard.open("release");
239    }
240
241    @Override
242    protected void finalize() throws Throwable {
243        try {
244            if (mCloseGuard != null) {
245                mCloseGuard.warnIfOpen();
246            }
247            if (mNativeObject != 0) {
248                nativeRelease(mNativeObject);
249            }
250        } finally {
251            super.finalize();
252        }
253    }
254
255    @Override
256    public String toString() {
257        return "Surface(name=" + mName + ")";
258    }
259
260    /**
261     * Release the local reference to the server-side surface.
262     * Always call release() when you're done with a Surface.
263     * This will make the surface invalid.
264     */
265    public void release() {
266        if (mNativeObject != 0) {
267            nativeRelease(mNativeObject);
268            mNativeObject = 0;
269        }
270        mCloseGuard.close();
271    }
272
273    /**
274     * Free all server-side state associated with this surface and
275     * release this object's reference.  This method can only be
276     * called from the process that created the service.
277     */
278    public void destroy() {
279        if (mNativeObject != 0) {
280            nativeDestroy(mNativeObject);
281            mNativeObject = 0;
282        }
283        mCloseGuard.close();
284    }
285
286    private void checkNotReleased() {
287        if (mNativeObject == 0) throw new NullPointerException(
288                "mNativeObject is null. Have you called release() already?");
289    }
290
291    /*
292     * set surface parameters.
293     * needs to be inside open/closeTransaction block
294     */
295
296    /** start a transaction */
297    public static void openTransaction() {
298        nativeOpenTransaction();
299    }
300
301    /** end a transaction */
302    public static void closeTransaction() {
303        nativeCloseTransaction();
304    }
305
306    /** flag the transaction as an animation */
307    public static void setAnimationTransaction() {
308        nativeSetAnimationTransaction();
309    }
310
311    public void setLayer(int zorder) {
312        checkNotReleased();
313        nativeSetLayer(mNativeObject, zorder);
314    }
315
316    public void setPosition(float x, float y) {
317        checkNotReleased();
318        nativeSetPosition(mNativeObject, x, y);
319    }
320
321    public void setSize(int w, int h) {
322        checkNotReleased();
323        nativeSetSize(mNativeObject, w, h);
324    }
325
326    public void hide() {
327        checkNotReleased();
328        nativeSetFlags(mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
329    }
330
331    public void show() {
332        checkNotReleased();
333        nativeSetFlags(mNativeObject, 0, SURFACE_HIDDEN);
334    }
335
336    public void setTransparentRegionHint(Region region) {
337        checkNotReleased();
338        nativeSetTransparentRegionHint(mNativeObject, region);
339    }
340
341    public void setAlpha(float alpha) {
342        checkNotReleased();
343        nativeSetAlpha(mNativeObject, alpha);
344    }
345
346    public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
347        checkNotReleased();
348        nativeSetMatrix(mNativeObject, dsdx, dtdx, dsdy, dtdy);
349    }
350
351    public void setFlags(int flags, int mask) {
352        checkNotReleased();
353        nativeSetFlags(mNativeObject, flags, mask);
354    }
355
356    public void setWindowCrop(Rect crop) {
357        checkNotReleased();
358        if (crop != null) {
359            nativeSetWindowCrop(mNativeObject,
360                crop.left, crop.top, crop.right, crop.bottom);
361        } else {
362            nativeSetWindowCrop(mNativeObject, 0, 0, 0, 0);
363        }
364    }
365
366    public void setLayerStack(int layerStack) {
367        checkNotReleased();
368        nativeSetLayerStack(mNativeObject, layerStack);
369    }
370
371    /*
372     * set display parameters.
373     * needs to be inside open/closeTransaction block
374     */
375
376    /**
377     * Describes the properties of a physical display known to surface flinger.
378     */
379    public static final class PhysicalDisplayInfo {
380        public int width;
381        public int height;
382        public float refreshRate;
383        public float density;
384        public float xDpi;
385        public float yDpi;
386        public boolean secure;
387
388        public PhysicalDisplayInfo() {
389        }
390
391        public PhysicalDisplayInfo(PhysicalDisplayInfo other) {
392            copyFrom(other);
393        }
394
395        @Override
396        public boolean equals(Object o) {
397            return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o);
398        }
399
400        public boolean equals(PhysicalDisplayInfo other) {
401            return other != null
402                    && width == other.width
403                    && height == other.height
404                    && refreshRate == other.refreshRate
405                    && density == other.density
406                    && xDpi == other.xDpi
407                    && yDpi == other.yDpi
408                    && secure == other.secure;
409        }
410
411        @Override
412        public int hashCode() {
413            return 0; // don't care
414        }
415
416        public void copyFrom(PhysicalDisplayInfo other) {
417            width = other.width;
418            height = other.height;
419            refreshRate = other.refreshRate;
420            density = other.density;
421            xDpi = other.xDpi;
422            yDpi = other.yDpi;
423            secure = other.secure;
424        }
425
426        // For debugging purposes
427        @Override
428        public String toString() {
429            return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
430                    + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure
431                    + "}";
432        }
433    }
434
435    public static void unblankDisplay(IBinder displayToken) {
436        if (displayToken == null) {
437            throw new IllegalArgumentException("displayToken must not be null");
438        }
439        nativeUnblankDisplay(displayToken);
440    }
441
442    public static void blankDisplay(IBinder displayToken) {
443        if (displayToken == null) {
444            throw new IllegalArgumentException("displayToken must not be null");
445        }
446        nativeBlankDisplay(displayToken);
447    }
448
449    public static boolean getDisplayInfo(IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo) {
450        if (displayToken == null) {
451            throw new IllegalArgumentException("displayToken must not be null");
452        }
453        if (outInfo == null) {
454            throw new IllegalArgumentException("outInfo must not be null");
455        }
456        return nativeGetDisplayInfo(displayToken, outInfo);
457    }
458
459    public static void setDisplayProjection(IBinder displayToken,
460            int orientation, Rect layerStackRect, Rect displayRect) {
461        if (displayToken == null) {
462            throw new IllegalArgumentException("displayToken must not be null");
463        }
464        if (layerStackRect == null) {
465            throw new IllegalArgumentException("layerStackRect must not be null");
466        }
467        if (displayRect == null) {
468            throw new IllegalArgumentException("displayRect must not be null");
469        }
470        nativeSetDisplayProjection(displayToken, orientation,
471                layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom,
472                displayRect.left, displayRect.top, displayRect.right, displayRect.bottom);
473    }
474
475    public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
476        if (displayToken == null) {
477            throw new IllegalArgumentException("displayToken must not be null");
478        }
479        nativeSetDisplayLayerStack(displayToken, layerStack);
480    }
481
482    public static void setDisplaySurface(IBinder displayToken, Surface surface) {
483        if (displayToken == null) {
484            throw new IllegalArgumentException("displayToken must not be null");
485        }
486
487        if (surface != null) {
488            synchronized (surface.mLock) {
489                nativeSetDisplaySurface(displayToken, surface.mNativeObject);
490            }
491        } else {
492            nativeSetDisplaySurface(displayToken, 0);
493        }
494    }
495
496    public static IBinder createDisplay(String name, boolean secure) {
497        if (name == null) {
498            throw new IllegalArgumentException("name must not be null");
499        }
500        return nativeCreateDisplay(name, secure);
501    }
502
503    public static void destroyDisplay(IBinder displayToken) {
504        if (displayToken == null) {
505            throw new IllegalArgumentException("displayToken must not be null");
506        }
507        nativeDestroyDisplay(displayToken);
508    }
509
510    public static IBinder getBuiltInDisplay(int builtInDisplayId) {
511        return nativeGetBuiltInDisplay(builtInDisplayId);
512    }
513
514
515    /**
516     * Copy the current screen contents into the provided {@link Surface}
517     *
518     * @param display The display to take the screenshot of.
519     * @param consumer The {@link Surface} to take the screenshot into.
520     * @param width The desired width of the returned bitmap; the raw
521     * screen will be scaled down to this size.
522     * @param height The desired height of the returned bitmap; the raw
523     * screen will be scaled down to this size.
524     * @param minLayer The lowest (bottom-most Z order) surface layer to
525     * include in the screenshot.
526     * @param maxLayer The highest (top-most Z order) surface layer to
527     * include in the screenshot.
528     */
529    public static void screenshot(IBinder display, Surface consumer,
530            int width, int height, int minLayer, int maxLayer) {
531        screenshot(display, consumer, width, height, minLayer, maxLayer, false);
532    }
533
534    /**
535     * Copy the current screen contents into the provided {@link Surface}
536     *
537     * @param display The display to take the screenshot of.
538     * @param consumer The {@link Surface} to take the screenshot into.
539     * @param width The desired width of the returned bitmap; the raw
540     * screen will be scaled down to this size.
541     * @param height The desired height of the returned bitmap; the raw
542     * screen will be scaled down to this size.
543     */
544    public static void screenshot(IBinder display, Surface consumer,
545            int width, int height) {
546        screenshot(display, consumer, width, height, 0, 0, true);
547    }
548
549    /**
550     * Copy the current screen contents into the provided {@link Surface}
551     *
552     * @param display The display to take the screenshot of.
553     * @param consumer The {@link Surface} to take the screenshot into.
554     */
555    public static void screenshot(IBinder display, Surface consumer) {
556        screenshot(display, consumer, 0, 0, 0, 0, true);
557    }
558
559
560    /**
561     * Copy the current screen contents into a bitmap and return it.
562     *
563     * CAVEAT: Versions of screenshot that return a {@link Bitmap} can
564     * be extremely slow; avoid use unless absolutely necessary; prefer
565     * the versions that use a {@link Surface} instead, such as
566     * {@link SurfaceControl#screenshot(IBinder, Surface)}.
567     *
568     * @param width The desired width of the returned bitmap; the raw
569     * screen will be scaled down to this size.
570     * @param height The desired height of the returned bitmap; the raw
571     * screen will be scaled down to this size.
572     * @param minLayer The lowest (bottom-most Z order) surface layer to
573     * include in the screenshot.
574     * @param maxLayer The highest (top-most Z order) surface layer to
575     * include in the screenshot.
576     * @return Returns a Bitmap containing the screen contents, or null
577     * if an error occurs. Make sure to call Bitmap.recycle() as soon as
578     * possible, once its content is not needed anymore.
579     */
580    public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) {
581        // TODO: should take the display as a parameter
582        IBinder displayToken = SurfaceControl.getBuiltInDisplay(
583                SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
584        return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false);
585    }
586
587    /**
588     * Like {@link SurfaceControl#screenshot(int, int, int, int)} but includes all
589     * Surfaces in the screenshot.
590     *
591     * @param width The desired width of the returned bitmap; the raw
592     * screen will be scaled down to this size.
593     * @param height The desired height of the returned bitmap; the raw
594     * screen will be scaled down to this size.
595     * @return Returns a Bitmap containing the screen contents, or null
596     * if an error occurs. Make sure to call Bitmap.recycle() as soon as
597     * possible, once its content is not needed anymore.
598     */
599    public static Bitmap screenshot(int width, int height) {
600        // TODO: should take the display as a parameter
601        IBinder displayToken = SurfaceControl.getBuiltInDisplay(
602                SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
603        return nativeScreenshot(displayToken, width, height, 0, 0, true);
604    }
605
606    private static void screenshot(IBinder display, Surface consumer,
607            int width, int height, int minLayer, int maxLayer, boolean allLayers) {
608        if (display == null) {
609            throw new IllegalArgumentException("displayToken must not be null");
610        }
611        if (consumer == null) {
612            throw new IllegalArgumentException("consumer must not be null");
613        }
614        nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers);
615    }
616}
617