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