/* * 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 com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType import com.android.launcher3.responsive.ResponsiveSpec.DimensionType import com.android.launcher3.util.ResourceHelper /** * A class to provide responsive grid specs for workspace, folder and all apps. * * This class is responsible for provide width and height [CalculatedResponsiveSpec] to be used for * the correct placement of the workspace, all apps and folders. * * @param type A [ResponsiveSpecType] to indicates the type of the spec. * @param groupOfSpecs Groups of responsive specifications */ class ResponsiveSpecsProvider( val type: ResponsiveSpecType, groupOfSpecs: List> ) { private val groupOfSpecs: List> init { this.groupOfSpecs = groupOfSpecs .onEach { group -> check(group.widthSpecs.isNotEmpty() && group.heightSpecs.isNotEmpty()) { "$LOG_TAG is incomplete - " + "width list size = ${group.widthSpecs.size}; " + "height list size = ${group.heightSpecs.size}." } } .sortedBy { it.aspectRatio } } fun getSpecsByAspectRatio(aspectRatio: Float): ResponsiveSpecGroup { check(aspectRatio > 0f) { "Invalid aspect ratio! The value should be bigger than 0." } val specsGroup = groupOfSpecs.firstOrNull { aspectRatio <= it.aspectRatio } checkNotNull(specsGroup) { "No available spec with aspectRatio within $aspectRatio." } return specsGroup } /** * Retrieves a responsive grid specification that matches the number of [numCells], * * [availableSpace] and [aspectRatio]. * * @param aspectRatio the device width divided by device height (aspect ratio) to filter the * specifications * @param dimensionType the grid axis of the spec width is x axis, height is y axis. * @param numCells number of rows/columns in the grid * @param availableSpace available width to filter the specifications * @return A [CalculatedResponsiveSpec] that matches the parameters provided. */ fun getCalculatedSpec( aspectRatio: Float, dimensionType: DimensionType, numCells: Int, availableSpace: Int, ): CalculatedResponsiveSpec { val specsGroup = getSpecsByAspectRatio(aspectRatio) val spec = specsGroup.getSpec(dimensionType, availableSpace) return CalculatedResponsiveSpec(aspectRatio, availableSpace, numCells, spec) } /** * Retrieves a responsive grid specification that matches the number of [numCells], * * [availableSpace] and [aspectRatio]. This function uses a [CalculatedResponsiveSpec] to * match workspace when its true. * * @param aspectRatio the device width divided by device height (aspect ratio) to filter the * specifications * @param dimensionType the grid axis of the spec width is x axis, height is y axis. * @param numCells number of rows/columns in the grid * @param availableSpace available width to filter the specifications * @param calculatedWorkspaceSpec the calculated workspace specification to use its values as * base when matchWorkspace is true. * @return A [CalculatedResponsiveSpec] that matches the parameters provided. */ fun getCalculatedSpec( aspectRatio: Float, dimensionType: DimensionType, numCells: Int, availableSpace: Int, calculatedWorkspaceSpec: CalculatedResponsiveSpec ): CalculatedResponsiveSpec { check(calculatedWorkspaceSpec.spec.dimensionType == dimensionType) { "Invalid specType for CalculatedWorkspaceSpec. " + "Expected: $dimensionType - " + "Found: ${calculatedWorkspaceSpec.spec.dimensionType}}" } check(calculatedWorkspaceSpec.isResponsiveSpecType(ResponsiveSpecType.Workspace)) { "Invalid specType for CalculatedWorkspaceSpec. " + "Expected: ${ResponsiveSpecType.Workspace} - " + "Found: ${calculatedWorkspaceSpec.spec.specType}}" } val specsGroup = getSpecsByAspectRatio(aspectRatio) val spec = specsGroup.getSpec(dimensionType, availableSpace) return CalculatedResponsiveSpec( aspectRatio, availableSpace, numCells, spec, calculatedWorkspaceSpec ) } companion object { private const val LOG_TAG = "ResponsiveSpecsProvider" @JvmStatic fun create( resourceHelper: ResourceHelper, type: ResponsiveSpecType ): ResponsiveSpecsProvider { val parser = ResponsiveSpecsParser(resourceHelper) val specs = parser.parseXML(type, ::ResponsiveSpec) return ResponsiveSpecsProvider(type, specs) } } }