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

Commit bc7932ed authored by P.Y. Laligand's avatar P.Y. Laligand Committed by Android (Google) Code Review
Browse files

Merge "Overlay display now support multiple modes."

parents d78d78d6 af9c52eb
Loading
Loading
Loading
Loading
+192 −63
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import android.view.SurfaceControl;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@@ -47,6 +49,21 @@ import java.util.regex.Pattern;
 * service as usual.  The UI handler is only used by the {@link OverlayDisplayWindow}.
 * </p><p>
 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
 * </p><p>
 * This adapter is configured via the
 * {@link android.provider.Settings.Global#OVERLAY_DISPLAY_DEVICES} setting. This setting should be
 * formatted as follows:
 * <pre>
 * [mode1]|[mode2]|...,[flag1],[flag2],...
 * </pre>
 * with each mode specified as:
 * <pre>
 * [width]x[height]/[densityDpi]
 * </pre>
 * Supported flags:
 * <ul>
 * <li><pre>secure</pre>: creates a secure display</li>
 * </ul>
 * </p>
 */
final class OverlayDisplayAdapter extends DisplayAdapter {
@@ -58,8 +75,10 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
    private static final int MAX_WIDTH = 4096;
    private static final int MAX_HEIGHT = 4096;

    private static final Pattern SETTING_PATTERN =
            Pattern.compile("(\\d+)x(\\d+)/(\\d+)(,[a-z]+)*");
    private static final Pattern DISPLAY_PATTERN =
            Pattern.compile("([^,]+)(,[a-z]+)*");
    private static final Pattern MODE_PATTERN =
            Pattern.compile("(\\d+)x(\\d+)/(\\d+)");

    // Unique id prefix for overlay displays.
    private static final String UNIQUE_ID_PREFIX = "overlay:";
@@ -136,21 +155,36 @@ final class OverlayDisplayAdapter extends DisplayAdapter {

        int count = 0;
        for (String part : value.split(";")) {
            Matcher matcher = SETTING_PATTERN.matcher(part);
            if (matcher.matches()) {
            Matcher displayMatcher = DISPLAY_PATTERN.matcher(part);
            if (displayMatcher.matches()) {
                if (count >= 4) {
                    Slog.w(TAG, "Too many overlay display devices specified: " + value);
                    break;
                }
                String modeString = displayMatcher.group(1);
                String flagString = displayMatcher.group(2);
                ArrayList<OverlayMode> modes = new ArrayList<>();
                for (String mode : modeString.split("\\|")) {
                    Matcher modeMatcher = MODE_PATTERN.matcher(mode);
                    if (modeMatcher.matches()) {
                        try {
                    int width = Integer.parseInt(matcher.group(1), 10);
                    int height = Integer.parseInt(matcher.group(2), 10);
                    int densityDpi = Integer.parseInt(matcher.group(3), 10);
                    String flagString = matcher.group(4);
                            int width = Integer.parseInt(modeMatcher.group(1), 10);
                            int height = Integer.parseInt(modeMatcher.group(2), 10);
                            int densityDpi = Integer.parseInt(modeMatcher.group(3), 10);
                            if (width >= MIN_WIDTH && width <= MAX_WIDTH
                                    && height >= MIN_HEIGHT && height <= MAX_HEIGHT
                                    && densityDpi >= DisplayMetrics.DENSITY_LOW
                                    && densityDpi <= DisplayMetrics.DENSITY_XXHIGH) {
                                modes.add(new OverlayMode(width, height, densityDpi));
                                continue;
                            }
                        } catch (NumberFormatException ex) {
                        }
                    } else if (mode.isEmpty()) {
                        continue;
                    }
                }
                if (!modes.isEmpty()) {
                    int number = ++count;
                    String name = getContext().getResources().getString(
                            com.android.internal.R.string.display_manager_overlay_display_name,
@@ -159,17 +193,11 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
                    boolean secure = flagString != null && flagString.contains(",secure");

                    Slog.i(TAG, "Showing overlay display device #" + number
                                + ": name=" + name + ", width=" + width + ", height=" + height
                                + ", densityDpi=" + densityDpi + ", secure=" + secure);
                            + ": name=" + name + ", modes=" + Arrays.toString(modes.toArray()));

                        mOverlays.add(new OverlayDisplayHandle(name,
                                width, height, densityDpi, gravity, secure, number));
                    mOverlays.add(new OverlayDisplayHandle(name, modes, gravity, secure, number));
                    continue;
                }
                } catch (NumberFormatException ex) {
                }
            } else if (part.isEmpty()) {
                continue;
            }
            Slog.w(TAG, "Malformed overlay display devices setting: " + value);
        }
@@ -189,36 +217,41 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
        }
    }

    private final class OverlayDisplayDevice extends DisplayDevice {
    private abstract class OverlayDisplayDevice extends DisplayDevice {
        private final String mName;
        private final int mWidth;
        private final int mHeight;
        private final float mRefreshRate;
        private final long mDisplayPresentationDeadlineNanos;
        private final int mDensityDpi;
        private final boolean mSecure;
        private final Display.Mode mMode;
        private final List<OverlayMode> mRawModes;
        private final Display.Mode[] mModes;
        private final int mDefaultMode;

        private int mState;
        private SurfaceTexture mSurfaceTexture;
        private Surface mSurface;
        private DisplayDeviceInfo mInfo;
        private int mActiveMode;

        public OverlayDisplayDevice(IBinder displayToken, String name,
                int width, int height, float refreshRate, long presentationDeadlineNanos,
                int densityDpi, boolean secure, int state,
                List<OverlayMode> modes, int activeMode, int defaultMode,
                float refreshRate, long presentationDeadlineNanos,
                boolean secure, int state,
                SurfaceTexture surfaceTexture, int number) {
            super(OverlayDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + number);
            mName = name;
            mWidth = width;
            mHeight = height;
            mRefreshRate = refreshRate;
            mDisplayPresentationDeadlineNanos = presentationDeadlineNanos;
            mDensityDpi = densityDpi;
            mSecure = secure;
            mState = state;
            mSurfaceTexture = surfaceTexture;
            mMode = createMode(width, height, refreshRate);
            mRawModes = modes;
            mModes = new Display.Mode[modes.size()];
            for (int i = 0; i < modes.size(); i++) {
                OverlayMode mode = modes.get(i);
                mModes[i] = createMode(mode.mWidth, mode.mHeight, refreshRate);
            }
            mActiveMode = activeMode;
            mDefaultMode = defaultMode;
        }

        public void destroyLocked() {
@@ -248,17 +281,19 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
        @Override
        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
            if (mInfo == null) {
                Display.Mode mode = mModes[mActiveMode];
                OverlayMode rawMode = mRawModes.get(mActiveMode);
                mInfo = new DisplayDeviceInfo();
                mInfo.name = mName;
                mInfo.uniqueId = getUniqueId();
                mInfo.width = mWidth;
                mInfo.height = mHeight;
                mInfo.modeId = mMode.getModeId();
                mInfo.defaultModeId = mMode.getModeId();
                mInfo.supportedModes = new Display.Mode[] { mMode };
                mInfo.densityDpi = mDensityDpi;
                mInfo.xDpi = mDensityDpi;
                mInfo.yDpi = mDensityDpi;
                mInfo.width = mode.getPhysicalWidth();
                mInfo.height = mode.getPhysicalHeight();
                mInfo.modeId = mode.getModeId();
                mInfo.defaultModeId = mModes[0].getModeId();
                mInfo.supportedModes = mModes;
                mInfo.densityDpi = rawMode.mDensityDpi;
                mInfo.xDpi = rawMode.mDensityDpi;
                mInfo.yDpi = rawMode.mDensityDpi;
                mInfo.presentationDeadlineNanos = mDisplayPresentationDeadlineNanos +
                        1000000000L / (int) mRefreshRate;   // display's deadline + 1 frame
                mInfo.flags = DisplayDeviceInfo.FLAG_PRESENTATION;
@@ -271,6 +306,40 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
            }
            return mInfo;
        }

        @Override
        public void requestModeInTransactionLocked(int id) {
            int index = -1;
            if (id == 0) {
                // Use the default.
                index = 0;
            } else {
                for (int i = 0; i < mModes.length; i++) {
                    if (mModes[i].getModeId() == id) {
                        index = i;
                        break;
                    }
                }
            }
            if (index == -1) {
                Slog.w(TAG, "Unable to locate mode " + id + ", reverting to default.");
                index = mDefaultMode;
            }
            if (mActiveMode == index) {
                return;
            }
            mActiveMode = index;
            mInfo = null;
            sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
            onModeChangedLocked(index);
        }

        /**
         * Called when the device switched to a new mode.
         *
         * @param index index of the mode in the list of modes
         */
        public abstract void onModeChangedLocked(int index);
    }

    /**
@@ -280,27 +349,32 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
     * Guarded by the {@link DisplayManagerService.SyncRoot} lock.
     */
    private final class OverlayDisplayHandle implements OverlayDisplayWindow.Listener {
        private static final int DEFAULT_MODE_INDEX = 0;

        private final String mName;
        private final int mWidth;
        private final int mHeight;
        private final int mDensityDpi;
        private final List<OverlayMode> mModes;
        private final int mGravity;
        private final boolean mSecure;
        private final int mNumber;

        private OverlayDisplayWindow mWindow;
        private OverlayDisplayDevice mDevice;
        private int mActiveMode;

        public OverlayDisplayHandle(String name, int width,
                int height, int densityDpi, int gravity, boolean secure, int number) {
        public OverlayDisplayHandle(String name, List<OverlayMode> modes, int gravity,
                boolean secure, int number) {
            mName = name;
            mWidth = width;
            mHeight = height;
            mDensityDpi = densityDpi;
            mModes = modes;
            mGravity = gravity;
            mSecure = secure;
            mNumber = number;

            mActiveMode = 0;

            showLocked();
        }

        private void showLocked() {
            mUiHandler.post(mShowRunnable);
        }

@@ -309,15 +383,28 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
            mUiHandler.post(mDismissRunnable);
        }

        private void onActiveModeChangedLocked(int index) {
            mUiHandler.removeCallbacks(mResizeRunnable);
            mActiveMode = index;
            if (mWindow != null) {
                mUiHandler.post(mResizeRunnable);
            }
        }

        // Called on the UI thread.
        @Override
        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate,
                long presentationDeadlineNanos, int state) {
            synchronized (getSyncRoot()) {
                IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);
                mDevice = new OverlayDisplayDevice(displayToken, mName,
                        mWidth, mHeight, refreshRate, presentationDeadlineNanos,
                        mDensityDpi, mSecure, state, surfaceTexture, mNumber);
                mDevice = new OverlayDisplayDevice(displayToken, mName, mModes, mActiveMode,
                        DEFAULT_MODE_INDEX, refreshRate, presentationDeadlineNanos,
                        mSecure, state, surfaceTexture, mNumber) {
                    @Override
                    public void onModeChangedLocked(int index) {
                        onActiveModeChangedLocked(index);
                    }
                };

                sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
            }
@@ -347,9 +434,8 @@ final class OverlayDisplayAdapter extends DisplayAdapter {

        public void dumpLocked(PrintWriter pw) {
            pw.println("  " + mName + ":");
            pw.println("    mWidth=" + mWidth);
            pw.println("    mHeight=" + mHeight);
            pw.println("    mDensityDpi=" + mDensityDpi);
            pw.println("    mModes=" + Arrays.toString(mModes.toArray()));
            pw.println("    mActiveMode=" + mActiveMode);
            pw.println("    mGravity=" + mGravity);
            pw.println("    mSecure=" + mSecure);
            pw.println("    mNumber=" + mNumber);
@@ -366,8 +452,9 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
        private final Runnable mShowRunnable = new Runnable() {
            @Override
            public void run() {
                OverlayMode mode = mModes.get(mActiveMode);
                OverlayDisplayWindow window = new OverlayDisplayWindow(getContext(),
                        mName, mWidth, mHeight, mDensityDpi, mGravity, mSecure,
                        mName, mode.mWidth, mode.mHeight, mode.mDensityDpi, mGravity, mSecure,
                        OverlayDisplayHandle.this);
                window.show();

@@ -392,5 +479,47 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
                }
            }
        };

        // Runs on the UI thread.
        private final Runnable mResizeRunnable = new Runnable() {
            @Override
            public void run() {
                OverlayMode mode;
                OverlayDisplayWindow window;
                synchronized (getSyncRoot()) {
                    if (mWindow == null) {
                        return;
                    }
                    mode = mModes.get(mActiveMode);
                    window = mWindow;
                }
                window.resize(mode.mWidth, mode.mHeight, mode.mDensityDpi);
            }
        };
    }

    /**
     * A display mode for an overlay display.
     */
    private static final class OverlayMode {
        final int mWidth;
        final int mHeight;
        final int mDensityDpi;

        OverlayMode(int width, int height, int densityDpi) {
            mWidth = width;
            mHeight = height;
            mDensityDpi = densityDpi;
        }

        @Override
        public String toString() {
            return new StringBuilder("{")
                    .append("width=").append(mWidth)
                    .append(", height=").append(mHeight)
                    .append(", densityDpi=").append(mDensityDpi)
                    .append("}")
                    .toString();
        }
    }
}
+25 −13
Original line number Diff line number Diff line
@@ -60,9 +60,9 @@ final class OverlayDisplayWindow implements DumpUtils.Dump {

    private final Context mContext;
    private final String mName;
    private final int mWidth;
    private final int mHeight;
    private final int mDensityDpi;
    private int mWidth;
    private int mHeight;
    private int mDensityDpi;
    private final int mGravity;
    private final boolean mSecure;
    private final Listener mListener;
@@ -97,19 +97,9 @@ final class OverlayDisplayWindow implements DumpUtils.Dump {
            Listener listener) {
        mContext = context;
        mName = name;
        mWidth = width;
        mHeight = height;
        mDensityDpi = densityDpi;
        mGravity = gravity;
        mSecure = secure;
        mListener = listener;
        mTitle = context.getResources().getString(
                com.android.internal.R.string.display_manager_overlay_display_title,
                mName, mWidth, mHeight, mDensityDpi);
        if (secure) {
            mTitle += context.getResources().getString(
                    com.android.internal.R.string.display_manager_overlay_display_secure_suffix);
        }

        mDisplayManager = (DisplayManager)context.getSystemService(
                Context.DISPLAY_SERVICE);
@@ -119,6 +109,8 @@ final class OverlayDisplayWindow implements DumpUtils.Dump {
        mDefaultDisplay = mWindowManager.getDefaultDisplay();
        updateDefaultDisplayInfo();

        resize(width, height, densityDpi, false /* doLayout */);

        createWindow();
    }

@@ -145,6 +137,26 @@ final class OverlayDisplayWindow implements DumpUtils.Dump {
        }
    }

    public void resize(int width, int height, int densityDpi) {
        resize(width, height, densityDpi, true /* doLayout */);
    }

    private void resize(int width, int height, int densityDpi, boolean doLayout) {
        mWidth = width;
        mHeight = height;
        mDensityDpi = densityDpi;
        mTitle = mContext.getResources().getString(
                com.android.internal.R.string.display_manager_overlay_display_title,
                mName, mWidth, mHeight, mDensityDpi);
        if (mSecure) {
            mTitle += mContext.getResources().getString(
                    com.android.internal.R.string.display_manager_overlay_display_secure_suffix);
        }
        if (doLayout) {
            relayout();
        }
    }

    public void relayout() {
        if (mWindowVisible) {
            updateWindowParams();