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