Loading res/values/attrs.xml +10 −1 Original line number Diff line number Diff line Loading @@ -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" /> Loading @@ -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"> Loading Loading @@ -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" /> Loading src/com/android/launcher3/DeviceProfile.java +17 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -1985,6 +1999,7 @@ public class DeviceProfile { + mAllAppsResponsiveWidthSpec.toString()); writer.println(prefix + "\tmResponsiveFolderHeightSpec:" + mResponsiveFolderHeightSpec); writer.println(prefix + "\tmResponsiveFolderWidthSpec:" + mResponsiveFolderWidthSpec); writer.println(prefix + "\tmResponsiveHotseatSpec:" + mResponsiveHotseatSpec); } } Loading src/com/android/launcher3/InvariantDeviceProfile.java +13 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading Loading @@ -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; Loading @@ -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, Loading src/com/android/launcher3/responsive/HotseatSpecs.kt 0 → 100644 +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}" + ")" } } src/com/android/launcher3/responsive/SizeSpec.kt +9 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
res/values/attrs.xml +10 −1 Original line number Diff line number Diff line Loading @@ -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" /> Loading @@ -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"> Loading Loading @@ -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" /> Loading
src/com/android/launcher3/DeviceProfile.java +17 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -1985,6 +1999,7 @@ public class DeviceProfile { + mAllAppsResponsiveWidthSpec.toString()); writer.println(prefix + "\tmResponsiveFolderHeightSpec:" + mResponsiveFolderHeightSpec); writer.println(prefix + "\tmResponsiveFolderWidthSpec:" + mResponsiveFolderWidthSpec); writer.println(prefix + "\tmResponsiveHotseatSpec:" + mResponsiveHotseatSpec); } } Loading
src/com/android/launcher3/InvariantDeviceProfile.java +13 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading Loading @@ -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; Loading @@ -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, Loading
src/com/android/launcher3/responsive/HotseatSpecs.kt 0 → 100644 +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}" + ")" } }
src/com/android/launcher3/responsive/SizeSpec.kt +9 −0 Original line number Diff line number Diff line Loading @@ -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