summaryrefslogtreecommitdiff
path: root/android/view/Surface.java
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
committerJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
commit10d07c88d69cc64f73a069163e7ea5ba2519a099 (patch)
tree8dbd149eb350320a29c3d10e7ad3201de1c5cbee /android/view/Surface.java
parent677516fb6b6f207d373984757d3d9450474b6b00 (diff)
downloadandroid-28-10d07c88d69cc64f73a069163e7ea5ba2519a099.tar.gz
Import Android SDK Platform PI [4335822]
/google/data/ro/projects/android/fetch_artifact \ --bid 4335822 \ --target sdk_phone_armv7-win_sdk \ sdk-repo-linux-sources-4335822.zip AndroidVersion.ApiLevel has been modified to appear as 28 Change-Id: Ic8f04be005a71c2b9abeaac754d8da8d6f9a2c32
Diffstat (limited to 'android/view/Surface.java')
-rw-r--r--android/view/Surface.java858
1 files changed, 858 insertions, 0 deletions
diff --git a/android/view/Surface.java b/android/view/Surface.java
new file mode 100644
index 00000000..2c1f7346
--- /dev/null
+++ b/android/view/Surface.java
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.IntDef;
+import android.content.res.CompatibilityInfo.Translator;
+import android.graphics.Canvas;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Handle onto a raw buffer that is being managed by the screen compositor.
+ *
+ * <p>A Surface is generally created by or from a consumer of image buffers (such as a
+ * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or
+ * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as
+ * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL},
+ * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw
+ * into.</p>
+ *
+ * <p><strong>Note:</strong> A Surface acts like a
+ * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By
+ * itself it will not keep its parent consumer from being reclaimed.</p>
+ */
+public class Surface implements Parcelable {
+ private static final String TAG = "Surface";
+
+ private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
+ throws OutOfResourcesException;
+
+ private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject);
+ private static native long nativeGetFromSurfaceControl(long surfaceControlNativeObject);
+
+ private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
+ throws OutOfResourcesException;
+ private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
+
+ private static native void nativeRelease(long nativeObject);
+ private static native boolean nativeIsValid(long nativeObject);
+ private static native boolean nativeIsConsumerRunningBehind(long nativeObject);
+ private static native long nativeReadFromParcel(long nativeObject, Parcel source);
+ private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
+
+ private static native void nativeAllocateBuffers(long nativeObject);
+
+ private static native int nativeGetWidth(long nativeObject);
+ private static native int nativeGetHeight(long nativeObject);
+
+ private static native long nativeGetNextFrameNumber(long nativeObject);
+ private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
+ private static native int nativeForceScopedDisconnect(long nativeObject);
+ private static native int nativeAttachAndQueueBuffer(long nativeObject, GraphicBuffer buffer);
+
+ private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled);
+ private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled);
+
+ public static final Parcelable.Creator<Surface> CREATOR =
+ new Parcelable.Creator<Surface>() {
+ @Override
+ public Surface createFromParcel(Parcel source) {
+ try {
+ Surface s = new Surface();
+ s.readFromParcel(source);
+ return s;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating surface from parcel", e);
+ return null;
+ }
+ }
+
+ @Override
+ public Surface[] newArray(int size) {
+ return new Surface[size];
+ }
+ };
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ // Guarded state.
+ final Object mLock = new Object(); // protects the native state
+ private String mName;
+ long mNativeObject; // package scope only for SurfaceControl access
+ private long mLockedObject;
+ private int mGenerationId; // incremented each time mNativeObject changes
+ private final Canvas mCanvas = new CompatibleCanvas();
+
+ // A matrix to scale the matrix set by application. This is set to null for
+ // non compatibility mode.
+ private Matrix mCompatibleMatrix;
+
+ private HwuiContext mHwuiContext;
+
+ private boolean mIsSingleBuffered;
+ private boolean mIsSharedBufferModeEnabled;
+ private boolean mIsAutoRefreshEnabled;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
+ SCALING_MODE_SCALE_CROP, SCALING_MODE_NO_SCALE_CROP})
+ public @interface ScalingMode {}
+ // From system/window.h
+ /** @hide */
+ public static final int SCALING_MODE_FREEZE = 0;
+ /** @hide */
+ public static final int SCALING_MODE_SCALE_TO_WINDOW = 1;
+ /** @hide */
+ public static final int SCALING_MODE_SCALE_CROP = 2;
+ /** @hide */
+ public static final int SCALING_MODE_NO_SCALE_CROP = 3;
+
+ /** @hide */
+ @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Rotation {}
+
+ /**
+ * Rotation constant: 0 degree rotation (natural orientation)
+ */
+ public static final int ROTATION_0 = 0;
+
+ /**
+ * Rotation constant: 90 degree rotation.
+ */
+ public static final int ROTATION_90 = 1;
+
+ /**
+ * Rotation constant: 180 degree rotation.
+ */
+ public static final int ROTATION_180 = 2;
+
+ /**
+ * Rotation constant: 270 degree rotation.
+ */
+ public static final int ROTATION_270 = 3;
+
+ /**
+ * Create an empty surface, which will later be filled in by readFromParcel().
+ * @hide
+ */
+ public Surface() {
+ }
+
+ /**
+ * Create Surface from a {@link SurfaceTexture}.
+ *
+ * Images drawn to the Surface will be made available to the {@link
+ * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
+ * SurfaceTexture#updateTexImage}.
+ *
+ * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
+ * Surface.
+ * @throws OutOfResourcesException if the surface could not be created.
+ */
+ public Surface(SurfaceTexture surfaceTexture) {
+ if (surfaceTexture == null) {
+ throw new IllegalArgumentException("surfaceTexture must not be null");
+ }
+ mIsSingleBuffered = surfaceTexture.isSingleBuffered();
+ synchronized (mLock) {
+ mName = surfaceTexture.toString();
+ setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
+ }
+ }
+
+ /* called from android_view_Surface_createFromIGraphicBufferProducer() */
+ private Surface(long nativeObject) {
+ synchronized (mLock) {
+ setNativeObjectLocked(nativeObject);
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ release();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Release the local reference to the server-side surface.
+ * Always call release() when you're done with a Surface.
+ * This will make the surface invalid.
+ */
+ public void release() {
+ synchronized (mLock) {
+ if (mNativeObject != 0) {
+ nativeRelease(mNativeObject);
+ setNativeObjectLocked(0);
+ }
+ if (mHwuiContext != null) {
+ mHwuiContext.destroy();
+ mHwuiContext = null;
+ }
+ }
+ }
+
+ /**
+ * Free all server-side state associated with this surface and
+ * release this object's reference. This method can only be
+ * called from the process that created the service.
+ * @hide
+ */
+ public void destroy() {
+ release();
+ }
+
+ /**
+ * Returns true if this object holds a valid surface.
+ *
+ * @return True if it holds a physical surface, so lockCanvas() will succeed.
+ * Otherwise returns false.
+ */
+ public boolean isValid() {
+ synchronized (mLock) {
+ if (mNativeObject == 0) return false;
+ return nativeIsValid(mNativeObject);
+ }
+ }
+
+ /**
+ * Gets the generation number of this surface, incremented each time
+ * the native surface contained within this object changes.
+ *
+ * @return The current generation number.
+ * @hide
+ */
+ public int getGenerationId() {
+ synchronized (mLock) {
+ return mGenerationId;
+ }
+ }
+
+ /**
+ * Returns the next frame number which will be dequeued for rendering.
+ * Intended for use with SurfaceFlinger's deferred transactions API.
+ *
+ * @hide
+ */
+ public long getNextFrameNumber() {
+ synchronized (mLock) {
+ return nativeGetNextFrameNumber(mNativeObject);
+ }
+ }
+
+ /**
+ * Returns true if the consumer of this Surface is running behind the producer.
+ *
+ * @return True if the consumer is more than one buffer ahead of the producer.
+ * @hide
+ */
+ public boolean isConsumerRunningBehind() {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ return nativeIsConsumerRunningBehind(mNativeObject);
+ }
+ }
+
+ /**
+ * Gets a {@link Canvas} for drawing into this surface.
+ *
+ * After drawing into the provided {@link Canvas}, the caller must
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * @param inOutDirty A rectangle that represents the dirty region that the caller wants
+ * to redraw. This function may choose to expand the dirty rectangle if for example
+ * the surface has been resized or if the previous contents of the surface were
+ * not available. The caller must redraw the entire dirty region as represented
+ * by the contents of the inOutDirty rectangle upon return from this function.
+ * The caller may also pass <code>null</code> instead, in the case where the
+ * entire surface should be redrawn.
+ * @return A canvas for drawing into the surface.
+ *
+ * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
+ * @throws OutOfResourcesException If the canvas cannot be locked.
+ */
+ public Canvas lockCanvas(Rect inOutDirty)
+ throws Surface.OutOfResourcesException, IllegalArgumentException {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ if (mLockedObject != 0) {
+ // Ideally, nativeLockCanvas() would throw in this situation and prevent the
+ // double-lock, but that won't happen if mNativeObject was updated. We can't
+ // abandon the old mLockedObject because it might still be in use, so instead
+ // we just refuse to re-lock the Surface.
+ throw new IllegalArgumentException("Surface was already locked");
+ }
+ mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
+ return mCanvas;
+ }
+ }
+
+ /**
+ * Posts the new contents of the {@link Canvas} to the surface and
+ * releases the {@link Canvas}.
+ *
+ * @param canvas The canvas previously obtained from {@link #lockCanvas}.
+ */
+ public void unlockCanvasAndPost(Canvas canvas) {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+
+ if (mHwuiContext != null) {
+ mHwuiContext.unlockAndPost(canvas);
+ } else {
+ unlockSwCanvasAndPost(canvas);
+ }
+ }
+ }
+
+ private void unlockSwCanvasAndPost(Canvas canvas) {
+ if (canvas != mCanvas) {
+ throw new IllegalArgumentException("canvas object must be the same instance that "
+ + "was previously returned by lockCanvas");
+ }
+ if (mNativeObject != mLockedObject) {
+ Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
+ Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
+ Long.toHexString(mLockedObject) +")");
+ }
+ if (mLockedObject == 0) {
+ throw new IllegalStateException("Surface was not locked");
+ }
+ try {
+ nativeUnlockCanvasAndPost(mLockedObject, canvas);
+ } finally {
+ nativeRelease(mLockedObject);
+ mLockedObject = 0;
+ }
+ }
+
+ /**
+ * Gets a {@link Canvas} for drawing into this surface.
+ *
+ * After drawing into the provided {@link Canvas}, the caller must
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
+ * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
+ * unsupported drawing operations</a> for a list of what is and isn't
+ * supported in a hardware-accelerated canvas. It is also required to
+ * fully cover the surface every time {@link #lockHardwareCanvas()} is
+ * called as the buffer is not preserved between frames. Partial updates
+ * are not supported.
+ *
+ * @return A canvas for drawing into the surface.
+ *
+ * @throws IllegalStateException If the canvas cannot be locked.
+ */
+ public Canvas lockHardwareCanvas() {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ if (mHwuiContext == null) {
+ mHwuiContext = new HwuiContext();
+ }
+ return mHwuiContext.lockCanvas(
+ nativeGetWidth(mNativeObject),
+ nativeGetHeight(mNativeObject));
+ }
+ }
+
+ /**
+ * @deprecated This API has been removed and is not supported. Do not use.
+ */
+ @Deprecated
+ public void unlockCanvas(Canvas canvas) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Sets the translator used to scale canvas's width/height in compatibility
+ * mode.
+ */
+ void setCompatibilityTranslator(Translator translator) {
+ if (translator != null) {
+ float appScale = translator.applicationScale;
+ mCompatibleMatrix = new Matrix();
+ mCompatibleMatrix.setScale(appScale, appScale);
+ }
+ }
+
+ /**
+ * Copy another surface to this one. This surface now holds a reference
+ * to the same data as the original surface, and is -not- the owner.
+ * This is for use by the window manager when returning a window surface
+ * back from a client, converting it from the representation being managed
+ * by the window manager to the representation the client uses to draw
+ * in to it.
+ *
+ * @param other {@link SurfaceControl} to copy from.
+ *
+ * @hide
+ */
+ public void copyFrom(SurfaceControl other) {
+ if (other == null) {
+ throw new IllegalArgumentException("other must not be null");
+ }
+
+ long surfaceControlPtr = other.mNativeObject;
+ if (surfaceControlPtr == 0) {
+ throw new NullPointerException(
+ "null SurfaceControl native object. Are you using a released SurfaceControl?");
+ }
+ long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
+
+ synchronized (mLock) {
+ if (mNativeObject != 0) {
+ nativeRelease(mNativeObject);
+ }
+ setNativeObjectLocked(newNativeObject);
+ }
+ }
+
+ /**
+ * Gets a reference a surface created from this one. This surface now holds a reference
+ * to the same data as the original surface, and is -not- the owner.
+ * This is for use by the window manager when returning a window surface
+ * back from a client, converting it from the representation being managed
+ * by the window manager to the representation the client uses to draw
+ * in to it.
+ *
+ * @param other {@link SurfaceControl} to create surface from.
+ *
+ * @hide
+ */
+ public void createFrom(SurfaceControl other) {
+ if (other == null) {
+ throw new IllegalArgumentException("other must not be null");
+ }
+
+ long surfaceControlPtr = other.mNativeObject;
+ if (surfaceControlPtr == 0) {
+ throw new NullPointerException(
+ "null SurfaceControl native object. Are you using a released SurfaceControl?");
+ }
+ long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
+
+ synchronized (mLock) {
+ if (mNativeObject != 0) {
+ nativeRelease(mNativeObject);
+ }
+ setNativeObjectLocked(newNativeObject);
+ }
+ }
+
+ /**
+ * This is intended to be used by {@link SurfaceView#updateWindow} only.
+ * @param other access is not thread safe
+ * @hide
+ * @deprecated
+ */
+ @Deprecated
+ public void transferFrom(Surface other) {
+ if (other == null) {
+ throw new IllegalArgumentException("other must not be null");
+ }
+ if (other != this) {
+ final long newPtr;
+ synchronized (other.mLock) {
+ newPtr = other.mNativeObject;
+ other.setNativeObjectLocked(0);
+ }
+
+ synchronized (mLock) {
+ if (mNativeObject != 0) {
+ nativeRelease(mNativeObject);
+ }
+ setNativeObjectLocked(newPtr);
+ }
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public void readFromParcel(Parcel source) {
+ if (source == null) {
+ throw new IllegalArgumentException("source must not be null");
+ }
+
+ synchronized (mLock) {
+ // nativeReadFromParcel() will either return mNativeObject, or
+ // create a new native Surface and return it after reducing
+ // the reference count on mNativeObject. Either way, it is
+ // not necessary to call nativeRelease() here.
+ // NOTE: This must be kept synchronized with the native parceling code
+ // in frameworks/native/libs/Surface.cpp
+ mName = source.readString();
+ mIsSingleBuffered = source.readInt() != 0;
+ setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
+ }
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (dest == null) {
+ throw new IllegalArgumentException("dest must not be null");
+ }
+ synchronized (mLock) {
+ // NOTE: This must be kept synchronized with the native parceling code
+ // in frameworks/native/libs/Surface.cpp
+ dest.writeString(mName);
+ dest.writeInt(mIsSingleBuffered ? 1 : 0);
+ nativeWriteToParcel(mNativeObject, dest);
+ }
+ if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
+ release();
+ }
+ }
+
+ @Override
+ public String toString() {
+ synchronized (mLock) {
+ return "Surface(name=" + mName + ")/@0x" +
+ Integer.toHexString(System.identityHashCode(this));
+ }
+ }
+
+ private void setNativeObjectLocked(long ptr) {
+ if (mNativeObject != ptr) {
+ if (mNativeObject == 0 && ptr != 0) {
+ mCloseGuard.open("release");
+ } else if (mNativeObject != 0 && ptr == 0) {
+ mCloseGuard.close();
+ }
+ mNativeObject = ptr;
+ mGenerationId += 1;
+ if (mHwuiContext != null) {
+ mHwuiContext.updateSurface();
+ }
+ }
+ }
+
+ private void checkNotReleasedLocked() {
+ if (mNativeObject == 0) {
+ throw new IllegalStateException("Surface has already been released.");
+ }
+ }
+
+ /**
+ * Allocate buffers ahead of time to avoid allocation delays during rendering
+ * @hide
+ */
+ public void allocateBuffers() {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ nativeAllocateBuffers(mNativeObject);
+ }
+ }
+
+ /**
+ * Set the scaling mode to be used for this surfaces buffers
+ * @hide
+ */
+ void setScalingMode(@ScalingMode int scalingMode) {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ int err = nativeSetScalingMode(mNativeObject, scalingMode);
+ if (err != 0) {
+ throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode);
+ }
+ }
+ }
+
+ void forceScopedDisconnect() {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ int err = nativeForceScopedDisconnect(mNativeObject);
+ if (err != 0) {
+ throw new RuntimeException("Failed to disconnect Surface instance (bad object?)");
+ }
+ }
+ }
+
+ /**
+ * Transfer ownership of buffer and present it on the Surface.
+ * @hide
+ */
+ public void attachAndQueueBuffer(GraphicBuffer buffer) {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ int err = nativeAttachAndQueueBuffer(mNativeObject, buffer);
+ if (err != 0) {
+ throw new RuntimeException(
+ "Failed to attach and queue buffer to Surface (bad object?)");
+ }
+ }
+ }
+
+ /**
+ * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture
+ * @hide
+ */
+ public boolean isSingleBuffered() {
+ return mIsSingleBuffered;
+ }
+
+ /**
+ * <p>The shared buffer mode allows both the application and the surface compositor
+ * (SurfaceFlinger) to concurrently access this surface's buffer. While the
+ * application is still required to issue a present request
+ * (see {@link #unlockCanvasAndPost(Canvas)}) to the compositor when an update is required,
+ * the compositor may trigger an update at any time. Since the surface's buffer is shared
+ * between the application and the compositor, updates triggered by the compositor may
+ * cause visible tearing.</p>
+ *
+ * <p>The shared buffer mode can be used with
+ * {@link #setAutoRefreshEnabled(boolean) auto-refresh} to avoid the overhead of
+ * issuing present requests.</p>
+ *
+ * <p>If the application uses the shared buffer mode to reduce latency, it is
+ * recommended to use software rendering (see {@link #lockCanvas(Rect)} to ensure
+ * the graphics workloads are not affected by other applications and/or the system
+ * using the GPU. When using software rendering, the application should update the
+ * smallest possible region of the surface required.</p>
+ *
+ * <p class="note">The shared buffer mode might not be supported by the underlying
+ * hardware. Enabling shared buffer mode on hardware that does not support it will
+ * not yield an error but the application will not benefit from lower latency (and
+ * tearing will not be visible).</p>
+ *
+ * <p class="note">Depending on how many and what kind of surfaces are visible, the
+ * surface compositor may need to copy the shared buffer before it is displayed. When
+ * this happens, the latency benefits of shared buffer mode will be reduced.</p>
+ *
+ * @param enabled True to enable the shared buffer mode on this surface, false otherwise
+ *
+ * @see #isSharedBufferModeEnabled()
+ * @see #setAutoRefreshEnabled(boolean)
+ *
+ * @hide
+ */
+ public void setSharedBufferModeEnabled(boolean enabled) {
+ if (mIsSharedBufferModeEnabled != enabled) {
+ int error = nativeSetSharedBufferModeEnabled(mNativeObject, enabled);
+ if (error != 0) {
+ throw new RuntimeException(
+ "Failed to set shared buffer mode on Surface (bad object?)");
+ } else {
+ mIsSharedBufferModeEnabled = enabled;
+ }
+ }
+ }
+
+ /**
+ * @return True if shared buffer mode is enabled on this surface, false otherwise
+ *
+ * @see #setSharedBufferModeEnabled(boolean)
+ *
+ * @hide
+ */
+ public boolean isSharedBufferModeEnabled() {
+ return mIsSharedBufferModeEnabled;
+ }
+
+ /**
+ * <p>When auto-refresh is enabled, the surface compositor (SurfaceFlinger)
+ * automatically updates the display on a regular refresh cycle. The application
+ * can continue to issue present requests but it is not required. Enabling
+ * auto-refresh may result in visible tearing.</p>
+ *
+ * <p>Auto-refresh has no effect if the {@link #setSharedBufferModeEnabled(boolean)
+ * shared buffer mode} is not enabled.</p>
+ *
+ * <p>Because auto-refresh will trigger continuous updates of the display, it is
+ * recommended to turn it on only when necessary. For example, in a drawing/painting
+ * application auto-refresh should be enabled on finger/pen down and disabled on
+ * finger/pen up.</p>
+ *
+ * @param enabled True to enable auto-refresh on this surface, false otherwise
+ *
+ * @see #isAutoRefreshEnabled()
+ * @see #setSharedBufferModeEnabled(boolean)
+ *
+ * @hide
+ */
+ public void setAutoRefreshEnabled(boolean enabled) {
+ if (mIsAutoRefreshEnabled != enabled) {
+ int error = nativeSetAutoRefreshEnabled(mNativeObject, enabled);
+ if (error != 0) {
+ throw new RuntimeException("Failed to set auto refresh on Surface (bad object?)");
+ } else {
+ mIsAutoRefreshEnabled = enabled;
+ }
+ }
+ }
+
+ /**
+ * @return True if auto-refresh is enabled on this surface, false otherwise
+ *
+ * @hide
+ */
+ public boolean isAutoRefreshEnabled() {
+ return mIsAutoRefreshEnabled;
+ }
+
+ /**
+ * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
+ * when a SurfaceTexture could not successfully be allocated.
+ */
+ @SuppressWarnings("serial")
+ public static class OutOfResourcesException extends RuntimeException {
+ public OutOfResourcesException() {
+ }
+ public OutOfResourcesException(String name) {
+ super(name);
+ }
+ }
+
+ /**
+ * Returns a human readable representation of a rotation.
+ *
+ * @param rotation The rotation.
+ * @return The rotation symbolic name.
+ *
+ * @hide
+ */
+ public static String rotationToString(int rotation) {
+ switch (rotation) {
+ case Surface.ROTATION_0: {
+ return "ROTATION_0";
+ }
+ case Surface.ROTATION_90: {
+ return "ROTATION_90";
+ }
+ case Surface.ROTATION_180: {
+ return "ROTATION_180";
+ }
+ case Surface.ROTATION_270: {
+ return "ROTATION_270";
+ }
+ default: {
+ throw new IllegalArgumentException("Invalid rotation: " + rotation);
+ }
+ }
+ }
+
+ /**
+ * A Canvas class that can handle the compatibility mode.
+ * This does two things differently.
+ * <ul>
+ * <li>Returns the width and height of the target metrics, rather than
+ * native. For example, the canvas returns 320x480 even if an app is running
+ * in WVGA high density.
+ * <li>Scales the matrix in setMatrix by the application scale, except if
+ * the matrix looks like obtained from getMatrix. This is a hack to handle
+ * the case that an application uses getMatrix to keep the original matrix,
+ * set matrix of its own, then set the original matrix back. There is no
+ * perfect solution that works for all cases, and there are a lot of cases
+ * that this model does not work, but we hope this works for many apps.
+ * </ul>
+ */
+ private final class CompatibleCanvas extends Canvas {
+ // A temp matrix to remember what an application obtained via {@link getMatrix}
+ private Matrix mOrigMatrix = null;
+
+ @Override
+ public void setMatrix(Matrix matrix) {
+ if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
+ // don't scale the matrix if it's not compatibility mode, or
+ // the matrix was obtained from getMatrix.
+ super.setMatrix(matrix);
+ } else {
+ Matrix m = new Matrix(mCompatibleMatrix);
+ m.preConcat(matrix);
+ super.setMatrix(m);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void getMatrix(Matrix m) {
+ super.getMatrix(m);
+ if (mOrigMatrix == null) {
+ mOrigMatrix = new Matrix();
+ }
+ mOrigMatrix.set(m);
+ }
+ }
+
+ private final class HwuiContext {
+ private final RenderNode mRenderNode;
+ private long mHwuiRenderer;
+ private DisplayListCanvas mCanvas;
+
+ HwuiContext() {
+ mRenderNode = RenderNode.create("HwuiCanvas", null);
+ mRenderNode.setClipToBounds(false);
+ mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject);
+ }
+
+ Canvas lockCanvas(int width, int height) {
+ if (mCanvas != null) {
+ throw new IllegalStateException("Surface was already locked!");
+ }
+ mCanvas = mRenderNode.start(width, height);
+ return mCanvas;
+ }
+
+ void unlockAndPost(Canvas canvas) {
+ if (canvas != mCanvas) {
+ throw new IllegalArgumentException("canvas object must be the same instance that "
+ + "was previously returned by lockCanvas");
+ }
+ mRenderNode.end(mCanvas);
+ mCanvas = null;
+ nHwuiDraw(mHwuiRenderer);
+ }
+
+ void updateSurface() {
+ nHwuiSetSurface(mHwuiRenderer, mNativeObject);
+ }
+
+ void destroy() {
+ if (mHwuiRenderer != 0) {
+ nHwuiDestroy(mHwuiRenderer);
+ mHwuiRenderer = 0;
+ }
+ }
+ }
+
+ private static native long nHwuiCreate(long rootNode, long surface);
+ private static native void nHwuiSetSurface(long renderer, long surface);
+ private static native void nHwuiDraw(long renderer);
+ private static native void nHwuiDestroy(long renderer);
+}