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