1 /* <lambda>null2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3.responsive 18 19 import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType 20 import com.android.launcher3.responsive.ResponsiveSpec.DimensionType 21 import com.android.launcher3.util.ResourceHelper 22 23 /** 24 * A class to provide responsive grid specs for workspace, folder and all apps. 25 * 26 * This class is responsible for provide width and height [CalculatedResponsiveSpec] to be used for 27 * the correct placement of the workspace, all apps and folders. 28 * 29 * @param type A [ResponsiveSpecType] to indicates the type of the spec. 30 * @param groupOfSpecs Groups of responsive specifications 31 */ 32 class ResponsiveSpecsProvider( 33 val type: ResponsiveSpecType, 34 groupOfSpecs: List<ResponsiveSpecGroup<ResponsiveSpec>> 35 ) { 36 private val groupOfSpecs: List<ResponsiveSpecGroup<ResponsiveSpec>> 37 38 init { 39 this.groupOfSpecs = 40 groupOfSpecs 41 .onEach { group -> 42 check(group.widthSpecs.isNotEmpty() && group.heightSpecs.isNotEmpty()) { 43 "$LOG_TAG is incomplete - " + 44 "width list size = ${group.widthSpecs.size}; " + 45 "height list size = ${group.heightSpecs.size}." 46 } 47 } 48 .sortedBy { it.aspectRatio } 49 } 50 51 fun getSpecsByAspectRatio(aspectRatio: Float): ResponsiveSpecGroup<ResponsiveSpec> { 52 check(aspectRatio > 0f) { "Invalid aspect ratio! The value should be bigger than 0." } 53 54 val specsGroup = groupOfSpecs.firstOrNull { aspectRatio <= it.aspectRatio } 55 checkNotNull(specsGroup) { "No available spec with aspectRatio within $aspectRatio." } 56 57 return specsGroup 58 } 59 60 /** 61 * Retrieves a responsive grid specification that matches the number of [numCells], 62 * * [availableSpace] and [aspectRatio]. 63 * 64 * @param aspectRatio the device width divided by device height (aspect ratio) to filter the 65 * specifications 66 * @param dimensionType the grid axis of the spec width is x axis, height is y axis. 67 * @param numCells number of rows/columns in the grid 68 * @param availableSpace available width to filter the specifications 69 * @return A [CalculatedResponsiveSpec] that matches the parameters provided. 70 */ 71 fun getCalculatedSpec( 72 aspectRatio: Float, 73 dimensionType: DimensionType, 74 numCells: Int, 75 availableSpace: Int, 76 ): CalculatedResponsiveSpec { 77 val specsGroup = getSpecsByAspectRatio(aspectRatio) 78 val spec = specsGroup.getSpec(dimensionType, availableSpace) 79 return CalculatedResponsiveSpec(aspectRatio, availableSpace, numCells, spec) 80 } 81 82 /** 83 * Retrieves a responsive grid specification that matches the number of [numCells], 84 * * [availableSpace] and [aspectRatio]. This function uses a [CalculatedResponsiveSpec] to 85 * match workspace when its true. 86 * 87 * @param aspectRatio the device width divided by device height (aspect ratio) to filter the 88 * specifications 89 * @param dimensionType the grid axis of the spec width is x axis, height is y axis. 90 * @param numCells number of rows/columns in the grid 91 * @param availableSpace available width to filter the specifications 92 * @param calculatedWorkspaceSpec the calculated workspace specification to use its values as 93 * base when matchWorkspace is true. 94 * @return A [CalculatedResponsiveSpec] that matches the parameters provided. 95 */ 96 fun getCalculatedSpec( 97 aspectRatio: Float, 98 dimensionType: DimensionType, 99 numCells: Int, 100 availableSpace: Int, 101 calculatedWorkspaceSpec: CalculatedResponsiveSpec 102 ): CalculatedResponsiveSpec { 103 check(calculatedWorkspaceSpec.spec.dimensionType == dimensionType) { 104 "Invalid specType for CalculatedWorkspaceSpec. " + 105 "Expected: $dimensionType - " + 106 "Found: ${calculatedWorkspaceSpec.spec.dimensionType}}" 107 } 108 109 check(calculatedWorkspaceSpec.isResponsiveSpecType(ResponsiveSpecType.Workspace)) { 110 "Invalid specType for CalculatedWorkspaceSpec. " + 111 "Expected: ${ResponsiveSpecType.Workspace} - " + 112 "Found: ${calculatedWorkspaceSpec.spec.specType}}" 113 } 114 115 val specsGroup = getSpecsByAspectRatio(aspectRatio) 116 val spec = specsGroup.getSpec(dimensionType, availableSpace) 117 return CalculatedResponsiveSpec( 118 aspectRatio, 119 availableSpace, 120 numCells, 121 spec, 122 calculatedWorkspaceSpec 123 ) 124 } 125 126 companion object { 127 private const val LOG_TAG = "ResponsiveSpecsProvider" 128 @JvmStatic 129 fun create( 130 resourceHelper: ResourceHelper, 131 type: ResponsiveSpecType 132 ): ResponsiveSpecsProvider { 133 val parser = ResponsiveSpecsParser(resourceHelper) 134 val specs = parser.parseXML(type, ::ResponsiveSpec) 135 return ResponsiveSpecsProvider(type, specs) 136 } 137 } 138 } 139