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