Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a975a0a1 authored by Wale Ogunwale's avatar Wale Ogunwale Committed by Android (Google) Code Review
Browse files

Merge "Introduce SurfaceControl Builder API"

parents 6ffdd11f e625fcf3
Loading
Loading
Loading
Loading
+203 −23
Original line number Diff line number Diff line
@@ -16,27 +16,22 @@

package android.view;

import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;

import android.annotation.Size;
import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
import android.os.Debug;
import android.os.IBinder;
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;

import dalvik.system.CloseGuard;
import libcore.util.NativeAllocationRegistry;

import java.io.Closeable;

import libcore.util.NativeAllocationRegistry;

/**
 * SurfaceControl
 *  @hide
@@ -186,7 +181,7 @@ public class SurfaceControl {

    /**
     * Surface creation flag: Indicates that the surface must be considered opaque,
     * even if its pixel format is set to translucent. This can be useful if an
     * even if its pixel format contains an alpha channel. This can be useful if an
     * application needs full RGBA 8888 support for instance but will
     * still draw every pixel opaque.
     * <p>
@@ -306,6 +301,203 @@ public class SurfaceControl {
     */
    public static final int WINDOW_TYPE_DONT_SCREENSHOT = 441731;

    /**
     * Builder class for {@link SurfaceControl} objects.
     */
    public static class Builder {
        private SurfaceSession mSession;
        private int mFlags = HIDDEN;
        private int mWidth;
        private int mHeight;
        private int mFormat = PixelFormat.OPAQUE;
        private String mName;
        private SurfaceControl mParent;
        private int mWindowType;
        private int mOwnerUid;

        /**
         * Begin building a SurfaceControl with a given {@link SurfaceSession}.
         *
         * @param session The {@link SurfaceSession} with which to eventually construct the surface.
         */
        public Builder(SurfaceSession session) {
            mSession = session;
        }

        /**
         * Construct a new {@link SurfaceControl} with the set parameters.
         */
        public SurfaceControl build() {
            if (mWidth <= 0 || mHeight <= 0) {
                throw new IllegalArgumentException(
                        "width and height must be set");
            }
            return new SurfaceControl(mSession, mName, mWidth, mHeight, mFormat,
                    mFlags, mParent, mWindowType, mOwnerUid);
        }

        /**
         * Set a debugging-name for the SurfaceControl.
         *
         * @param name A name to identify the Surface in debugging.
         */
        public Builder setName(String name) {
            mName = name;
            return this;
        }

        /**
         * Set the initial size of the controlled surface's buffers in pixels.
         *
         * @param width The buffer width in pixels.
         * @param height The buffer height in pixels.
         */
        public Builder setSize(int width, int height) {
            if (width <= 0 || height <= 0) {
                throw new IllegalArgumentException(
                        "width and height must be positive");
            }
            mWidth = width;
            mHeight = height;
            return this;
        }

        /**
         * Set the pixel format of the controlled surface's buffers, using constants from
         * {@link android.graphics.PixelFormat}.
         */
        public Builder setFormat(@PixelFormat.Format int format) {
            mFormat = format;
            return this;
        }

        /**
         * Specify if the app requires a hardware-protected path to
         * an external display sync. If protected content is enabled, but
         * such a path is not available, then the controlled Surface will
         * not be displayed.
         *
         * @param protectedContent Whether to require a protected sink.
         */
        public Builder setProtected(boolean protectedContent) {
            if (protectedContent) {
                mFlags |= PROTECTED_APP;
            } else {
                mFlags &= ~PROTECTED_APP;
            }
            return this;
        }

        /**
         * Specify whether the Surface contains secure content. If true, the system
         * will prevent the surfaces content from being copied by another process. In
         * particular screenshots and VNC servers will be disabled. This is however
         * not a complete prevention of readback as {@link #setProtected}.
         */
        public Builder setSecure(boolean secure) {
            if (secure) {
                mFlags |= SECURE;
            } else {
                mFlags &= ~SECURE;
            }
            return this;
        }

        /**
         * Indicates whether the surface must be considered opaque,
         * even if its pixel format is set to translucent. This can be useful if an
         * application needs full RGBA 8888 support for instance but will
         * still draw every pixel opaque.
         * <p>
         * This flag only determines whether opacity will be sampled from the alpha channel.
         * Plane-alpha from calls to setAlpha() can still result in blended composition
         * regardless of the opaque setting.
         *
         * Combined effects are (assuming a buffer format with an alpha channel):
         * <ul>
         * <li>OPAQUE + alpha(1.0) == opaque composition
         * <li>OPAQUE + alpha(0.x) == blended composition
         * <li>OPAQUE + alpha(0.0) == no composition
         * <li>!OPAQUE + alpha(1.0) == blended composition
         * <li>!OPAQUE + alpha(0.x) == blended composition
         * <li>!OPAQUE + alpha(0.0) == no composition
         * </ul>
         * If the underlying buffer lacks an alpha channel, it is as if setOpaque(true)
         * were set automatically.
         * @param opaque Whether the Surface is OPAQUE.
         */
        public Builder setOpaque(boolean opaque) {
            if (opaque) {
                mFlags |= OPAQUE;
            } else {
                mFlags &= ~OPAQUE;
            }
            return this;
        }

        /**
         * Set a parent surface for our new SurfaceControl.
         *
         * Child surfaces are constrained to the onscreen region of their parent.
         * Furthermore they stack relatively in Z order, and inherit the transformation
         * of the parent.
         *
         * @param parent The parent control.
         */
        public Builder setParent(SurfaceControl parent) {
            mParent = parent;
            return this;
        }

        /**
         * Set surface metadata.
         *
         * Currently these are window-types as per {@link WindowManager.LayoutParams} and
         * owner UIDs. Child surfaces inherit their parents
         * metadata so only the WindowManager needs to set this on root Surfaces.
         *
         * @param windowType A window-type
         * @param ownerUid UID of the window owner.
         */
        public Builder setMetadata(int windowType, int ownerUid) {
            if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
                throw new UnsupportedOperationException(
                        "It only makes sense to set Surface metadata from the WindowManager");
            }
            mWindowType = windowType;
            mOwnerUid = ownerUid;
            return this;
        }

        /**
         * Indicate whether a 'ColorLayer' is to be constructed.
         *
         * Color layers will not have an associated BufferQueue and will instead always render a
         * solid color (that is, solid before plane alpha). Currently that color is black.
         *
         * @param isColorLayer Whether to create a color layer.
         */
        public Builder setColorLayer(boolean isColorLayer) {
            if (isColorLayer) {
                mFlags |= FX_SURFACE_DIM;
            } else {
                mFlags &= ~FX_SURFACE_DIM;
            }
            return this;
        }

        /**
         * Set 'Surface creation flags' such as {@link HIDDEN}, {@link SECURE}.
         *
         * TODO: Finish conversion to individual builder methods?
         * @param flags The combined flags
         */
        public Builder setFlags(int flags) {
            mFlags = flags;
            return this;
        }
    }

    /**
     * Create a surface with a name.
     * <p>
@@ -331,19 +523,7 @@ public class SurfaceControl {
     *
     * @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
     */
    public SurfaceControl(SurfaceSession session,
            String name, int w, int h, int format, int flags, int windowType, int ownerUid)
                    throws OutOfResourcesException {
        this(session, name, w, h, format, flags, null, windowType, ownerUid);
    }

    public SurfaceControl(SurfaceSession session,
            String name, int w, int h, int format, int flags)
                    throws OutOfResourcesException {
        this(session, name, w, h, format, flags, null, INVALID_WINDOW_TYPE, Binder.getCallingUid());
    }

    public SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
    private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
            SurfaceControl parent, int windowType, int ownerUid)
                    throws OutOfResourcesException {
        if (session == null) {
+17 −10
Original line number Diff line number Diff line
@@ -532,10 +532,15 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
                    mDeferredDestroySurfaceControl = mSurfaceControl;

                    updateOpaqueFlag();
                    mSurfaceControl = new SurfaceControlWithBackground(mSurfaceSession,
                            "SurfaceView - " + viewRoot.getTitle().toString(),
                            mSurfaceWidth, mSurfaceHeight, mFormat,
                            mSurfaceFlags);
                    final String name = "SurfaceView - " + viewRoot.getTitle().toString();

                    mSurfaceControl = new SurfaceControlWithBackground(
                            name,
                            (mSurfaceFlags & SurfaceControl.OPAQUE) != 0,
                            new SurfaceControl.Builder(mSurfaceSession)
                                    .setSize(mSurfaceWidth, mSurfaceHeight)
                                    .setFormat(mFormat)
                                    .setFlags(mSurfaceFlags));
                } else if (mSurfaceControl == null) {
                    return;
                }
@@ -1098,13 +1103,15 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
        private boolean mOpaque = true;
        public boolean mVisible = false;

        public SurfaceControlWithBackground(SurfaceSession s,
                        String name, int w, int h, int format, int flags)
        public SurfaceControlWithBackground(String name, boolean opaque, SurfaceControl.Builder b)
                       throws Exception {
            super(s, name, w, h, format, flags);
            mBackgroundControl = new SurfaceControl(s, "Background for - " + name, w, h,
                    PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
            mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
            super(b.setName(name).build());

            mBackgroundControl = b.setName("Background for -" + name)
                    .setFormat(OPAQUE)
                    .setColorLayer(true)
                    .build();
            mOpaque = opaque;
        }

        @Override
+5 −3
Original line number Diff line number Diff line
@@ -585,9 +585,11 @@ final class ColorFade {
                    } else {
                        flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
                    }
                    mSurfaceControl = new SurfaceControl(mSurfaceSession,
                            "ColorFade", mDisplayWidth, mDisplayHeight,
                            PixelFormat.OPAQUE, flags);
                    mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
                            .setName("ColorFade")
                            .setSize(mDisplayWidth, mDisplayHeight)
                            .setFlags(flags)
                            .build();
                } catch (OutOfResourcesException ex) {
                    Slog.e(TAG, "Unable to create surface.", ex);
                    return false;
+37 −35
Original line number Diff line number Diff line
@@ -74,12 +74,12 @@ import java.util.Set;
 */
final class AccessibilityController {

    private final WindowManagerService mWindowManagerService;
    private final WindowManagerService mService;

    private static final float[] sTempFloats = new float[9];

    public AccessibilityController(WindowManagerService service) {
        mWindowManagerService = service;
        mService = service;
    }

    private DisplayMagnifier mDisplayMagnifier;
@@ -91,7 +91,7 @@ final class AccessibilityController {
            if (mDisplayMagnifier != null) {
                throw new IllegalStateException("Magnification callbacks already set!");
            }
            mDisplayMagnifier = new DisplayMagnifier(mWindowManagerService, callbacks);
            mDisplayMagnifier = new DisplayMagnifier(mService, callbacks);
        } else {
            if  (mDisplayMagnifier == null) {
                throw new IllegalStateException("Magnification callbacks already cleared!");
@@ -108,7 +108,7 @@ final class AccessibilityController {
                        "Windows for accessibility callback already set!");
            }
            mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
                    mWindowManagerService, callback);
                    mService, callback);
        } else {
            if (mWindowsForAccessibilityObserver == null) {
                throw new IllegalStateException(
@@ -120,7 +120,7 @@ final class AccessibilityController {

    public void performComputeChangedWindowsNotLocked() {
        WindowsForAccessibilityObserver observer = null;
        synchronized (mWindowManagerService) {
        synchronized (mService) {
            observer = mWindowsForAccessibilityObserver;
        }
        if (observer != null) {
@@ -188,7 +188,7 @@ final class AccessibilityController {
        // Not relevant for the display magnifier.

        WindowsForAccessibilityObserver observer = null;
        synchronized (mWindowManagerService) {
        synchronized (mService) {
            observer = mWindowsForAccessibilityObserver;
        }
        if (observer != null) {
@@ -268,7 +268,7 @@ final class AccessibilityController {
        private final Region mTempRegion4 = new Region();

        private final Context mContext;
        private final WindowManagerService mWindowManagerService;
        private final WindowManagerService mService;
        private final MagnifiedViewport mMagnifedViewport;
        private final Handler mHandler;

@@ -281,9 +281,9 @@ final class AccessibilityController {
        public DisplayMagnifier(WindowManagerService windowManagerService,
                MagnificationCallbacks callbacks) {
            mContext = windowManagerService.mContext;
            mWindowManagerService = windowManagerService;
            mService = windowManagerService;
            mCallbacks = callbacks;
            mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
            mHandler = new MyHandler(mService.mH.getLooper());
            mMagnifedViewport = new MagnifiedViewport();
            mLongAnimationDuration = mContext.getResources().getInteger(
                    com.android.internal.R.integer.config_longAnimTime);
@@ -292,7 +292,7 @@ final class AccessibilityController {
        public void setMagnificationSpecLocked(MagnificationSpec spec) {
            mMagnifedViewport.updateMagnificationSpecLocked(spec);
            mMagnifedViewport.recomputeBoundsLocked();
            mWindowManagerService.scheduleAnimationLocked();
            mService.scheduleAnimationLocked();
        }

        public void setForceShowMagnifiableBoundsLocked(boolean show) {
@@ -330,7 +330,7 @@ final class AccessibilityController {
                Slog.i(LOG_TAG, "Layers changed.");
            }
            mMagnifedViewport.recomputeBoundsLocked();
            mWindowManagerService.scheduleAnimationLocked();
            mService.scheduleAnimationLocked();
        }

        public void onRotationChangedLocked(DisplayContent displayContent) {
@@ -421,7 +421,7 @@ final class AccessibilityController {
        public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
            MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
            if (spec != null && !spec.isNop()) {
                if (!mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
                if (!mService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
                    return null;
                }
            }
@@ -565,7 +565,7 @@ final class AccessibilityController {
                    portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
                    windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);

                    if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
                    if (mService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
                        mMagnificationRegion.op(windowBounds, Region.Op.UNION);
                        mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
                    } else {
@@ -632,7 +632,7 @@ final class AccessibilityController {
                if (isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked()) {
                    setMagnifiedRegionBorderShownLocked(false, false);
                    final long delay = (long) (mLongAnimationDuration
                            * mWindowManagerService.getWindowAnimationScaleLocked());
                            * mService.getWindowAnimationScaleLocked());
                    Message message = mHandler.obtainMessage(
                            MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
                    mHandler.sendMessageDelayed(message, delay);
@@ -675,7 +675,7 @@ final class AccessibilityController {
            }

            private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
                final DisplayContent dc = mWindowManagerService.getDefaultDisplayContentLocked();
                final DisplayContent dc = mService.getDefaultDisplayContentLocked();
                dc.forAllWindows((w) -> {
                    if (w.isOnScreen() && w.isVisibleLw()
                            && !w.mWinAnimator.mEnterAnimationPending) {
@@ -705,23 +705,25 @@ final class AccessibilityController {
                    SurfaceControl surfaceControl = null;
                    try {
                        mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
                        surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession,
                                SURFACE_TITLE, mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT,
                                SurfaceControl.HIDDEN);
                        surfaceControl = new SurfaceControl.Builder(mService.mFxSession)
                                .setName(SURFACE_TITLE)
                                .setSize(mTempPoint.x, mTempPoint.y) // not a typo
                                .setFormat(PixelFormat.TRANSLUCENT)
                                .build();
                    } catch (OutOfResourcesException oore) {
                        /* ignore */
                    }
                    mSurfaceControl = surfaceControl;
                    mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay()
                            .getLayerStack());
                    mSurfaceControl.setLayer(mWindowManagerService.mPolicy.getWindowLayerFromTypeLw(
                    mSurfaceControl.setLayer(mService.mPolicy.getWindowLayerFromTypeLw(
                            TYPE_MAGNIFICATION_OVERLAY)
                            * WindowManagerService.TYPE_LAYER_MULTIPLIER);
                    mSurfaceControl.setPosition(0, 0);
                    mSurface.copyFrom(mSurfaceControl);

                    mAnimationController = new AnimationController(context,
                            mWindowManagerService.mH.getLooper());
                            mService.mH.getLooper());

                    TypedValue typedValue = new TypedValue();
                    context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
@@ -736,7 +738,7 @@ final class AccessibilityController {
                }

                public void setShown(boolean shown, boolean animate) {
                    synchronized (mWindowManagerService.mWindowMap) {
                    synchronized (mService.mWindowMap) {
                        if (mShown == shown) {
                            return;
                        }
@@ -751,13 +753,13 @@ final class AccessibilityController {
                @SuppressWarnings("unused")
                // Called reflectively from an animator.
                public int getAlpha() {
                    synchronized (mWindowManagerService.mWindowMap) {
                    synchronized (mService.mWindowMap) {
                        return mAlpha;
                    }
                }

                public void setAlpha(int alpha) {
                    synchronized (mWindowManagerService.mWindowMap) {
                    synchronized (mService.mWindowMap) {
                        if (mAlpha == alpha) {
                            return;
                        }
@@ -770,7 +772,7 @@ final class AccessibilityController {
                }

                public void setBounds(Region bounds) {
                    synchronized (mWindowManagerService.mWindowMap) {
                    synchronized (mService.mWindowMap) {
                        if (mBounds.equals(bounds)) {
                            return;
                        }
@@ -783,7 +785,7 @@ final class AccessibilityController {
                }

                public void updateSize() {
                    synchronized (mWindowManagerService.mWindowMap) {
                    synchronized (mService.mWindowMap) {
                        mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
                        mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
                        invalidate(mDirtyRect);
@@ -797,12 +799,12 @@ final class AccessibilityController {
                        mDirtyRect.setEmpty();
                    }
                    mInvalidated = true;
                    mWindowManagerService.scheduleAnimationLocked();
                    mService.scheduleAnimationLocked();
                }

                /** NOTE: This has to be called within a surface transaction. */
                public void drawIfNeeded() {
                    synchronized (mWindowManagerService.mWindowMap) {
                    synchronized (mService.mWindowMap) {
                        if (!mInvalidated) {
                            return;
                        }
@@ -950,11 +952,11 @@ final class AccessibilityController {
                    } break;

                    case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
                        synchronized (mWindowManagerService.mWindowMap) {
                        synchronized (mService.mWindowMap) {
                            if (mMagnifedViewport.isMagnifyingLocked()
                                    || isForceShowingMagnifiableBoundsLocked()) {
                                mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
                                mWindowManagerService.scheduleAnimationLocked();
                                mService.scheduleAnimationLocked();
                            }
                        }
                    } break;
@@ -995,7 +997,7 @@ final class AccessibilityController {

        private final Context mContext;

        private final WindowManagerService mWindowManagerService;
        private final WindowManagerService mService;

        private final Handler mHandler;

@@ -1006,9 +1008,9 @@ final class AccessibilityController {
        public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
                WindowsForAccessibilityCallback callback) {
            mContext = windowManagerService.mContext;
            mWindowManagerService = windowManagerService;
            mService = windowManagerService;
            mCallback = callback;
            mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
            mHandler = new MyHandler(mService.mH.getLooper());
            mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
                    .getSendRecurringAccessibilityEventsInterval();
            computeChangedWindows();
@@ -1034,11 +1036,11 @@ final class AccessibilityController {
            boolean windowsChanged = false;
            List<WindowInfo> windows = new ArrayList<WindowInfo>();

            synchronized (mWindowManagerService.mWindowMap) {
            synchronized (mService.mWindowMap) {
                // Do not send the windows if there is no current focus as
                // the window manager is still looking for where to put it.
                // We will do the work when we get a focus change callback.
                if (mWindowManagerService.mCurrentFocus == null) {
                if (mService.mCurrentFocus == null) {
                    return;
                }

@@ -1320,7 +1322,7 @@ final class AccessibilityController {
        }

        private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
            final DisplayContent dc = mWindowManagerService.getDefaultDisplayContentLocked();
            final DisplayContent dc = mService.getDefaultDisplayContentLocked();
            dc.forAllWindows((w) -> {
                if (w.isVisibleLw()) {
                    outWindows.put(w.mLayer, w);
+5 −2
Original line number Diff line number Diff line
@@ -50,8 +50,11 @@ public class BlackFrame {
            int w = r-l;
            int h = b-t;

            surface = new SurfaceControl(session, "BlackSurface",
                    w, h, OPAQUE, FX_SURFACE_DIM | SurfaceControl.HIDDEN);
            surface = new SurfaceControl.Builder(session)
                    .setName("BlackSurface")
                    .setSize(w, h)
                    .setColorLayer(true)
                    .build();

            surface.setAlpha(1);
            surface.setLayerStack(layerStack);
Loading