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

Commit 72bc6f53 authored by Jordan Silva's avatar Jordan Silva Committed by Android (Google) Code Review
Browse files

Merge changes from topic "comet-landscape" into main

* changes:
  Update Responsive Grid tests with aspect ratio group
  Refactoring Responsive Grid XML specs for more flexibility
parents b503e27a d7c7eaf8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -268,6 +268,10 @@
        <attr name="maxAvailableSize" format="dimension" />
    </declare-styleable>

    <declare-styleable name="ResponsiveSpecGroup">
        <attr name="maxAspectRatio" format="float" />
    </declare-styleable>

    <declare-styleable name="WorkspaceSpec">
        <attr name="specType" />
        <attr name="maxAvailableSize" />
+54 −41
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.launcher3;

import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.Flags.enableOverviewIconMenu;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_DEFAULT;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_LANDSCAPE;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_LANDSCAPE;
@@ -24,7 +25,6 @@ import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_PORTR
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.Utilities.pxFromSp;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH;
import static com.android.launcher3.Flags.enableOverviewIconMenu;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.icons.GraphicsUtils.getShapePath;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
@@ -54,14 +54,12 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.responsive.AllAppsSpecs;
import com.android.launcher3.responsive.CalculatedAllAppsSpec;
import com.android.launcher3.responsive.CalculatedFolderSpec;
import com.android.launcher3.responsive.CalculatedHotseatSpec;
import com.android.launcher3.responsive.CalculatedWorkspaceSpec;
import com.android.launcher3.responsive.FolderSpecs;
import com.android.launcher3.responsive.HotseatSpecs;
import com.android.launcher3.responsive.WorkspaceSpecs;
import com.android.launcher3.responsive.CalculatedResponsiveSpec;
import com.android.launcher3.responsive.HotseatSpecsProvider;
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType;
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType;
import com.android.launcher3.responsive.ResponsiveSpecsProvider;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.CellContentDimensions;
import com.android.launcher3.util.DisplayController;
@@ -84,7 +82,8 @@ public class DeviceProfile {

    public static final PointF DEFAULT_SCALE = new PointF(1.0f, 1.0f);
    public static final ViewScaleProvider DEFAULT_PROVIDER = itemInfo -> DEFAULT_SCALE;
    public static final Consumer<DeviceProfile> DEFAULT_DIMENSION_PROVIDER = dp -> {};
    public static final Consumer<DeviceProfile> DEFAULT_DIMENSION_PROVIDER = dp -> {
    };

    public final InvariantDeviceProfile inv;
    private final Info mInfo;
@@ -119,12 +118,12 @@ public class DeviceProfile {

    // Responsive grid
    private final boolean mIsResponsiveGrid;
    private CalculatedWorkspaceSpec mResponsiveWidthSpec;
    private CalculatedWorkspaceSpec mResponsiveHeightSpec;
    private CalculatedAllAppsSpec mAllAppsResponsiveWidthSpec;
    private CalculatedAllAppsSpec mAllAppsResponsiveHeightSpec;
    private CalculatedFolderSpec mResponsiveFolderWidthSpec;
    private CalculatedFolderSpec mResponsiveFolderHeightSpec;
    private CalculatedResponsiveSpec mResponsiveWidthSpec;
    private CalculatedResponsiveSpec mResponsiveHeightSpec;
    private CalculatedResponsiveSpec mAllAppsResponsiveWidthSpec;
    private CalculatedResponsiveSpec mAllAppsResponsiveHeightSpec;
    private CalculatedResponsiveSpec mResponsiveFolderWidthSpec;
    private CalculatedResponsiveSpec mResponsiveFolderHeightSpec;
    private CalculatedHotseatSpec mResponsiveHotseatSpec;

    /**
@@ -519,12 +518,15 @@ public class DeviceProfile {
        int minQsbMargin = res.getDimensionPixelSize(R.dimen.min_qsb_margin);

        if (mIsResponsiveGrid) {
            HotseatSpecs hotseatSpecs =
                    HotseatSpecs.create(new ResourceHelper(context,
            float responsiveAspectRatio = (float) widthPx / heightPx;
            HotseatSpecsProvider hotseatSpecsProvider =
                    HotseatSpecsProvider.create(new ResourceHelper(context,
                            isTwoPanels ? inv.hotseatSpecsTwoPanelId : inv.hotseatSpecsId));
            mResponsiveHotseatSpec =
                    isVerticalBarLayout() ? hotseatSpecs.getCalculatedWidthSpec(widthPx)
                            : hotseatSpecs.getCalculatedHeightSpec(heightPx);
                    isVerticalBarLayout() ? hotseatSpecsProvider.getCalculatedSpec(
                            responsiveAspectRatio, DimensionType.WIDTH, widthPx)
                            : hotseatSpecsProvider.getCalculatedSpec(responsiveAspectRatio,
                                    DimensionType.HEIGHT, heightPx);
            hotseatQsbSpace = mResponsiveHotseatSpec.getHotseatQsbSpace();
            hotseatBarBottomSpace =
                    isVerticalBarLayout() ? 0 : mResponsiveHotseatSpec.getEdgePadding();
@@ -587,35 +589,46 @@ public class DeviceProfile {
        // Needs to be calculated after hotseatBarSizePx is correct,
        // for the available height to be correct
        if (mIsResponsiveGrid) {
            WorkspaceSpecs workspaceSpecs = WorkspaceSpecs.create(
                    new ResourceHelper(context,
                            isTwoPanels ? inv.workspaceSpecsTwoPanelId : inv.workspaceSpecsId));
            int availableResponsiveWidth =
                    availableWidthPx - (isVerticalBarLayout() ? hotseatBarSizePx : 0);
            int numColumns = getPanelCount() * inv.numColumns;
            // don't use availableHeightPx because it subtracts mInsets.bottom
            int availableResponsiveHeight = heightPx - mInsets.top
                    - (isVerticalBarLayout() ? 0 : hotseatBarSizePx);
            mResponsiveWidthSpec = workspaceSpecs.getCalculatedWidthSpec(numColumns,
                    availableResponsiveWidth);
            mResponsiveHeightSpec = workspaceSpecs.getCalculatedHeightSpec(inv.numRows,
                    availableResponsiveHeight);
            float responsiveAspectRatio = (float) widthPx / heightPx;

            AllAppsSpecs allAppsSpecs = AllAppsSpecs.create(
            ResponsiveSpecsProvider workspaceSpecs = ResponsiveSpecsProvider.create(
                    new ResourceHelper(context,
                            isTwoPanels ? inv.allAppsSpecsTwoPanelId : inv.allAppsSpecsId));
            mAllAppsResponsiveWidthSpec = allAppsSpecs.getCalculatedWidthSpec(numColumns,
                    mResponsiveWidthSpec.getAvailableSpace(), mResponsiveWidthSpec);
            mAllAppsResponsiveHeightSpec = allAppsSpecs.getCalculatedHeightSpec(inv.numRows,
                    mResponsiveHeightSpec.getAvailableSpace(), mResponsiveHeightSpec);

            FolderSpecs folderSpecs = FolderSpecs.create(
                            isTwoPanels ? inv.workspaceSpecsTwoPanelId : inv.workspaceSpecsId),
                    ResponsiveSpecType.Workspace);
            mResponsiveWidthSpec = workspaceSpecs.getCalculatedSpec(responsiveAspectRatio,
                    DimensionType.WIDTH, numColumns, availableResponsiveWidth);
            mResponsiveHeightSpec = workspaceSpecs.getCalculatedSpec(responsiveAspectRatio,
                    DimensionType.HEIGHT, inv.numRows, availableResponsiveHeight);

            ResponsiveSpecsProvider allAppsSpecs = ResponsiveSpecsProvider.create(
                    new ResourceHelper(context,
                            isTwoPanels ? inv.allAppsSpecsTwoPanelId : inv.allAppsSpecsId),
                    ResponsiveSpecType.AllApps);
            mAllAppsResponsiveWidthSpec = allAppsSpecs.getCalculatedSpec(responsiveAspectRatio,
                    DimensionType.WIDTH, numColumns, mResponsiveWidthSpec.getAvailableSpace(),
                    mResponsiveWidthSpec);
            mAllAppsResponsiveHeightSpec = allAppsSpecs.getCalculatedSpec(responsiveAspectRatio,
                    DimensionType.HEIGHT, inv.numRows, mResponsiveHeightSpec.getAvailableSpace(),
                    mResponsiveHeightSpec);

            ResponsiveSpecsProvider folderSpecs = ResponsiveSpecsProvider.create(
                    new ResourceHelper(context,
                            isTwoPanels ? inv.folderSpecsTwoPanelId : inv.folderSpecsId));
            mResponsiveFolderWidthSpec = folderSpecs.getCalculatedWidthSpec(inv.numFolderColumns,
                    mResponsiveWidthSpec.getAvailableSpace(), mResponsiveWidthSpec);
            mResponsiveFolderHeightSpec = folderSpecs.getCalculatedHeightSpec(inv.numFolderRows,
                    mResponsiveHeightSpec.getAvailableSpace(), mResponsiveHeightSpec);
                            isTwoPanels ? inv.folderSpecsTwoPanelId : inv.folderSpecsId),
                    ResponsiveSpecType.Folder);
            mResponsiveFolderWidthSpec = folderSpecs.getCalculatedSpec(responsiveAspectRatio,
                    DimensionType.WIDTH, inv.numFolderColumns,
                    mResponsiveWidthSpec.getAvailableSpace(),
                    mResponsiveWidthSpec);
            mResponsiveFolderHeightSpec = folderSpecs.getCalculatedSpec(responsiveAspectRatio,
                    DimensionType.HEIGHT, inv.numFolderRows,
                    mResponsiveHeightSpec.getAvailableSpace(),
                    mResponsiveHeightSpec);
        }

        desiredWorkspaceHorizontalMarginPx = getHorizontalMarginPx(inv, res);
+0 −104
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.responsive

import android.content.res.TypedArray
import com.android.launcher3.R
import com.android.launcher3.responsive.ResponsiveSpec.SpecType
import com.android.launcher3.util.ResourceHelper

class AllAppsSpecs(widthSpecs: List<AllAppsSpec>, heightSpecs: List<AllAppsSpec>) :
    ResponsiveSpecs<AllAppsSpec>(widthSpecs, heightSpecs) {

    fun getCalculatedWidthSpec(
        columns: Int,
        availableWidth: Int,
        calculatedWorkspaceSpec: CalculatedWorkspaceSpec
    ): CalculatedAllAppsSpec {
        check(calculatedWorkspaceSpec.spec.specType == SpecType.WIDTH) {
            "Invalid specType for CalculatedWorkspaceSpec. " +
                "Expected: ${SpecType.WIDTH} - " +
                "Found: ${calculatedWorkspaceSpec.spec.specType}}"
        }

        val spec = getWidthSpec(availableWidth)
        return CalculatedAllAppsSpec(availableWidth, columns, spec, calculatedWorkspaceSpec)
    }

    fun getCalculatedHeightSpec(
        rows: Int,
        availableHeight: Int,
        calculatedWorkspaceSpec: CalculatedWorkspaceSpec
    ): CalculatedAllAppsSpec {
        check(calculatedWorkspaceSpec.spec.specType == SpecType.HEIGHT) {
            "Invalid specType for CalculatedWorkspaceSpec. " +
                "Expected: ${SpecType.HEIGHT} - " +
                "Found: ${calculatedWorkspaceSpec.spec.specType}}"
        }

        val spec = getHeightSpec(availableHeight)
        return CalculatedAllAppsSpec(availableHeight, rows, spec, calculatedWorkspaceSpec)
    }

    companion object {
        private const val XML_ALL_APPS_SPEC = "allAppsSpec"

        @JvmStatic
        fun create(resourceHelper: ResourceHelper): AllAppsSpecs {
            val parser = ResponsiveSpecsParser(resourceHelper)
            val specs = parser.parseXML(XML_ALL_APPS_SPEC, ::AllAppsSpec)
            val (widthSpecs, heightSpecs) = specs.partition { it.specType == SpecType.WIDTH }
            return AllAppsSpecs(widthSpecs, heightSpecs)
        }
    }
}

data class AllAppsSpec(
    override val maxAvailableSize: Int,
    override val specType: SpecType,
    override val startPadding: SizeSpec,
    override val endPadding: SizeSpec,
    override val gutter: SizeSpec,
    override val cellSize: SizeSpec
) : ResponsiveSpec(maxAvailableSize, specType, startPadding, endPadding, gutter, cellSize) {

    init {
        check(isValid()) { "Invalid AllAppsSpec found." }
    }

    constructor(
        attrs: TypedArray,
        specs: Map<String, SizeSpec>
    ) : this(
        maxAvailableSize =
            attrs.getDimensionPixelSize(R.styleable.ResponsiveSpec_maxAvailableSize, 0),
        specType =
            SpecType.values()[
                    attrs.getInt(R.styleable.ResponsiveSpec_specType, SpecType.HEIGHT.ordinal)],
        startPadding = specs.getOrError(SizeSpec.XmlTags.START_PADDING),
        endPadding = specs.getOrError(SizeSpec.XmlTags.END_PADDING),
        gutter = specs.getOrError(SizeSpec.XmlTags.GUTTER),
        cellSize = specs.getOrError(SizeSpec.XmlTags.CELL_SIZE)
    )
}

class CalculatedAllAppsSpec(
    availableSpace: Int,
    cells: Int,
    spec: AllAppsSpec,
    calculatedWorkspaceSpec: CalculatedWorkspaceSpec
) : CalculatedResponsiveSpec(availableSpace, cells, spec, calculatedWorkspaceSpec)
+0 −105
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.responsive

import android.content.res.TypedArray
import com.android.launcher3.R
import com.android.launcher3.responsive.ResponsiveSpec.SpecType
import com.android.launcher3.util.ResourceHelper

class FolderSpecs(widthSpecs: List<FolderSpec>, heightSpecs: List<FolderSpec>) :
    ResponsiveSpecs<FolderSpec>(widthSpecs, heightSpecs) {

    fun getCalculatedWidthSpec(
        columns: Int,
        availableWidth: Int,
        calculatedWorkspaceSpec: CalculatedWorkspaceSpec
    ): CalculatedFolderSpec {
        check(calculatedWorkspaceSpec.spec.specType == SpecType.WIDTH) {
            "Invalid specType for CalculatedWorkspaceSpec. " +
                "Expected: ${SpecType.WIDTH} - " +
                "Found: ${calculatedWorkspaceSpec.spec.specType}}"
        }

        val spec = getWidthSpec(availableWidth)
        return CalculatedFolderSpec(availableWidth, columns, spec, calculatedWorkspaceSpec)
    }

    fun getCalculatedHeightSpec(
        rows: Int,
        availableHeight: Int,
        calculatedWorkspaceSpec: CalculatedWorkspaceSpec
    ): CalculatedFolderSpec {
        check(calculatedWorkspaceSpec.spec.specType == SpecType.HEIGHT) {
            "Invalid specType for CalculatedWorkspaceSpec. " +
                "Expected: ${SpecType.HEIGHT} - " +
                "Found: ${calculatedWorkspaceSpec.spec.specType}}"
        }

        val spec = getHeightSpec(availableHeight)
        return CalculatedFolderSpec(availableHeight, rows, spec, calculatedWorkspaceSpec)
    }

    companion object {

        private const val XML_FOLDER_SPEC = "folderSpec"

        @JvmStatic
        fun create(resourceHelper: ResourceHelper): FolderSpecs {
            val parser = ResponsiveSpecsParser(resourceHelper)
            val specs = parser.parseXML(XML_FOLDER_SPEC, ::FolderSpec)
            val (widthSpecs, heightSpecs) = specs.partition { it.specType == SpecType.WIDTH }
            return FolderSpecs(widthSpecs, heightSpecs)
        }
    }
}

data class FolderSpec(
    override val maxAvailableSize: Int,
    override val specType: SpecType,
    override val startPadding: SizeSpec,
    override val endPadding: SizeSpec,
    override val gutter: SizeSpec,
    override val cellSize: SizeSpec
) : ResponsiveSpec(maxAvailableSize, specType, startPadding, endPadding, gutter, cellSize) {

    init {
        check(isValid()) { "Invalid FolderSpec found." }
    }

    constructor(
        attrs: TypedArray,
        specs: Map<String, SizeSpec>
    ) : this(
        maxAvailableSize =
            attrs.getDimensionPixelSize(R.styleable.ResponsiveSpec_maxAvailableSize, 0),
        specType =
            SpecType.values()[
                    attrs.getInt(R.styleable.ResponsiveSpec_specType, SpecType.HEIGHT.ordinal)],
        startPadding = specs.getOrError(SizeSpec.XmlTags.START_PADDING),
        endPadding = specs.getOrError(SizeSpec.XmlTags.END_PADDING),
        gutter = specs.getOrError(SizeSpec.XmlTags.GUTTER),
        cellSize = specs.getOrError(SizeSpec.XmlTags.CELL_SIZE)
    )
}

class CalculatedFolderSpec(
    availableSpace: Int,
    cells: Int,
    spec: FolderSpec,
    calculatedWorkspaceSpec: CalculatedWorkspaceSpec
) : CalculatedResponsiveSpec(availableSpace, cells, spec, calculatedWorkspaceSpec)
+28 −30
Original line number Diff line number Diff line
@@ -19,67 +19,65 @@ package com.android.launcher3.responsive
import android.content.res.TypedArray
import android.util.Log
import com.android.launcher3.R
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
import com.android.launcher3.util.ResourceHelper

class HotseatSpecs(widthSpecs: List<HotseatSpec>, heightSpecs: List<HotseatSpec>) {
class HotseatSpecsProvider(private val groupOfSpecs: List<ResponsiveSpecGroup<HotseatSpec>>) {
    fun getSpecsByAspectRatio(aspectRatio: Float): ResponsiveSpecGroup<HotseatSpec> {
        check(aspectRatio > 0f) { "Invalid aspect ratio! The value should be bigger than 0." }

    val widthSpecs: List<HotseatSpec>
    val heightSpecs: List<HotseatSpec>
        val specsGroup = groupOfSpecs.firstOrNull { aspectRatio <= it.aspectRatio }
        check(specsGroup != null) { "No available spec with aspectRatio within $aspectRatio." }

    init {
        this.widthSpecs = widthSpecs.sortedBy { it.maxAvailableSize }
        this.heightSpecs = heightSpecs.sortedBy { it.maxAvailableSize }
    }

    fun getCalculatedHeightSpec(availableHeight: Int): CalculatedHotseatSpec {
        val spec = heightSpecs.firstOrNull { availableHeight <= it.maxAvailableSize }
        check(spec != null) { "No available height spec found within $availableHeight." }
        return CalculatedHotseatSpec(availableHeight, spec)
        return specsGroup
    }

    fun getCalculatedWidthSpec(availableWidth: Int): CalculatedHotseatSpec {
        val spec = widthSpecs.firstOrNull { availableWidth <= it.maxAvailableSize }
        check(spec != null) { "No available width spec found within $availableWidth." }
        return CalculatedHotseatSpec(availableWidth, spec)
    fun getCalculatedSpec(
        aspectRatio: Float,
        dimensionType: DimensionType,
        availableSpace: Int
    ): CalculatedHotseatSpec {
        val specsGroup = getSpecsByAspectRatio(aspectRatio)
        val spec = specsGroup.getSpec(dimensionType, availableSpace)
        return CalculatedHotseatSpec(availableSpace, spec)
    }

    companion object {
        private const val XML_HOTSEAT_SPEC = "hotseatSpec"

        @JvmStatic
        fun create(resourceHelper: ResourceHelper): HotseatSpecs {
        fun create(resourceHelper: ResourceHelper): HotseatSpecsProvider {
            val parser = ResponsiveSpecsParser(resourceHelper)
            val specs = parser.parseXML(XML_HOTSEAT_SPEC, ::HotseatSpec)
            val (widthSpecs, heightSpecs) =
                specs.partition { it.specType == ResponsiveSpec.SpecType.WIDTH }
            return HotseatSpecs(widthSpecs, heightSpecs)
            val specs = parser.parseXML(ResponsiveSpecType.Hotseat, ::HotseatSpec)
            return HotseatSpecsProvider(specs)
        }
    }
}

data class HotseatSpec(
    val maxAvailableSize: Int,
    val specType: ResponsiveSpec.SpecType,
    override val maxAvailableSize: Int,
    override val dimensionType: DimensionType,
    override val specType: ResponsiveSpecType,
    val hotseatQsbSpace: SizeSpec,
    val edgePadding: SizeSpec
) {

) : IResponsiveSpec {
    init {
        check(isValid()) { "Invalid HotseatSpec found." }
    }

    constructor(
        responsiveSpecType: ResponsiveSpecType,
        attrs: TypedArray,
        specs: Map<String, SizeSpec>
    ) : this(
        maxAvailableSize =
            attrs.getDimensionPixelSize(R.styleable.ResponsiveSpec_maxAvailableSize, 0),
        specType =
            ResponsiveSpec.SpecType.values()[
        dimensionType =
            DimensionType.entries[
                    attrs.getInt(
                        R.styleable.ResponsiveSpec_specType,
                        ResponsiveSpec.SpecType.HEIGHT.ordinal
                        DimensionType.HEIGHT.ordinal
                    )],
        specType = responsiveSpecType,
        hotseatQsbSpace = specs.getOrError(SizeSpec.XmlTags.HOTSEAT_QSB_SPACE),
        edgePadding = specs.getOrError(SizeSpec.XmlTags.EDGE_PADDING)
    )
Loading