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