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

Commit f2402e25 authored by Jordan Silva's avatar Jordan Silva
Browse files

Refactoring Responsive Grid XML specs for more flexibility

It merges portrait and landscape XML specs for responsive grid. This update allows the responsive grid to rely on other properties like aspect ratio and not solely the orientation from resource qualifiers.

Bug: 299889733
Flag: ACONFIG com.android.launcher3.enable_responsive_workspace TEAMFOOD
Test: CalculatedAllAppsSpecTest
Test: CalculatedFolderSpecTest
Test: CalculatedHotseatSpecTest
Test: CalculatedWorkspaceSpecTest
Test: AllAppsSpecsTest
Test: FolderSpecTest
Test: HotseatSpecsTest
Test: WorkspaceSpecsTest
Change-Id: I39ee54d49c9d2a54fcbe91c8a1327a21a8126032
parent 0ddc9843
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