Home | History | Annotate | Download | only in view
      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.GraphicBuffer;
     23 import android.graphics.Matrix;
     24 import android.graphics.Rect;
     25 import android.graphics.SurfaceTexture;
     26 import android.os.Parcel;
     27 import android.os.Parcelable;
     28 import android.util.Log;
     29 
     30 import dalvik.system.CloseGuard;
     31 
     32 import java.lang.annotation.Retention;
     33 import java.lang.annotation.RetentionPolicy;
     34 
     35 /**
     36  * Handle onto a raw buffer that is being managed by the screen compositor.
     37  *
     38  * <p>A Surface is generally created by or from a consumer of image buffers (such as a
     39  * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or
     40  * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as
     41  * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL},
     42  * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or
     43  * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw
     44  * into.</p>
     45  *
     46  * <p><strong>Note:</strong> A Surface acts like a
     47  * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By
     48  * itself it will not keep its parent consumer from being reclaimed.</p>
     49  */
     50 public class Surface implements Parcelable {
     51     private static final String TAG = "Surface";
     52 
     53     private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
     54             throws OutOfResourcesException;
     55 
     56     private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject);
     57     private static native long nativeGetFromSurfaceControl(long surfaceControlNativeObject);
     58 
     59     private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
     60             throws OutOfResourcesException;
     61     private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
     62 
     63     private static native void nativeRelease(long nativeObject);
     64     private static native boolean nativeIsValid(long nativeObject);
     65     private static native boolean nativeIsConsumerRunningBehind(long nativeObject);
     66     private static native long nativeReadFromParcel(long nativeObject, Parcel source);
     67     private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
     68 
     69     private static native void nativeAllocateBuffers(long nativeObject);
     70 
     71     private static native int nativeGetWidth(long nativeObject);
     72     private static native int nativeGetHeight(long nativeObject);
     73 
     74     private static native long nativeGetNextFrameNumber(long nativeObject);
     75     private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
     76     private static native int nativeForceScopedDisconnect(long nativeObject);
     77     private static native int nativeAttachAndQueueBuffer(long nativeObject, GraphicBuffer buffer);
     78 
     79     private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled);
     80     private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled);
     81 
     82     public static final Parcelable.Creator<Surface> CREATOR =
     83             new Parcelable.Creator<Surface>() {
     84         @Override
     85         public Surface createFromParcel(Parcel source) {
     86             try {
     87                 Surface s = new Surface();
     88                 s.readFromParcel(source);
     89                 return s;
     90             } catch (Exception e) {
     91                 Log.e(TAG, "Exception creating surface from parcel", e);
     92                 return null;
     93             }
     94         }
     95 
     96         @Override
     97         public Surface[] newArray(int size) {
     98             return new Surface[size];
     99         }
    100     };
    101 
    102     private final CloseGuard mCloseGuard = CloseGuard.get();
    103 
    104     // Guarded state.
    105     final Object mLock = new Object(); // protects the native state
    106     private String mName;
    107     long mNativeObject; // package scope only for SurfaceControl access
    108     private long mLockedObject;
    109     private int mGenerationId; // incremented each time mNativeObject changes
    110     private final Canvas mCanvas = new CompatibleCanvas();
    111 
    112     // A matrix to scale the matrix set by application. This is set to null for
    113     // non compatibility mode.
    114     private Matrix mCompatibleMatrix;
    115 
    116     private HwuiContext mHwuiContext;
    117 
    118     private boolean mIsSingleBuffered;
    119     private boolean mIsSharedBufferModeEnabled;
    120     private boolean mIsAutoRefreshEnabled;
    121 
    122     /** @hide */
    123     @Retention(RetentionPolicy.SOURCE)
    124     @IntDef(prefix = { "SCALING_MODE_" }, value = {
    125             SCALING_MODE_FREEZE,
    126             SCALING_MODE_SCALE_TO_WINDOW,
    127             SCALING_MODE_SCALE_CROP,
    128             SCALING_MODE_NO_SCALE_CROP
    129     })
    130     public @interface ScalingMode {}
    131     // From system/window.h
    132     /** @hide */
    133     public static final int SCALING_MODE_FREEZE = 0;
    134     /** @hide */
    135     public static final int SCALING_MODE_SCALE_TO_WINDOW = 1;
    136     /** @hide */
    137     public static final int SCALING_MODE_SCALE_CROP = 2;
    138     /** @hide */
    139     public static final int SCALING_MODE_NO_SCALE_CROP = 3;
    140 
    141     /** @hide */
    142     @IntDef(prefix = { "ROTATION_" }, value = {
    143             ROTATION_0,
    144             ROTATION_90,
    145             ROTATION_180,
    146             ROTATION_270
    147     })
    148     @Retention(RetentionPolicy.SOURCE)
    149     public @interface Rotation {}
    150 
    151     /**
    152      * Rotation constant: 0 degree rotation (natural orientation)
    153      */
    154     public static final int ROTATION_0 = 0;
    155 
    156     /**
    157      * Rotation constant: 90 degree rotation.
    158      */
    159     public static final int ROTATION_90 = 1;
    160 
    161     /**
    162      * Rotation constant: 180 degree rotation.
    163      */
    164     public static final int ROTATION_180 = 2;
    165 
    166     /**
    167      * Rotation constant: 270 degree rotation.
    168      */
    169     public static final int ROTATION_270 = 3;
    170 
    171     /**
    172      * Create an empty surface, which will later be filled in by readFromParcel().
    173      * @hide
    174      */
    175     public Surface() {
    176     }
    177 
    178     /**
    179      * Create Surface from a {@link SurfaceTexture}.
    180      *
    181      * Images drawn to the Surface will be made available to the {@link
    182      * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
    183      * SurfaceTexture#updateTexImage}.
    184      *
    185      * Please note that holding onto the Surface created here is not enough to
    186      * keep the provided SurfaceTexture from being reclaimed.  In that sense,
    187      * the Surface will act like a
    188      * {@link java.lang.ref.WeakReference weak reference} to the SurfaceTexture.
    189      *
    190      * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
    191      * Surface.
    192      * @throws OutOfResourcesException if the surface could not be created.
    193      */
    194     public Surface(SurfaceTexture surfaceTexture) {
    195         if (surfaceTexture == null) {
    196             throw new IllegalArgumentException("surfaceTexture must not be null");
    197         }
    198         mIsSingleBuffered = surfaceTexture.isSingleBuffered();
    199         synchronized (mLock) {
    200             mName = surfaceTexture.toString();
    201             setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
    202         }
    203     }
    204 
    205     /* called from android_view_Surface_createFromIGraphicBufferProducer() */
    206     private Surface(long nativeObject) {
    207         synchronized (mLock) {
    208             setNativeObjectLocked(nativeObject);
    209         }
    210     }
    211 
    212     @Override
    213     protected void finalize() throws Throwable {
    214         try {
    215             if (mCloseGuard != null) {
    216                 mCloseGuard.warnIfOpen();
    217             }
    218             release();
    219         } finally {
    220             super.finalize();
    221         }
    222     }
    223 
    224     /**
    225      * Release the local reference to the server-side surface.
    226      * Always call release() when you're done with a Surface.
    227      * This will make the surface invalid.
    228      */
    229     public void release() {
    230         synchronized (mLock) {
    231             if (mNativeObject != 0) {
    232                 nativeRelease(mNativeObject);
    233                 setNativeObjectLocked(0);
    234             }
    235             if (mHwuiContext != null) {
    236                 mHwuiContext.destroy();
    237                 mHwuiContext = null;
    238             }
    239         }
    240     }
    241 
    242     /**
    243      * Free all server-side state associated with this surface and
    244      * release this object's reference.  This method can only be
    245      * called from the process that created the service.
    246      * @hide
    247      */
    248     public void destroy() {
    249         release();
    250     }
    251 
    252     /**
    253      * Destroys the HwuiContext without completely
    254      * releasing the Surface.
    255      * @hide
    256      */
    257     public void hwuiDestroy() {
    258         if (mHwuiContext != null) {
    259             mHwuiContext.destroy();
    260             mHwuiContext = null;
    261         }
    262     }
    263 
    264     /**
    265      * Returns true if this object holds a valid surface.
    266      *
    267      * @return True if it holds a physical surface, so lockCanvas() will succeed.
    268      * Otherwise returns false.
    269      */
    270     public boolean isValid() {
    271         synchronized (mLock) {
    272             if (mNativeObject == 0) return false;
    273             return nativeIsValid(mNativeObject);
    274         }
    275     }
    276 
    277     /**
    278      * Gets the generation number of this surface, incremented each time
    279      * the native surface contained within this object changes.
    280      *
    281      * @return The current generation number.
    282      * @hide
    283      */
    284     public int getGenerationId() {
    285         synchronized (mLock) {
    286             return mGenerationId;
    287         }
    288     }
    289 
    290     /**
    291      * Returns the next frame number which will be dequeued for rendering.
    292      * Intended for use with SurfaceFlinger's deferred transactions API.
    293      *
    294      * @hide
    295      */
    296     public long getNextFrameNumber() {
    297         synchronized (mLock) {
    298             checkNotReleasedLocked();
    299             return nativeGetNextFrameNumber(mNativeObject);
    300         }
    301     }
    302 
    303     /**
    304      * Returns true if the consumer of this Surface is running behind the producer.
    305      *
    306      * @return True if the consumer is more than one buffer ahead of the producer.
    307      * @hide
    308      */
    309     public boolean isConsumerRunningBehind() {
    310         synchronized (mLock) {
    311             checkNotReleasedLocked();
    312             return nativeIsConsumerRunningBehind(mNativeObject);
    313         }
    314     }
    315 
    316     /**
    317      * Gets a {@link Canvas} for drawing into this surface.
    318      *
    319      * After drawing into the provided {@link Canvas}, the caller must
    320      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
    321      *
    322      * @param inOutDirty A rectangle that represents the dirty region that the caller wants
    323      * to redraw.  This function may choose to expand the dirty rectangle if for example
    324      * the surface has been resized or if the previous contents of the surface were
    325      * not available.  The caller must redraw the entire dirty region as represented
    326      * by the contents of the inOutDirty rectangle upon return from this function.
    327      * The caller may also pass <code>null</code> instead, in the case where the
    328      * entire surface should be redrawn.
    329      * @return A canvas for drawing into the surface.
    330      *
    331      * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
    332      * @throws OutOfResourcesException If the canvas cannot be locked.
    333      */
    334     public Canvas lockCanvas(Rect inOutDirty)
    335             throws Surface.OutOfResourcesException, IllegalArgumentException {
    336         synchronized (mLock) {
    337             checkNotReleasedLocked();
    338             if (mLockedObject != 0) {
    339                 // Ideally, nativeLockCanvas() would throw in this situation and prevent the
    340                 // double-lock, but that won't happen if mNativeObject was updated.  We can't
    341                 // abandon the old mLockedObject because it might still be in use, so instead
    342                 // we just refuse to re-lock the Surface.
    343                 throw new IllegalArgumentException("Surface was already locked");
    344             }
    345             mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
    346             return mCanvas;
    347         }
    348     }
    349 
    350     /**
    351      * Posts the new contents of the {@link Canvas} to the surface and
    352      * releases the {@link Canvas}.
    353      *
    354      * @param canvas The canvas previously obtained from {@link #lockCanvas}.
    355      */
    356     public void unlockCanvasAndPost(Canvas canvas) {
    357         synchronized (mLock) {
    358             checkNotReleasedLocked();
    359 
    360             if (mHwuiContext != null) {
    361                 mHwuiContext.unlockAndPost(canvas);
    362             } else {
    363                 unlockSwCanvasAndPost(canvas);
    364             }
    365         }
    366     }
    367 
    368     private void unlockSwCanvasAndPost(Canvas canvas) {
    369         if (canvas != mCanvas) {
    370             throw new IllegalArgumentException("canvas object must be the same instance that "
    371                     + "was previously returned by lockCanvas");
    372         }
    373         if (mNativeObject != mLockedObject) {
    374             Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
    375                     Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
    376                     Long.toHexString(mLockedObject) +")");
    377         }
    378         if (mLockedObject == 0) {
    379             throw new IllegalStateException("Surface was not locked");
    380         }
    381         try {
    382             nativeUnlockCanvasAndPost(mLockedObject, canvas);
    383         } finally {
    384             nativeRelease(mLockedObject);
    385             mLockedObject = 0;
    386         }
    387     }
    388 
    389     /**
    390      * Gets a {@link Canvas} for drawing into this surface.
    391      *
    392      * After drawing into the provided {@link Canvas}, the caller must
    393      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
    394      *
    395      * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
    396      * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
    397      * unsupported drawing operations</a> for a list of what is and isn't
    398      * supported in a hardware-accelerated canvas. It is also required to
    399      * fully cover the surface every time {@link #lockHardwareCanvas()} is
    400      * called as the buffer is not preserved between frames. Partial updates
    401      * are not supported.
    402      *
    403      * @return A canvas for drawing into the surface.
    404      *
    405      * @throws IllegalStateException If the canvas cannot be locked.
    406      */
    407     public Canvas lockHardwareCanvas() {
    408         synchronized (mLock) {
    409             checkNotReleasedLocked();
    410             if (mHwuiContext == null) {
    411                 mHwuiContext = new HwuiContext(false);
    412             }
    413             return mHwuiContext.lockCanvas(
    414                     nativeGetWidth(mNativeObject),
    415                     nativeGetHeight(mNativeObject));
    416         }
    417     }
    418 
    419     /**
    420      * Gets a {@link Canvas} for drawing into this surface that supports wide color gamut.
    421      *
    422      * After drawing into the provided {@link Canvas}, the caller must
    423      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
    424      *
    425      * Unlike {@link #lockCanvas(Rect)} and {@link #lockHardwareCanvas()},
    426      * this will return a hardware-accelerated canvas that supports wide color gamut.
    427      * See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
    428      * unsupported drawing operations</a> for a list of what is and isn't
    429      * supported in a hardware-accelerated canvas. It is also required to
    430      * fully cover the surface every time {@link #lockHardwareCanvas()} is
    431      * called as the buffer is not preserved between frames. Partial updates
    432      * are not supported.
    433      *
    434      * @return A canvas for drawing into the surface.
    435      *
    436      * @throws IllegalStateException If the canvas cannot be locked.
    437      *
    438      * @hide
    439      */
    440     public Canvas lockHardwareWideColorGamutCanvas() {
    441         synchronized (mLock) {
    442             checkNotReleasedLocked();
    443             if (mHwuiContext != null && !mHwuiContext.isWideColorGamut()) {
    444                 mHwuiContext.destroy();
    445                 mHwuiContext = null;
    446             }
    447             if (mHwuiContext == null) {
    448                 mHwuiContext = new HwuiContext(true);
    449             }
    450             return mHwuiContext.lockCanvas(
    451                     nativeGetWidth(mNativeObject),
    452                     nativeGetHeight(mNativeObject));
    453         }
    454     }
    455 
    456     /**
    457      * @deprecated This API has been removed and is not supported.  Do not use.
    458      */
    459     @Deprecated
    460     public void unlockCanvas(Canvas canvas) {
    461         throw new UnsupportedOperationException();
    462     }
    463 
    464     /**
    465      * Sets the translator used to scale canvas's width/height in compatibility
    466      * mode.
    467      */
    468     void setCompatibilityTranslator(Translator translator) {
    469         if (translator != null) {
    470             float appScale = translator.applicationScale;
    471             mCompatibleMatrix = new Matrix();
    472             mCompatibleMatrix.setScale(appScale, appScale);
    473         }
    474     }
    475 
    476     /**
    477      * Copy another surface to this one.  This surface now holds a reference
    478      * to the same data as the original surface, and is -not- the owner.
    479      * This is for use by the window manager when returning a window surface
    480      * back from a client, converting it from the representation being managed
    481      * by the window manager to the representation the client uses to draw
    482      * in to it.
    483      *
    484      * @param other {@link SurfaceControl} to copy from.
    485      *
    486      * @hide
    487      */
    488     public void copyFrom(SurfaceControl other) {
    489         if (other == null) {
    490             throw new IllegalArgumentException("other must not be null");
    491         }
    492 
    493         long surfaceControlPtr = other.mNativeObject;
    494         if (surfaceControlPtr == 0) {
    495             throw new NullPointerException(
    496                     "null SurfaceControl native object. Are you using a released SurfaceControl?");
    497         }
    498         long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
    499 
    500         synchronized (mLock) {
    501             if (mNativeObject != 0) {
    502                 nativeRelease(mNativeObject);
    503             }
    504             setNativeObjectLocked(newNativeObject);
    505         }
    506     }
    507 
    508     /**
    509      * Gets a reference a surface created from this one.  This surface now holds a reference
    510      * to the same data as the original surface, and is -not- the owner.
    511      * This is for use by the window manager when returning a window surface
    512      * back from a client, converting it from the representation being managed
    513      * by the window manager to the representation the client uses to draw
    514      * in to it.
    515      *
    516      * @param other {@link SurfaceControl} to create surface from.
    517      *
    518      * @hide
    519      */
    520     public void createFrom(SurfaceControl other) {
    521         if (other == null) {
    522             throw new IllegalArgumentException("other must not be null");
    523         }
    524 
    525         long surfaceControlPtr = other.mNativeObject;
    526         if (surfaceControlPtr == 0) {
    527             throw new NullPointerException(
    528                     "null SurfaceControl native object. Are you using a released SurfaceControl?");
    529         }
    530         long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
    531 
    532         synchronized (mLock) {
    533             if (mNativeObject != 0) {
    534                 nativeRelease(mNativeObject);
    535             }
    536             setNativeObjectLocked(newNativeObject);
    537         }
    538     }
    539 
    540     /**
    541      * This is intended to be used by {@link SurfaceView#updateWindow} only.
    542      * @param other access is not thread safe
    543      * @hide
    544      * @deprecated
    545      */
    546     @Deprecated
    547     public void transferFrom(Surface other) {
    548         if (other == null) {
    549             throw new IllegalArgumentException("other must not be null");
    550         }
    551         if (other != this) {
    552             final long newPtr;
    553             synchronized (other.mLock) {
    554                 newPtr = other.mNativeObject;
    555                 other.setNativeObjectLocked(0);
    556             }
    557 
    558             synchronized (mLock) {
    559                 if (mNativeObject != 0) {
    560                     nativeRelease(mNativeObject);
    561                 }
    562                 setNativeObjectLocked(newPtr);
    563             }
    564         }
    565     }
    566 
    567     @Override
    568     public int describeContents() {
    569         return 0;
    570     }
    571 
    572     public void readFromParcel(Parcel source) {
    573         if (source == null) {
    574             throw new IllegalArgumentException("source must not be null");
    575         }
    576 
    577         synchronized (mLock) {
    578             // nativeReadFromParcel() will either return mNativeObject, or
    579             // create a new native Surface and return it after reducing
    580             // the reference count on mNativeObject.  Either way, it is
    581             // not necessary to call nativeRelease() here.
    582             // NOTE: This must be kept synchronized with the native parceling code
    583             // in frameworks/native/libs/Surface.cpp
    584             mName = source.readString();
    585             mIsSingleBuffered = source.readInt() != 0;
    586             setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
    587         }
    588     }
    589 
    590     @Override
    591     public void writeToParcel(Parcel dest, int flags) {
    592         if (dest == null) {
    593             throw new IllegalArgumentException("dest must not be null");
    594         }
    595         synchronized (mLock) {
    596             // NOTE: This must be kept synchronized with the native parceling code
    597             // in frameworks/native/libs/Surface.cpp
    598             dest.writeString(mName);
    599             dest.writeInt(mIsSingleBuffered ? 1 : 0);
    600             nativeWriteToParcel(mNativeObject, dest);
    601         }
    602         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
    603             release();
    604         }
    605     }
    606 
    607     @Override
    608     public String toString() {
    609         synchronized (mLock) {
    610             return "Surface(name=" + mName + ")/@0x" +
    611                     Integer.toHexString(System.identityHashCode(this));
    612         }
    613     }
    614 
    615     private void setNativeObjectLocked(long ptr) {
    616         if (mNativeObject != ptr) {
    617             if (mNativeObject == 0 && ptr != 0) {
    618                 mCloseGuard.open("release");
    619             } else if (mNativeObject != 0 && ptr == 0) {
    620                 mCloseGuard.close();
    621             }
    622             mNativeObject = ptr;
    623             mGenerationId += 1;
    624             if (mHwuiContext != null) {
    625                 mHwuiContext.updateSurface();
    626             }
    627         }
    628     }
    629 
    630     private void checkNotReleasedLocked() {
    631         if (mNativeObject == 0) {
    632             throw new IllegalStateException("Surface has already been released.");
    633         }
    634     }
    635 
    636     /**
    637      * Allocate buffers ahead of time to avoid allocation delays during rendering
    638      * @hide
    639      */
    640     public void allocateBuffers() {
    641         synchronized (mLock) {
    642             checkNotReleasedLocked();
    643             nativeAllocateBuffers(mNativeObject);
    644         }
    645     }
    646 
    647     /**
    648      * Set the scaling mode to be used for this surfaces buffers
    649      * @hide
    650      */
    651     void setScalingMode(@ScalingMode int scalingMode) {
    652         synchronized (mLock) {
    653             checkNotReleasedLocked();
    654             int err = nativeSetScalingMode(mNativeObject, scalingMode);
    655             if (err != 0) {
    656                 throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode);
    657             }
    658         }
    659     }
    660 
    661     void forceScopedDisconnect() {
    662         synchronized (mLock) {
    663             checkNotReleasedLocked();
    664             int err = nativeForceScopedDisconnect(mNativeObject);
    665             if (err != 0) {
    666                 throw new RuntimeException("Failed to disconnect Surface instance (bad object?)");
    667             }
    668         }
    669     }
    670 
    671     /**
    672      * Transfer ownership of buffer and present it on the Surface.
    673      * @hide
    674      */
    675     public void attachAndQueueBuffer(GraphicBuffer buffer) {
    676         synchronized (mLock) {
    677             checkNotReleasedLocked();
    678             int err = nativeAttachAndQueueBuffer(mNativeObject, buffer);
    679             if (err != 0) {
    680                 throw new RuntimeException(
    681                         "Failed to attach and queue buffer to Surface (bad object?)");
    682             }
    683         }
    684     }
    685 
    686     /**
    687      * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture
    688      * @hide
    689      */
    690     public boolean isSingleBuffered() {
    691         return mIsSingleBuffered;
    692     }
    693 
    694     /**
    695      * <p>The shared buffer mode allows both the application and the surface compositor
    696      * (SurfaceFlinger) to concurrently access this surface's buffer. While the
    697      * application is still required to issue a present request
    698      * (see {@link #unlockCanvasAndPost(Canvas)}) to the compositor when an update is required,
    699      * the compositor may trigger an update at any time. Since the surface's buffer is shared
    700      * between the application and the compositor, updates triggered by the compositor may
    701      * cause visible tearing.</p>
    702      *
    703      * <p>The shared buffer mode can be used with
    704      * {@link #setAutoRefreshEnabled(boolean) auto-refresh} to avoid the overhead of
    705      * issuing present requests.</p>
    706      *
    707      * <p>If the application uses the shared buffer mode to reduce latency, it is
    708      * recommended to use software rendering (see {@link #lockCanvas(Rect)} to ensure
    709      * the graphics workloads are not affected by other applications and/or the system
    710      * using the GPU. When using software rendering, the application should update the
    711      * smallest possible region of the surface required.</p>
    712      *
    713      * <p class="note">The shared buffer mode might not be supported by the underlying
    714      * hardware. Enabling shared buffer mode on hardware that does not support it will
    715      * not yield an error but the application will not benefit from lower latency (and
    716      * tearing will not be visible).</p>
    717      *
    718      * <p class="note">Depending on how many and what kind of surfaces are visible, the
    719      * surface compositor may need to copy the shared buffer before it is displayed. When
    720      * this happens, the latency benefits of shared buffer mode will be reduced.</p>
    721      *
    722      * @param enabled True to enable the shared buffer mode on this surface, false otherwise
    723      *
    724      * @see #isSharedBufferModeEnabled()
    725      * @see #setAutoRefreshEnabled(boolean)
    726      *
    727      * @hide
    728      */
    729     public void setSharedBufferModeEnabled(boolean enabled) {
    730         if (mIsSharedBufferModeEnabled != enabled) {
    731             int error = nativeSetSharedBufferModeEnabled(mNativeObject, enabled);
    732             if (error != 0) {
    733                 throw new RuntimeException(
    734                         "Failed to set shared buffer mode on Surface (bad object?)");
    735             } else {
    736                 mIsSharedBufferModeEnabled = enabled;
    737             }
    738         }
    739     }
    740 
    741     /**
    742      * @return True if shared buffer mode is enabled on this surface, false otherwise
    743      *
    744      * @see #setSharedBufferModeEnabled(boolean)
    745      *
    746      * @hide
    747      */
    748     public boolean isSharedBufferModeEnabled() {
    749         return mIsSharedBufferModeEnabled;
    750     }
    751 
    752     /**
    753      * <p>When auto-refresh is enabled, the surface compositor (SurfaceFlinger)
    754      * automatically updates the display on a regular refresh cycle. The application
    755      * can continue to issue present requests but it is not required. Enabling
    756      * auto-refresh may result in visible tearing.</p>
    757      *
    758      * <p>Auto-refresh has no effect if the {@link #setSharedBufferModeEnabled(boolean)
    759      * shared buffer mode} is not enabled.</p>
    760      *
    761      * <p>Because auto-refresh will trigger continuous updates of the display, it is
    762      * recommended to turn it on only when necessary. For example, in a drawing/painting
    763      * application auto-refresh should be enabled on finger/pen down and disabled on
    764      * finger/pen up.</p>
    765      *
    766      * @param enabled True to enable auto-refresh on this surface, false otherwise
    767      *
    768      * @see #isAutoRefreshEnabled()
    769      * @see #setSharedBufferModeEnabled(boolean)
    770      *
    771      * @hide
    772      */
    773     public void setAutoRefreshEnabled(boolean enabled) {
    774         if (mIsAutoRefreshEnabled != enabled) {
    775             int error = nativeSetAutoRefreshEnabled(mNativeObject, enabled);
    776             if (error != 0) {
    777                 throw new RuntimeException("Failed to set auto refresh on Surface (bad object?)");
    778             } else {
    779                 mIsAutoRefreshEnabled = enabled;
    780             }
    781         }
    782     }
    783 
    784     /**
    785      * @return True if auto-refresh is enabled on this surface, false otherwise
    786      *
    787      * @hide
    788      */
    789     public boolean isAutoRefreshEnabled() {
    790         return mIsAutoRefreshEnabled;
    791     }
    792 
    793     /**
    794      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
    795      * when a SurfaceTexture could not successfully be allocated.
    796      */
    797     @SuppressWarnings("serial")
    798     public static class OutOfResourcesException extends RuntimeException {
    799         public OutOfResourcesException() {
    800         }
    801         public OutOfResourcesException(String name) {
    802             super(name);
    803         }
    804     }
    805 
    806     /**
    807      * Returns a human readable representation of a rotation.
    808      *
    809      * @param rotation The rotation.
    810      * @return The rotation symbolic name.
    811      *
    812      * @hide
    813      */
    814     public static String rotationToString(int rotation) {
    815         switch (rotation) {
    816             case Surface.ROTATION_0: {
    817                 return "ROTATION_0";
    818             }
    819             case Surface.ROTATION_90: {
    820                 return "ROTATION_90";
    821             }
    822             case Surface.ROTATION_180: {
    823                 return "ROTATION_180";
    824             }
    825             case Surface.ROTATION_270: {
    826                 return "ROTATION_270";
    827             }
    828             default: {
    829                 return Integer.toString(rotation);
    830             }
    831         }
    832     }
    833 
    834     /**
    835      * A Canvas class that can handle the compatibility mode.
    836      * This does two things differently.
    837      * <ul>
    838      * <li>Returns the width and height of the target metrics, rather than
    839      * native. For example, the canvas returns 320x480 even if an app is running
    840      * in WVGA high density.
    841      * <li>Scales the matrix in setMatrix by the application scale, except if
    842      * the matrix looks like obtained from getMatrix. This is a hack to handle
    843      * the case that an application uses getMatrix to keep the original matrix,
    844      * set matrix of its own, then set the original matrix back. There is no
    845      * perfect solution that works for all cases, and there are a lot of cases
    846      * that this model does not work, but we hope this works for many apps.
    847      * </ul>
    848      */
    849     private final class CompatibleCanvas extends Canvas {
    850         // A temp matrix to remember what an application obtained via {@link getMatrix}
    851         private Matrix mOrigMatrix = null;
    852 
    853         @Override
    854         public void setMatrix(Matrix matrix) {
    855             if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
    856                 // don't scale the matrix if it's not compatibility mode, or
    857                 // the matrix was obtained from getMatrix.
    858                 super.setMatrix(matrix);
    859             } else {
    860                 Matrix m = new Matrix(mCompatibleMatrix);
    861                 m.preConcat(matrix);
    862                 super.setMatrix(m);
    863             }
    864         }
    865 
    866         @SuppressWarnings("deprecation")
    867         @Override
    868         public void getMatrix(Matrix m) {
    869             super.getMatrix(m);
    870             if (mOrigMatrix == null) {
    871                 mOrigMatrix = new Matrix();
    872             }
    873             mOrigMatrix.set(m);
    874         }
    875     }
    876 
    877     private final class HwuiContext {
    878         private final RenderNode mRenderNode;
    879         private long mHwuiRenderer;
    880         private DisplayListCanvas mCanvas;
    881         private final boolean mIsWideColorGamut;
    882 
    883         HwuiContext(boolean isWideColorGamut) {
    884             mRenderNode = RenderNode.create("HwuiCanvas", null);
    885             mRenderNode.setClipToBounds(false);
    886             mIsWideColorGamut = isWideColorGamut;
    887             mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject,
    888                     isWideColorGamut);
    889         }
    890 
    891         Canvas lockCanvas(int width, int height) {
    892             if (mCanvas != null) {
    893                 throw new IllegalStateException("Surface was already locked!");
    894             }
    895             mCanvas = mRenderNode.start(width, height);
    896             return mCanvas;
    897         }
    898 
    899         void unlockAndPost(Canvas canvas) {
    900             if (canvas != mCanvas) {
    901                 throw new IllegalArgumentException("canvas object must be the same instance that "
    902                         + "was previously returned by lockCanvas");
    903             }
    904             mRenderNode.end(mCanvas);
    905             mCanvas = null;
    906             nHwuiDraw(mHwuiRenderer);
    907         }
    908 
    909         void updateSurface() {
    910             nHwuiSetSurface(mHwuiRenderer, mNativeObject);
    911         }
    912 
    913         void destroy() {
    914             if (mHwuiRenderer != 0) {
    915                 nHwuiDestroy(mHwuiRenderer);
    916                 mHwuiRenderer = 0;
    917             }
    918         }
    919 
    920         boolean isWideColorGamut() {
    921             return mIsWideColorGamut;
    922         }
    923     }
    924 
    925     private static native long nHwuiCreate(long rootNode, long surface, boolean isWideColorGamut);
    926     private static native void nHwuiSetSurface(long renderer, long surface);
    927     private static native void nHwuiDraw(long renderer);
    928     private static native void nHwuiDestroy(long renderer);
    929 }
    930