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

Commit 5abd083b authored by Nergi Rahardi's avatar Nergi Rahardi Committed by Android (Google) Code Review
Browse files

Merge changes If2e9f410,Ie3c6caba into main

* changes:
  Update getConnectedDisplays to generic getDisplays with extra field
  Handle display pane update from DisplayListener
parents 7780f30b 36ed3cc3
Loading
Loading
Loading
Loading
+23 −31
Original line number Diff line number Diff line
@@ -102,11 +102,20 @@ open class ConnectedDisplayInjector(open val context: Context?) {
        return RevealedWallpaper(display.displayId, view, windowManager)
    }

    private fun wrapDmDisplay(display: Display, isEnabled: DisplayIsEnabled): DisplayDevice =
        DisplayDevice(display.displayId, display.name, display.mode,
                display.getSupportedModes().asList(), isEnabled)

    private fun isDisplayAllowed(display: Display): Boolean =
    private fun wrapDmDisplay(
        display: Display,
        isEnabled: DisplayIsEnabled,
        isConnectedDisplay: Boolean
    ): DisplayDevice = DisplayDevice(
        display.displayId,
        display.name,
        display.mode,
        display.supportedModes.asList(),
        isEnabled,
        isConnectedDisplay
    )

    private fun isConnectedDisplay(display: Display): Boolean =
        display.type == Display.TYPE_EXTERNAL || display.type == Display.TYPE_OVERLAY
                || isVirtualDisplayAllowed(display);

@@ -133,35 +142,18 @@ open class ConnectedDisplayInjector(open val context: Context?) {
    }

    /**
     * TODO(b/419742776): Unify this with #getAllDisplayIds
     * @return all displays including disabled.
     */
    open fun getConnectedDisplays(): List<DisplayDevice> {
    open fun getDisplays(): List<DisplayDevice> {
        val dm = displayManager ?: return emptyList()

        val enabledIds = dm.getDisplays().map { it.getDisplayId() }.toSet()

        return dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)
            .filter { isDisplayAllowed(it) }
            .map {
                val isEnabled = if (enabledIds.contains(it.displayId))
                    DisplayIsEnabled.YES
                else
                    DisplayIsEnabled.NO
                wrapDmDisplay(it, isEnabled)
            }
            .toList()
    }
        val enabledIds = dm.displays.map { it.displayId }.toSet()

    /**
     * This method return all enabled display ids without further filtering
     * TODO(b/419742776): Unify this with #getConnectedDisplays
     *
     * @see getConnectedDisplays to specifically fetch all connected displays
     */
    open fun getAllDisplayIds(): List<Int> {
        val dm = displayManager ?: return emptyList()
        return dm.getDisplays().map { it.displayId }.toList()
        return dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED).map {
            val isEnabled = if (enabledIds.contains(it.displayId)) DisplayIsEnabled.YES
            else DisplayIsEnabled.NO
            wrapDmDisplay(it, isEnabled, isConnectedDisplay(it))
        }.toList()
    }

    /**
@@ -174,8 +166,8 @@ open class ConnectedDisplayInjector(open val context: Context?) {
            return null
        }
        val display = displayManager?.getDisplay(displayId) ?: return null
        return if (isDisplayAllowed(display)) {
            wrapDmDisplay(display, DisplayIsEnabled.UNKNOWN)
        return if (isConnectedDisplay(display)) {
            wrapDmDisplay(display, DisplayIsEnabled.UNKNOWN, true)
        } else {
            null
        }
+17 −4
Original line number Diff line number Diff line
@@ -17,15 +17,28 @@
package com.android.settings.connecteddevice.display

import android.view.Display.Mode

import androidx.annotation.Keep

enum class DisplayIsEnabled { YES, NO, UNKNOWN }
/**
 * Unknown is a convenience enum to denote the query for isEnabled was skipped, since it took more
 * time to query this info.
 */
enum class DisplayIsEnabled {
    YES,
    NO,
    UNKNOWN,
}

/**
 * Contains essential information from {@link android.view.Display} needed by the user to configure
 * a display.
 */
@Keep
data class DisplayDevice(val id: Int, val name: String, val mode: Mode?,
        val supportedModes: List<Mode>, val isEnabled: DisplayIsEnabled) {}
data class DisplayDevice(
    val id: Int,
    val name: String,
    val mode: Mode?,
    val supportedModes: List<Mode>,
    val isEnabled: DisplayIsEnabled,
    val isConnectedDisplay: Boolean,
)
+72 −30
Original line number Diff line number Diff line
@@ -60,6 +60,13 @@ class DisplayTopologyPreference(val injector: ConnectedDisplayInjector) :

    private val topologyListener = Consumer<DisplayTopology> { applyTopology(it) }

    private val displayListener =
        object : ExternalDisplaySettingsConfiguration.DisplayListener() {
            override fun update(displayId: Int) {
                applyDisplayUpdateInMirroringMode()
            }
        }

    private val paneContentLayoutListener =
        object : View.OnLayoutChangeListener {
            override fun onLayoutChange(
@@ -117,6 +124,7 @@ class DisplayTopologyPreference(val injector: ConnectedDisplayInjector) :
    override fun onAttached() {
        super.onAttached()
        injector.registerTopologyListener(topologyListener)
        injector.registerDisplayListener(displayListener)
    }

    override fun onDetached() {
@@ -128,6 +136,7 @@ class DisplayTopologyPreference(val injector: ConnectedDisplayInjector) :
        revealedWallpapers = listOf()

        injector.unregisterTopologyListener(topologyListener)
        injector.unregisterDisplayListener(displayListener)
    }

    /**
@@ -200,6 +209,7 @@ class DisplayTopologyPreference(val injector: ConnectedDisplayInjector) :
        }

        applyTopology(topology)
        applyDisplayUpdateInMirroringMode()
    }

    @VisibleForTesting var timesRefreshedBlocks = 0
@@ -212,26 +222,19 @@ class DisplayTopologyPreference(val injector: ConnectedDisplayInjector) :
     * 4. Ensure wallpapers are revealed
     */
    private fun applyTopology(topology: DisplayTopology) {
        // Step 1
        val showStackedMirroringDisplay =
            isDisplayInMiroringMode(context) &&
                injector.flags.showStackedMirroringDisplayConnectedDisplaySetting()
        topologyHint.text =
            if (showStackedMirroringDisplay) {
                ""
            } else {
                context.getString(R.string.external_display_topology_hint)
        // If stacked mirroring display is turned on, updates will come from DisplayListener since
        // there's no more topology update when display is added / removed
        if (showStackedMirroringDisplay()) {
            return
        }

        val idToNode = topology.allNodesIdMap()
        val logicalDisplaySizeFetcher = LogicalDisplaySizeFetcher(injector, idToNode)

        // Step 1
        topologyHint.text = context.getString(R.string.external_display_topology_hint)
        // Step 2
        val oldBounds = topologyInfo?.positions
        val newBounds =
            if (showStackedMirroringDisplay)
                processDisplayBoundsMirroringMode(logicalDisplaySizeFetcher)
            else processDisplayBounds(topology)
        val newBounds = buildList {
            val bounds = topology.absoluteBounds
            (0..bounds.size() - 1).forEach { add(Pair(bounds.keyAt(it), bounds.valueAt(it))) }
        }
        if (
            oldBounds != null &&
                oldBounds.size == newBounds.size &&
@@ -241,8 +244,9 @@ class DisplayTopologyPreference(val injector: ConnectedDisplayInjector) :
        ) {
            return
        }

        // Step 3
        val idToNode = topology.allNodesIdMap()
        val logicalDisplaySizeFetcher = LogicalDisplaySizeFetcher(injector, idToNode)
        val scaling =
            TopologyScale(
                paneContent.width,
@@ -254,16 +258,50 @@ class DisplayTopologyPreference(val injector: ConnectedDisplayInjector) :
            scaling,
            newBounds,
            logicalDisplaySizeFetcher,
            showStackedMirroringDisplay,
            /* isMirroring= */ false,
        )
        topologyInfo = TopologyInfo(topology, scaling, newBounds)
        // Step 4
        revealWallpapers(idToNode.keys.toSet())
    }

    /**
     * Updating DisplayTopology pane consists of multiple steps:
     * 1. Remove hint text
     * 2. Prepare display blocks positioning
     * 3. Adjust display blocks bounds and scale within the pane
     * 4. Ensure wallpapers are revealed for mirrored display and removed for other displays
     */
    private fun applyDisplayUpdateInMirroringMode() {
        // If stacked mirroring display is turned off, update will be handled by topology update
        if (!showStackedMirroringDisplay()) {
            return
        }
        // Step 1
        topologyHint.text = ""
        // Step 2
        val logicalDisplaySizeFetcher = LogicalDisplaySizeFetcher(injector, emptyMap())
        val newBounds = processDisplayBoundsMirroringMode(logicalDisplaySizeFetcher)
        // Step 3
        val scaling =
            TopologyScale(
                paneContent.width,
                minEdgeLength = DisplayTopology.dpToPx(MIN_EDGE_LENGTH_DP, injector.densityDpi),
                maxEdgeLength = DisplayTopology.dpToPx(MAX_EDGE_LENGTH_DP, injector.densityDpi),
                newBounds.map { it.second },
            )
        setupDisplayPaneAndBlocks(
            scaling,
            newBounds,
            logicalDisplaySizeFetcher,
            /* isMirroring= */ true,
        )
        topologyInfo = null
        // Step 4
        val displayIdsToRevealWallpaper =
            if (showStackedMirroringDisplay) setOf(DEFAULT_DISPLAY)
            else {
                idToNode.keys.toSet()
        revealWallpapers(setOf(DEFAULT_DISPLAY))
    }

    private fun revealWallpapers(displayIdsToRevealWallpaper: Set<Int>) {
        // Construct a map containing revealers that we want to keep (keepRevealing). Then create a
        // list comprised of the values of that map as well as new revealers (revealedWallpapers).
        val keepRevealing =
@@ -283,15 +321,15 @@ class DisplayTopologyPreference(val injector: ConnectedDisplayInjector) :
                .toList()
    }

    private fun processDisplayBounds(topology: DisplayTopology) = buildList {
        val bounds = topology.absoluteBounds
        (0..bounds.size() - 1).forEach { add(Pair(bounds.keyAt(it), bounds.valueAt(it))) }
    }

    private fun processDisplayBoundsMirroringMode(
        logicalDisplaySizeFetcher: LogicalDisplaySizeFetcher
    ): List<Pair<Int, RectF>> {
        val displayIds = injector.getAllDisplayIds().sortedBy { it }
        val displayIds =
            injector
                .getDisplays()
                .filter { it.isEnabled == DisplayIsEnabled.YES }
                .map { it.id }
                .sortedBy { it }

        val bounds = mutableListOf<Pair<Int, RectF>>()
        val mirroringDiagonalStackOffsetPx =
@@ -473,6 +511,10 @@ class DisplayTopologyPreference(val injector: ConnectedDisplayInjector) :
        return true
    }

    private fun showStackedMirroringDisplay() =
        isDisplayInMiroringMode(context) &&
            injector.flags.showStackedMirroringDisplayConnectedDisplaySetting()

    /**
     * A simple wrapper class to fetch logical display size from either DisplayTopology or directly
     * from DisplayManager. This should used as a temporary variable only for the current
+2 −1
Original line number Diff line number Diff line
@@ -360,7 +360,8 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
    }

    private void updateScreen(final PrefRefresh screen) {
        final var displaysToShow = mInjector.getConnectedDisplays();
        final var displaysToShow = mInjector.getDisplays().stream().filter(
                DisplayDevice::isConnectedDisplay).toList();

        if (displaysToShow.isEmpty()) {
            showTextWhenNoDisplaysToShow(screen, /* position= */ 0);
+2 −1
Original line number Diff line number Diff line
@@ -131,7 +131,8 @@ public class ExternalDisplayUpdater {
            return null;
        }

        var allDisplays = mInjector.getConnectedDisplays();
        var allDisplays = mInjector.getDisplays().stream().filter(
                DisplayDevice::isConnectedDisplay).toList();
        for (var display : allDisplays) {
            if (display.isEnabled() == DisplayIsEnabled.YES) {
                return context.getString(R.string.external_display_on);
Loading