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

Commit 0a2167a0 authored by shawnlin's avatar shawnlin
Browse files

Support display cutout for multi-display devices

- Add a new string array config that stores the unique id of each
  display and when loading the cutout configs we first look up the index
  of the unique id of the added display in the array and use this index
  to load the corresponding cutout configs.
- Add new array configs for every cutout configs.

Bug: 186604541
Test: make, atest LocalDisplayAdapterTest
Test: check the device and see if the cutout is correctly set for each
display

Change-Id: I038832795c11cd16969caff5031fa1090493b008
parent 0330d6ef
Loading
Loading
Loading
Loading
+139 −9
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Path;
@@ -872,6 +873,135 @@ public final class DisplayCutout {
                false /* copyArguments */);
    }

    /**
     * Gets the index of the given display unique id in {@link R.array#config_displayUniqueIdArray}
     * which is used to get the related cutout configs for that display.
     *
     * For multi-display device, {@link R.array#config_displayUniqueIdArray} should be set for each
     * display if there are different type of cutouts on each display.
     * For single display device, {@link R.array#config_displayUniqueIdArray} should not to be set
     * and the system will load the default configs for main built-in display.
     */
    private static int getDisplayCutoutConfigIndex(Resources res, String displayUniqueId) {
        int index = -1;
        if (displayUniqueId == null || displayUniqueId.isEmpty()) {
            return index;
        }
        final String[] ids = res.getStringArray(R.array.config_displayUniqueIdArray);
        final int size = ids.length;
        for (int i = 0; i < size; i++) {
            if (displayUniqueId.equals(ids[i])) {
                index = i;
                break;
            }
        }
        return index;
    }

    /**
     * Gets the display cutout by the given display unique id.
     *
     * Loads the default config {@link R.string#config_mainBuiltInDisplayCutout) if
     * {@link R.array#config_displayUniqueIdArray} is not set.
     */
    private static String getDisplayCutoutPath(Resources res, String displayUniqueId) {
        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
        final String[] array = res.getStringArray(R.array.config_displayCutoutPathArray);
        if (index >= 0 && index < array.length) {
            return array[index];
        }
        return res.getString(R.string.config_mainBuiltInDisplayCutout);
    }

    /**
     * Gets the display cutout approximation rect by the given display unique id.
     *
     * Loads the default config {@link R.string#config_mainBuiltInDisplayCutoutRectApproximation} if
     * {@link R.array#config_displayUniqueIdArray} is not set.
     */
    private static String getDisplayCutoutApproximationRect(Resources res, String displayUniqueId) {
        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
        final String[] array = res.getStringArray(
                R.array.config_displayCutoutApproximationRectArray);
        if (index >= 0 && index < array.length) {
            return array[index];
        }
        return res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation);
    }

    /**
     * Gets whether to mask a built-in display cutout of a display which is determined by the
     * given display unique id.
     *
     * Loads the default config {@link R.bool#config_maskMainBuiltInDisplayCutout} if
     * {@link R.array#config_displayUniqueIdArray} is not set.
     *
     * @hide
     */
    public static boolean getMaskBuiltInDisplayCutout(Resources res, String displayUniqueId) {
        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
        final TypedArray array = res.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray);
        boolean maskCutout;
        if (index >= 0 && index < array.length()) {
            maskCutout = array.getBoolean(index, false);
        } else {
            maskCutout = res.getBoolean(R.bool.config_maskMainBuiltInDisplayCutout);
        }
        array.recycle();
        return maskCutout;
    }

    /**
     * Gets whether to fill a built-in display cutout of a display which is determined by the
     * given display unique id.
     *
     * Loads the default config{@link R.bool#config_fillMainBuiltInDisplayCutout} if
     * {@link R.array#config_displayUniqueIdArray} is not set.
     *
     * @hide
     */
    public static boolean getFillBuiltInDisplayCutout(Resources res, String displayUniqueId) {
        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
        final TypedArray array = res.obtainTypedArray(R.array.config_fillBuiltInDisplayCutoutArray);
        boolean fillCutout;
        if (index >= 0 && index < array.length()) {
            fillCutout = array.getBoolean(index, false);
        } else {
            fillCutout = res.getBoolean(R.bool.config_fillMainBuiltInDisplayCutout);
        }
        array.recycle();
        return fillCutout;
    }

    /**
     * Gets the waterfall cutout by the given display unique id.
     *
     * Loads the default waterfall dimens if {@link R.array#config_displayUniqueIdArray} is not set.
     * {@link R.dimen#waterfall_display_left_edge_size},
     * {@link R.dimen#waterfall_display_top_edge_size},
     * {@link R.dimen#waterfall_display_right_edge_size},
     * {@link R.dimen#waterfall_display_bottom_edge_size}
     */
    private static Insets getWaterfallInsets(Resources res, String displayUniqueId) {
        Insets insets;
        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
        final TypedArray array = res.obtainTypedArray(R.array.config_waterfallCutoutArray);
        if (index >= 0 && index < array.length() && array.getResourceId(index, 0) > 0) {
            final int resourceId = array.getResourceId(index, 0);
            final TypedArray waterfall = res.obtainTypedArray(resourceId);
            insets = Insets.of(
                    waterfall.getDimensionPixelSize(0 /* waterfall left edge size */, 0),
                    waterfall.getDimensionPixelSize(1 /* waterfall top edge size */, 0),
                    waterfall.getDimensionPixelSize(2 /* waterfall right edge size */, 0),
                    waterfall.getDimensionPixelSize(3 /* waterfall bottom edge size */, 0));
            waterfall.recycle();
        } else {
            insets = loadWaterfallInset(res);
        }
        array.recycle();
        return insets;
    }

    /**
     * Creates the display cutout according to
     * @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest
@@ -879,12 +1009,12 @@ public final class DisplayCutout {
     *
     * @hide
     */
    public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth,
            int displayHeight) {
        return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
                res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
    public static DisplayCutout fromResourcesRectApproximation(Resources res,
            String displayUniqueId, int displayWidth, int displayHeight) {
        return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId),
                getDisplayCutoutApproximationRect(res, displayUniqueId),
                displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
                loadWaterfallInset(res)).second;
                getWaterfallInsets(res, displayUniqueId)).second;
    }

    /**
@@ -892,11 +1022,11 @@ public final class DisplayCutout {
     *
     * @hide
     */
    public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
        return pathAndDisplayCutoutFromSpec(
                res.getString(R.string.config_mainBuiltInDisplayCutout), null,
    public static Path pathFromResources(Resources res, String displayUniqueId, int displayWidth,
            int displayHeight) {
        return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId), null,
                displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
                loadWaterfallInset(res)).first;
                getWaterfallInsets(res, displayUniqueId)).first;
    }

    /**
+76 −0
Original line number Diff line number Diff line
@@ -5081,4 +5081,80 @@

    <!-- Whether this device should support taking app snapshots on closure -->
    <bool name="config_disableTaskSnapshots">false</bool>

    <!-- The display cutout configs for secondary built-in display. -->
    <string name="config_secondaryBuiltInDisplayCutout" translatable="false"></string>
    <string name="config_secondaryBuiltInDisplayCutoutRectApproximation" translatable="false">
        @string/config_secondaryBuiltInDisplayCutout
    </string>
    <bool name="config_fillSecondaryBuiltInDisplayCutout">false</bool>
    <bool name="config_maskSecondaryBuiltInDisplayCutout">false</bool>

    <!-- An array contains unique ids of all built-in displays and the unique id of a display can be
         obtained from {@link Display#getUniqueId}. This array should be set for multi-display
         devices if there are different display related configs(e.g. display cutout, rounded corner)
         between each built-in display.
         It is used as an index for multi-display related configs:
         First look up the index of the unique id of the given built-in display unique id in this
         array and use this index to get the info in corresponding config arrays such as:
           - config_displayCutoutPathArray
           - config_displayCutoutApproximationRectArray
           - config_fillBuiltInDisplayCutoutArray
           - config_maskBuiltInDisplayCutoutArray
           - config_waterfallCutoutArray

         Leave this array empty for single display device and the system will load the default main
         built-in related configs.
         -->
    <string-array name="config_displayUniqueIdArray" translatable="false">
        <!-- Example:
        <item>"local:1234567891"</item> // main built-in display
        <item>"local:1234567892"</item> // secondary built-in display
        -->
    </string-array>

    <!-- The display cutout path config for each display in a multi-display device. -->
    <string-array name="config_displayCutoutPathArray" translatable="false">
        <item>@string/config_mainBuiltInDisplayCutout</item>
        <item>@string/config_secondaryBuiltInDisplayCutout</item>
    </string-array>

    <!-- The display cutout approximation rect config for each display in a multi-display device.
         -->
    <string-array name="config_displayCutoutApproximationRectArray" translatable="false">
        <item>@string/config_mainBuiltInDisplayCutoutRectApproximation</item>
        <item>@string/config_secondaryBuiltInDisplayCutoutRectApproximation</item>
    </string-array>

    <!-- The maskBuiltInDisplayCutout config for each display in a multi-display device. -->
    <array name="config_maskBuiltInDisplayCutoutArray" translatable="false">
        <item>@bool/config_maskMainBuiltInDisplayCutout</item>
        <item>@bool/config_maskSecondaryBuiltInDisplayCutout</item>
    </array>

    <!-- The fillBuiltInDisplayCutout config for each display in a multi-display device. -->
    <array name="config_fillBuiltInDisplayCutoutArray" translatable="false">
        <item>@bool/config_fillMainBuiltInDisplayCutout</item>
        <item>@bool/config_fillSecondaryBuiltInDisplayCutout</item>
    </array>

    <array name="config_mainBuiltInDisplayWaterfallCutout" translatable="false">
        <item>@dimen/waterfall_display_left_edge_size</item>
        <item>@dimen/waterfall_display_top_edge_size</item>
        <item>@dimen/waterfall_display_right_edge_size</item>
        <item>@dimen/waterfall_display_bottom_edge_size</item>
    </array>

    <array name="config_secondaryBuiltInDisplayWaterfallCutout" translatable="false">
        <item>@dimen/secondary_waterfall_display_left_edge_size</item>
        <item>@dimen/secondary_waterfall_display_top_edge_size</item>
        <item>@dimen/secondary_waterfall_display_right_edge_size</item>
        <item>@dimen/secondary_waterfall_display_bottom_edge_size</item>
    </array>

    <!-- The waterfall cutout config for each display in a multi-display device. -->
    <array name="config_waterfallCutoutArray" translatable="false">
        <item>@array/config_mainBuiltInDisplayWaterfallCutout</item>
        <item>@array/config_secondaryBuiltInDisplayWaterfallCutout</item>
    </array>
</resources>
+7 −1
Original line number Diff line number Diff line
@@ -920,7 +920,7 @@

    <dimen name="chooser_action_button_icon_size">18dp</dimen>

    <!-- For Waterfall Display -->
    <!-- For main built-in Waterfall Display -->
    <dimen name="waterfall_display_left_edge_size">0px</dimen>
    <dimen name="waterfall_display_top_edge_size">0px</dimen>
    <dimen name="waterfall_display_right_edge_size">0px</dimen>
@@ -943,4 +943,10 @@
    <dimen name="starting_surface_icon_size">160dp</dimen>
    <!-- The default width/height of the icon on the spec of adaptive icon drawable. -->
    <dimen name="starting_surface_default_icon_size">108dp</dimen>

    <!-- For secondary built-in Waterfall Display -->
    <dimen name="secondary_waterfall_display_left_edge_size">0px</dimen>
    <dimen name="secondary_waterfall_display_top_edge_size">0px</dimen>
    <dimen name="secondary_waterfall_display_right_edge_size">0px</dimen>
    <dimen name="secondary_waterfall_display_bottom_edge_size">0px</dimen>
</resources>
+17 −0
Original line number Diff line number Diff line
@@ -4443,4 +4443,21 @@
  <java-symbol type="integer" name="config_customizedMaxCachedProcesses" />

  <java-symbol type="bool" name="config_disableTaskSnapshots" />

  <java-symbol type="string" name="config_secondaryBuiltInDisplayCutout" />
  <java-symbol type="string" name="config_secondaryBuiltInDisplayCutoutRectApproximation" />
  <java-symbol type="bool" name="config_fillSecondaryBuiltInDisplayCutout" />
  <java-symbol type="bool" name="config_maskSecondaryBuiltInDisplayCutout" />
  <java-symbol type="array" name="config_displayUniqueIdArray" />
  <java-symbol type="array" name="config_displayCutoutPathArray" />
  <java-symbol type="array" name="config_displayCutoutApproximationRectArray" />
  <java-symbol type="array" name="config_fillBuiltInDisplayCutoutArray" />
  <java-symbol type="array" name="config_maskBuiltInDisplayCutoutArray" />
  <java-symbol type="dimen" name="secondary_waterfall_display_left_edge_size" />
  <java-symbol type="dimen" name="secondary_waterfall_display_top_edge_size" />
  <java-symbol type="dimen" name="secondary_waterfall_display_right_edge_size" />
  <java-symbol type="dimen" name="secondary_waterfall_display_bottom_edge_size" />
  <java-symbol type="array" name="config_mainBuiltInDisplayWaterfallCutout" />
  <java-symbol type="array" name="config_secondaryBuiltInDisplayWaterfallCutout" />
  <java-symbol type="array" name="config_waterfallCutoutArray" />
</resources>
+4 −3
Original line number Diff line number Diff line
@@ -797,8 +797,8 @@ public class ScreenDecorations extends SystemUI implements Tunable {
    }

    static boolean shouldDrawCutout(Context context) {
        return context.getResources().getBoolean(
                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
        return DisplayCutout.getFillBuiltInDisplayCutout(
                context.getResources(), context.getDisplay().getUniqueId());
    }

    private void updateLayoutParams() {
@@ -1085,7 +1085,8 @@ public class ScreenDecorations extends SystemUI implements Tunable {
            int dw = flipped ? lh : lw;
            int dh = flipped ? lw : lh;

            Path path = DisplayCutout.pathFromResources(getResources(), dw, dh);
            Path path = DisplayCutout.pathFromResources(
                    getResources(), getDisplay().getUniqueId(), dw, dh);
            if (path != null) {
                mBoundingPath.set(path);
            } else {
Loading