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 
nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)57     private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
58             throws OutOfResourcesException;
59 
nativeCreateFromSurfaceControl(long surfaceControlNativeObject)60     private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject);
nativeGetFromSurfaceControl(long surfaceObject, long surfaceControlNativeObject)61     private static native long nativeGetFromSurfaceControl(long surfaceObject,
62             long surfaceControlNativeObject);
63 
nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)64     private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
65             throws OutOfResourcesException;
nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas)66     private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
67 
68     @UnsupportedAppUsage
nativeRelease(long nativeObject)69     private static native void nativeRelease(long nativeObject);
nativeIsValid(long nativeObject)70     private static native boolean nativeIsValid(long nativeObject);
nativeIsConsumerRunningBehind(long nativeObject)71     private static native boolean nativeIsConsumerRunningBehind(long nativeObject);
nativeReadFromParcel(long nativeObject, Parcel source)72     private static native long nativeReadFromParcel(long nativeObject, Parcel source);
nativeWriteToParcel(long nativeObject, Parcel dest)73     private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
74 
nativeAllocateBuffers(long nativeObject)75     private static native void nativeAllocateBuffers(long nativeObject);
76 
nativeGetWidth(long nativeObject)77     private static native int nativeGetWidth(long nativeObject);
nativeGetHeight(long nativeObject)78     private static native int nativeGetHeight(long nativeObject);
79 
nativeGetNextFrameNumber(long nativeObject)80     private static native long nativeGetNextFrameNumber(long nativeObject);
nativeSetScalingMode(long nativeObject, int scalingMode)81     private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
nativeForceScopedDisconnect(long nativeObject)82     private static native int nativeForceScopedDisconnect(long nativeObject);
nativeAttachAndQueueBuffer(long nativeObject, GraphicBuffer buffer)83     private static native int nativeAttachAndQueueBuffer(long nativeObject, GraphicBuffer buffer);
84 
nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled)85     private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled);
nativeSetAutoRefreshEnabled(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
Surface()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      */
Surface(@onNull SurfaceControl from)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      */
Surface(SurfaceTexture surfaceTexture)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
Surface(long nativeObject)230     private Surface(long nativeObject) {
231         synchronized (mLock) {
232             setNativeObjectLocked(nativeObject);
233         }
234     }
235 
236     @Override
finalize()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      */
release()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
destroy()273     public void destroy() {
274         release();
275     }
276 
277     /**
278      * Destroys the HwuiContext without completely
279      * releasing the Surface.
280      * @hide
281      */
hwuiDestroy()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      */
isValid()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      */
getGenerationId()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
getNextFrameNumber()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      */
isConsumerRunningBehind()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      */
lockCanvas(Rect inOutDirty)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      */
unlockCanvasAndPost(Canvas canvas)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 
unlockSwCanvasAndPost(Canvas canvas)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      */
lockHardwareCanvas()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      */
lockHardwareWideColorGamutCanvas()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
unlockCanvas(Canvas canvas)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      */
setCompatibilityTranslator(Translator translator)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
copyFrom(SurfaceControl other)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      */
createFrom(SurfaceControl other)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
transferFrom(Surface other)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
describeContents()598     public int describeContents() {
599         return 0;
600     }
601 
readFromParcel(Parcel source)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
writeToParcel(Parcel dest, int flags)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
toString()638     public String toString() {
639         synchronized (mLock) {
640             return "Surface(name=" + mName + ")/@0x" +
641                     Integer.toHexString(System.identityHashCode(this));
642         }
643     }
644 
setNativeObjectLocked(long ptr)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 
checkNotReleasedLocked()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      */
allocateBuffers()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      */
setScalingMode(@calingMode int scalingMode)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 
forceScopedDisconnect()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      */
attachAndQueueBuffer(GraphicBuffer buffer)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      */
isSingleBuffered()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      */
setSharedBufferModeEnabled(boolean enabled)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      */
isSharedBufferModeEnabled()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      */
setAutoRefreshEnabled(boolean enabled)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      */
isAutoRefreshEnabled()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 {
OutOfResourcesException()829         public OutOfResourcesException() {
830         }
OutOfResourcesException(String name)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      */
rotationToString(int rotation)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
setMatrix(Matrix matrix)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
getMatrix(Matrix m)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 
HwuiContext(boolean isWideColorGamut)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 
lockCanvas(int width, int height)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 
unlockAndPost(Canvas canvas)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 
updateSurface()940         void updateSurface() {
941             nHwuiSetSurface(mHwuiRenderer, mNativeObject);
942         }
943 
destroy()944         void destroy() {
945             if (mHwuiRenderer != 0) {
946                 nHwuiDestroy(mHwuiRenderer);
947                 mHwuiRenderer = 0;
948             }
949         }
950 
isWideColorGamut()951         boolean isWideColorGamut() {
952             return mIsWideColorGamut;
953         }
954     }
955 
nHwuiCreate(long rootNode, long surface, boolean isWideColorGamut)956     private static native long nHwuiCreate(long rootNode, long surface, boolean isWideColorGamut);
nHwuiSetSurface(long renderer, long surface)957     private static native void nHwuiSetSurface(long renderer, long surface);
nHwuiDraw(long renderer)958     private static native void nHwuiDraw(long renderer);
nHwuiDestroy(long renderer)959     private static native void nHwuiDestroy(long renderer);
960 }
961