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

Commit 1df8bde2 authored by Marin Shalamanov's avatar Marin Shalamanov
Browse files

Add Display.Mode.getAlternativeRefreshRates()

Add a method to Display.Mode to return all refresh rates
to which a seamless display mode switch can be done. Note
that this is not a hard guarantee for seamless switches,
but rather a guarantee that switching to any other mode
will be non seamless.

This is implemented using the config groups which we get
from SurfaceFlinger.

Bug: 161776429
Test: atest LocalDisplayAdapterTest
Change-Id: Id0e721f6c278ce9dcc04d59422b2f881a1154102
parent 135dc67c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -52665,6 +52665,7 @@ package android.view {
  public static final class Display.Mode implements android.os.Parcelable {
    method public int describeContents();
    method @NonNull public float[] getAlternativeRefreshRates();
    method public int getModeId();
    method public int getPhysicalHeight();
    method public int getPhysicalWidth();
+1 −0
Original line number Diff line number Diff line
@@ -50772,6 +50772,7 @@ package android.view {
  public static final class Display.Mode implements android.os.Parcelable {
    method public int describeContents();
    method @NonNull public float[] getAlternativeRefreshRates();
    method public int getModeId();
    method public int getPhysicalHeight();
    method public int getPhysicalWidth();
+42 −2
Original line number Diff line number Diff line
@@ -1405,16 +1405,29 @@ public final class Display {
        private final int mWidth;
        private final int mHeight;
        private final float mRefreshRate;
        @NonNull
        private final float[] mAlternativeRefreshRates;

        /**
         * @hide
         */
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        public Mode(int modeId, int width, int height, float refreshRate) {
            this(modeId, width, height, refreshRate, new float[0]);
        }

        /**
         * @hide
         */
        public Mode(int modeId, int width, int height, float refreshRate,
                float[] alternativeRefreshRates) {
            mModeId = modeId;
            mWidth = width;
            mHeight = height;
            mRefreshRate = refreshRate;
            mAlternativeRefreshRates =
                    Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length);
            Arrays.sort(mAlternativeRefreshRates);
        }

        /**
@@ -1463,6 +1476,28 @@ public final class Display {
            return mRefreshRate;
        }

        /**
         * Returns an array of refresh rates which can be switched to seamlessly.
         * <p>
         * A seamless switch is one without visual interruptions, such as a black screen for
         * a second or two.
         * <p>
         * Presence in this list does not guarantee a switch will occur to the desired
         * refresh rate, but rather, if a switch does occur to a refresh rate in this list,
         * it is guaranteed to be seamless.
         * <p>
         * The binary relation "refresh rate X is alternative to Y" is non-reflexive,
         * symmetric and transitive. For example the mode 1920x1080 60Hz, will never have an
         * alternative refresh rate of 60Hz. If 1920x1080 60Hz has an alternative of 50Hz
         * then 1920x1080 50Hz will have alternative refresh rate of 60Hz. If 1920x1080 60Hz
         * has an alternative of 50Hz and 1920x1080 50Hz has an alternative of 24Hz, then 1920x1080
         * 60Hz will also have an alternative of 24Hz.
         */
        @NonNull
        public float[] getAlternativeRefreshRates() {
            return mAlternativeRefreshRates;
        }

        /**
         * Returns {@code true} if this mode matches the given parameters.
         *
@@ -1483,7 +1518,8 @@ public final class Display {
                return false;
            }
            Mode that = (Mode) other;
            return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate);
            return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate)
                    && Arrays.equals(mAlternativeRefreshRates, that.mAlternativeRefreshRates);
        }

        @Override
@@ -1493,6 +1529,7 @@ public final class Display {
            hash = hash * 17 + mWidth;
            hash = hash * 17 + mHeight;
            hash = hash * 17 + Float.floatToIntBits(mRefreshRate);
            hash = hash * 17 + Arrays.hashCode(mAlternativeRefreshRates);
            return hash;
        }

@@ -1503,6 +1540,8 @@ public final class Display {
                    .append(", width=").append(mWidth)
                    .append(", height=").append(mHeight)
                    .append(", fps=").append(mRefreshRate)
                    .append(", alternativeRefreshRates=")
                    .append(Arrays.toString(mAlternativeRefreshRates))
                    .append("}")
                    .toString();
        }
@@ -1513,7 +1552,7 @@ public final class Display {
        }

        private Mode(Parcel in) {
            this(in.readInt(), in.readInt(), in.readInt(), in.readFloat());
            this(in.readInt(), in.readInt(), in.readInt(), in.readFloat(), in.createFloatArray());
        }

        @Override
@@ -1522,6 +1561,7 @@ public final class Display {
            out.writeInt(mWidth);
            out.writeInt(mHeight);
            out.writeFloat(mRefreshRate);
            out.writeFloatArray(mAlternativeRefreshRates);
        }

        @SuppressWarnings("hiding")
+7 −2
Original line number Diff line number Diff line
@@ -120,8 +120,13 @@ abstract class DisplayAdapter {
    }

    public static Display.Mode createMode(int width, int height, float refreshRate) {
        return new Display.Mode(
                NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate);
        return createMode(width, height, refreshRate, new float[0]);
    }

    public static Display.Mode createMode(int width, int height, float refreshRate,
            float[] alternativeRefreshRates) {
        return new Display.Mode(NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate,
                alternativeRefreshRates);
    }

    public interface Listener {
+44 −8
Original line number Diff line number Diff line
@@ -266,12 +266,27 @@ final class LocalDisplayAdapter extends DisplayAdapter {
            boolean modesAdded = false;
            for (int i = 0; i < configs.length; i++) {
                SurfaceControl.DisplayConfig config = configs[i];
                List<Float> alternativeRefreshRates = new ArrayList<>();
                for (int j = 0; j < configs.length; j++) {
                    SurfaceControl.DisplayConfig other = configs[j];
                    boolean isAlternative = j != i && other.width == config.width
                            && other.height == config.height
                            && other.refreshRate != config.refreshRate
                            && other.configGroup == config.configGroup;
                    if (isAlternative) {
                        alternativeRefreshRates.add(configs[j].refreshRate);
                    }
                }
                Collections.sort(alternativeRefreshRates);

                // First, check to see if we've already added a matching mode. Since not all
                // configuration options are exposed via Display.Mode, it's possible that we have
                // multiple DisplayConfigs that would generate the same Display.Mode.
                boolean existingMode = false;
                for (int j = 0; j < records.size(); j++) {
                    if (records.get(j).hasMatchingMode(config)) {
                for (DisplayModeRecord record : records) {
                    if (record.hasMatchingMode(config)
                            && refreshRatesEquals(alternativeRefreshRates,
                                    record.mMode.getAlternativeRefreshRates())) {
                        existingMode = true;
                        break;
                    }
@@ -282,9 +297,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
                // If we haven't already added a mode for this configuration to the new set of
                // supported modes then check to see if we have one in the prior set of supported
                // modes to reuse.
                DisplayModeRecord record = findDisplayModeRecord(config);
                DisplayModeRecord record = findDisplayModeRecord(config, alternativeRefreshRates);
                if (record == null) {
                    record = new DisplayModeRecord(config);
                    float[] alternativeRates = new float[alternativeRefreshRates.size()];
                    for (int j = 0; j < alternativeRates.length; j++) {
                        alternativeRates[j] = alternativeRefreshRates.get(j);
                    }
                    record = new DisplayModeRecord(config, alternativeRates);
                    modesAdded = true;
                }
                records.add(record);
@@ -495,16 +514,31 @@ final class LocalDisplayAdapter extends DisplayAdapter {
            return true;
        }

        private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config) {
        private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config,
                List<Float> alternativeRefreshRates) {
            for (int i = 0; i < mSupportedModes.size(); i++) {
                DisplayModeRecord record = mSupportedModes.valueAt(i);
                if (record.hasMatchingMode(config)) {
                if (record.hasMatchingMode(config)
                        && refreshRatesEquals(alternativeRefreshRates,
                                record.mMode.getAlternativeRefreshRates())) {
                    return record;
                }
            }
            return null;
        }

        private boolean refreshRatesEquals(List<Float> list, float[] array) {
            if (list.size() != array.length) {
                return false;
            }
            for (int i = 0; i < list.size(); i++) {
                if (Float.floatToIntBits(list.get(i)) != Float.floatToIntBits(array[i])) {
                    return false;
                }
            }
            return true;
        }

        @Override
        public void applyPendingDisplayDeviceInfoChangesLocked() {
            if (mHavePendingChanges) {
@@ -1032,8 +1066,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
    private static final class DisplayModeRecord {
        public final Display.Mode mMode;

        DisplayModeRecord(SurfaceControl.DisplayConfig config) {
            mMode = createMode(config.width, config.height, config.refreshRate);
        DisplayModeRecord(SurfaceControl.DisplayConfig config,
                float[] alternativeRefreshRates) {
            mMode = createMode(config.width, config.height, config.refreshRate,
                    alternativeRefreshRates);
        }

        /**
Loading