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

Commit 19c41f59 authored by Thales Lima's avatar Thales Lima Committed by Android (Google) Code Review
Browse files

Merge "Create specs for hotseat" into udc-qpr-dev

parents 1788bdad f8bfb036
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@
        <attr name="demoModeLayoutId" format="reference" />
        <attr name="isScalable" format="boolean" />
        <attr name="devicePaddingId" format="reference" />

        <!-- File that contains the specs for the workspace.
        Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
        <attr name="workspaceSpecsId" format="reference" />
@@ -210,11 +211,14 @@
        Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
        <attr name="allAppsSpecsId" format="reference" />
        <attr name="allAppsSpecsTwoPanelId" format="reference" />

        <!-- File that contains the specs for the workspace.
        Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
        <attr name="folderSpecsId" format="reference" />
        <attr name="folderSpecsTwoPanelId" format="reference" />
        <!-- File that contains the specs for hotseat bar.
        Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
        <attr name="hotseatSpecsId" format="reference" />
        <attr name="hotseatSpecsTwoPanelId" format="reference" />

        <!-- By default all categories are enabled -->
        <attr name="deviceCategory" format="integer">
@@ -278,6 +282,11 @@
        <attr name="maxAvailableSize" />
    </declare-styleable>

    <declare-styleable name="HotseatSpec">
        <attr name="specType" />
        <attr name="maxAvailableSize" />
    </declare-styleable>

    <declare-styleable name="SizeSpec">
        <attr name="fixedSize" format="dimension" />
        <attr name="ofAvailableSpace" format="float" />
+17 −2
Original line number Diff line number Diff line
@@ -56,8 +56,10 @@ 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.uioverrides.ApiWrapper;
import com.android.launcher3.util.DisplayController;
@@ -121,6 +123,7 @@ public class DeviceProfile {
    private CalculatedAllAppsSpec mAllAppsResponsiveHeightSpec;
    private CalculatedFolderSpec mResponsiveFolderWidthSpec;
    private CalculatedFolderSpec mResponsiveFolderHeightSpec;
    private CalculatedHotseatSpec mResponsiveHotseatSpec;

    /**
     * The maximum amount of left/right workspace padding as a percentage of the screen width.
@@ -316,7 +319,8 @@ public class DeviceProfile {
        // TODO(b/241386436): shouldn't change any launcher behaviour
        mIsResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE
                && inv.allAppsSpecsId != INVALID_RESOURCE_HANDLE
                && inv.folderSpecsId != INVALID_RESOURCE_HANDLE;
                && inv.folderSpecsId != INVALID_RESOURCE_HANDLE
                && inv.hotseatSpecsId != INVALID_RESOURCE_HANDLE;

        mIsScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
        // Determine device posture.
@@ -495,7 +499,17 @@ public class DeviceProfile {

        int hotseatBarBottomSpace = pxFromDp(inv.hotseatBarBottomSpace[mTypeIndex], mMetrics);
        int minQsbMargin = res.getDimensionPixelSize(R.dimen.min_qsb_margin);

        if (mIsResponsiveGrid) {
            HotseatSpecs hotseatSpecs =
                    HotseatSpecs.create(new ResourceHelper(context,
                            isTwoPanels ? inv.hotseatSpecsTwoPanelId : inv.hotseatSpecsId));
            mResponsiveHotseatSpec = hotseatSpecs.getCalculatedHeightSpec(heightPx);
            hotseatQsbSpace = mResponsiveHotseatSpec.getHotseatQsbSpace();
        } else {
            hotseatQsbSpace = pxFromDp(inv.hotseatQsbSpace[mTypeIndex], mMetrics);
        }

        // Have a little space between the inset and the QSB
        if (mInsets.bottom + minQsbMargin > hotseatBarBottomSpace) {
            int availableSpace = hotseatQsbSpace - (mInsets.bottom - hotseatBarBottomSpace);
@@ -1985,6 +1999,7 @@ public class DeviceProfile {
                    + mAllAppsResponsiveWidthSpec.toString());
            writer.println(prefix + "\tmResponsiveFolderHeightSpec:" + mResponsiveFolderHeightSpec);
            writer.println(prefix + "\tmResponsiveFolderWidthSpec:" + mResponsiveFolderWidthSpec);
            writer.println(prefix + "\tmResponsiveHotseatSpec:" + mResponsiveHotseatSpec);
        }
    }

+13 −0
Original line number Diff line number Diff line
@@ -190,6 +190,8 @@ public class InvariantDeviceProfile {
    public int folderSpecsId = INVALID_RESOURCE_HANDLE;
    @XmlRes
    public int folderSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
    public int hotseatSpecsId = INVALID_RESOURCE_HANDLE;
    public int hotseatSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;

    public String dbFile;
    public int defaultLayoutId;
@@ -369,6 +371,8 @@ public class InvariantDeviceProfile {
        allAppsSpecsTwoPanelId = closestProfile.mAllAppsSpecsTwoPanelId;
        folderSpecsId = closestProfile.mFolderSpecsId;
        folderSpecsTwoPanelId = closestProfile.mFolderSpecsTwoPanelId;
        hotseatSpecsId = closestProfile.mHotseatSpecsId;
        hotseatSpecsTwoPanelId = closestProfile.mHotseatSpecsTwoPanelId;
        this.deviceType = deviceType;

        inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
@@ -820,6 +824,8 @@ public class InvariantDeviceProfile {
        private final int mAllAppsSpecsTwoPanelId;
        private final int mFolderSpecsId;
        private final int mFolderSpecsTwoPanelId;
        private final int mHotseatSpecsId;
        private final int mHotseatSpecsTwoPanelId;

        public GridOption(Context context, AttributeSet attrs) {
            TypedArray a = context.obtainStyledAttributes(
@@ -897,6 +903,11 @@ public class InvariantDeviceProfile {
                mFolderSpecsTwoPanelId = a.getResourceId(
                        R.styleable.GridDisplayOption_folderSpecsTwoPanelId,
                        INVALID_RESOURCE_HANDLE);
                mHotseatSpecsId = a.getResourceId(
                        R.styleable.GridDisplayOption_hotseatSpecsId, INVALID_RESOURCE_HANDLE);
                mHotseatSpecsTwoPanelId = a.getResourceId(
                        R.styleable.GridDisplayOption_hotseatSpecsTwoPanelId,
                        INVALID_RESOURCE_HANDLE);
            } else {
                mWorkspaceSpecsId = INVALID_RESOURCE_HANDLE;
                mWorkspaceSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
@@ -904,6 +915,8 @@ public class InvariantDeviceProfile {
                mAllAppsSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
                mFolderSpecsId = INVALID_RESOURCE_HANDLE;
                mFolderSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
                mHotseatSpecsId = INVALID_RESOURCE_HANDLE;
                mHotseatSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
            }

            int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
+122 −0
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 android.util.Log
import com.android.launcher3.R
import com.android.launcher3.util.ResourceHelper

class HotseatSpecs(val specs: List<HotseatSpec>) {

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

    companion object {
        private const val XML_HOTSEAT_SPEC = "hotseatSpec"

        @JvmStatic
        fun create(resourceHelper: ResourceHelper): HotseatSpecs {
            val parser = ResponsiveSpecsParser(resourceHelper)
            val specs = parser.parseXML(XML_HOTSEAT_SPEC, ::HotseatSpec)
            return HotseatSpecs(specs.filter { it.specType == ResponsiveSpec.SpecType.HEIGHT })
        }
    }
}

data class HotseatSpec(
    val maxAvailableSize: Int,
    val specType: ResponsiveSpec.SpecType,
    val hotseatQsbSpace: SizeSpec
) {

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

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

    fun isValid(): Boolean {
        if (maxAvailableSize <= 0) {
            Log.e(LOG_TAG, "${this::class.simpleName}#isValid - maxAvailableSize <= 0")
            return false
        }

        // All specs need to be individually valid
        if (!allSpecsAreValid()) {
            Log.e(LOG_TAG, "${this::class.simpleName}#isValid - !allSpecsAreValid()")
            return false
        }

        return true
    }

    private fun allSpecsAreValid(): Boolean {
        return hotseatQsbSpace.isValid() && hotseatQsbSpace.onlyFixedSize()
    }

    companion object {
        private const val LOG_TAG = "HotseatSpec"
    }
}

class CalculatedHotseatSpec(val availableSpace: Int, val spec: HotseatSpec) {

    var hotseatQsbSpace: Int = 0
        private set

    init {
        hotseatQsbSpace = spec.hotseatQsbSpace.getCalculatedValue(availableSpace)
    }

    override fun hashCode(): Int {
        var result = availableSpace.hashCode()
        result = 31 * result + hotseatQsbSpace.hashCode()
        result = 31 * result + spec.hashCode()
        return result
    }

    override fun equals(other: Any?): Boolean {
        return other is CalculatedHotseatSpec &&
            availableSpace == other.availableSpace &&
            hotseatQsbSpace == other.hotseatQsbSpace &&
            spec == other.spec
    }

    override fun toString(): String {
        return "${this::class.simpleName}(" +
            "availableSpace=$availableSpace, hotseatQsbSpace=$hotseatQsbSpace, " +
            "${spec::class.simpleName}.maxAvailableSize=${spec.maxAvailableSize}" +
            ")"
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -107,11 +107,20 @@ data class SizeSpec(
        return true
    }

    fun onlyFixedSize(): Boolean {
        if (ofAvailableSpace > 0 || ofRemainderSpace > 0 || matchWorkspace) {
            Log.e(TAG, "SizeSpec#onlyFixedSize - only fixed size allowed for this tag")
            return false
        }
        return true
    }

    object XmlTags {
        const val START_PADDING = "startPadding"
        const val END_PADDING = "endPadding"
        const val GUTTER = "gutter"
        const val CELL_SIZE = "cellSize"
        const val HOTSEAT_QSB_SPACE = "hotseatQsbSpace"
    }

    companion object {
Loading