From 762e8b8b6a38fd662840de2d672d1cf0cdcbc2f5 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Thu, 16 Jan 2020 10:00:26 -0800 Subject: [PATCH] Add more control to surface ordering (#2041) When UiHelper is set to translucent with setOpaque(false), the target SurfaceView's surface is set to be composited on top of the activity's window. There are situations however where one may want to render regular Views on top of the SurfaceView. The new setMediaOverlay() API allows exactly that: when this property is enabled, rendering to a translucent target will cause the SurfaceView's surface to be composited above other surfaces, but below the activity's surface. --- .../android/filament/android/UiHelper.java | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/android/filament-android/src/main/java/com/google/android/filament/android/UiHelper.java b/android/filament-android/src/main/java/com/google/android/filament/android/UiHelper.java index 46eb0853af..308844077a 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/android/UiHelper.java +++ b/android/filament-android/src/main/java/com/google/android/filament/android/UiHelper.java @@ -131,6 +131,7 @@ public class UiHelper { private RenderSurface mRenderSurface; private boolean mOpaque = true; + private boolean mOverlay = false; /** * Enum used to decide whether UiHelper should perform extra error checking. @@ -173,7 +174,7 @@ public class UiHelper { void detach(); } - private class SurfaceViewHandler implements RenderSurface { + private static class SurfaceViewHandler implements RenderSurface { private SurfaceView mSurfaceView; SurfaceViewHandler(SurfaceView surface) { @@ -323,6 +324,30 @@ public class UiHelper { mOpaque = opaque; } + /** + * Returns true if the SurfaceView used as a render target should be positioned above + * other surfaces but below the activity's surface. False by default. + */ + public boolean isMediaOverlay() { + return mOverlay; + } + + /** + * Controls whether the surface of the SurfaceView used as a render target should be + * positioned above other surfaces but below the activity's surface. This property + * only has an effect when used in combination with {@link #setOpaque(boolean) setOpaque(false)} + * and does not affect TextureView targets. + * + * Must be called before calling {@link #attachTo(SurfaceView)} + * or {@link #attachTo(TextureView)}. + * + * @param overlay Indicates whether the render target should be rendered below the activity's + * surface when transparent. + */ + public void setMediaOverlay(boolean overlay) { + mOverlay = overlay; + } + /** * Returns the flags to pass to * {@link com.google.android.filament.Engine#createSwapChain(Object, long)} to honor all @@ -340,11 +365,18 @@ public class UiHelper { */ public void attachTo(@NonNull SurfaceView view) { if (attach(view)) { - if (!isOpaque()) { - view.setZOrderOnTop(true); - view.getHolder().setFormat(PixelFormat.TRANSLUCENT); + boolean translucent = !isOpaque(); + // setZOrderOnTop() and setZOrderMediaOverlay() override each other, + // we must only call one of them + if (isMediaOverlay()) { + view.setZOrderMediaOverlay(translucent); + } else { + view.setZOrderOnTop(translucent); } + int format = isOpaque() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT; + view.getHolder().setFormat(format); + mRenderSurface = new SurfaceViewHandler(view); final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() { @@ -377,7 +409,6 @@ public class UiHelper { final Surface surface = holder.getSurface(); if (surface != null && surface.isValid()) { callback.surfaceCreated(holder); - int format = isOpaque() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT; callback.surfaceChanged(holder, format, holder.getSurfaceFrame().width(), holder.getSurfaceFrame().height()); }