• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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 android.content.res.TypedArray
20 import android.util.AttributeSet
21 import android.util.Log
22 import android.util.TypedValue
23 import com.android.launcher3.R
24 import com.android.launcher3.util.ResourceHelper
25 import kotlin.math.roundToInt
26 
27 /**
28  * [SizeSpec] is an attribute used to represent a property in the responsive grid specs.
29  *
30  * @param fixedSize a fixed size in dp to be used
31  * @param ofAvailableSpace a percentage of the available space
32  * @param ofRemainderSpace a percentage of the remaining space (available space minus used space)
33  * @param matchWorkspace indicates whether the workspace value will be used or not.
34  * @param maxSize restricts the maximum value allowed for the [SizeSpec].
35  */
36 data class SizeSpec(
37     val fixedSize: Float = 0f,
38     val ofAvailableSpace: Float = 0f,
39     val ofRemainderSpace: Float = 0f,
40     val matchWorkspace: Boolean = false,
41     val maxSize: Int = Int.MAX_VALUE
42 ) {
43 
44     /** Retrieves the correct value for [SizeSpec]. */
getCalculatedValuenull45     fun getCalculatedValue(availableSpace: Int, workspaceValue: Int = 0): Int {
46         val calculatedValue =
47             when {
48                 fixedSize > 0 -> fixedSize.roundToInt()
49                 matchWorkspace -> workspaceValue
50                 ofAvailableSpace > 0 -> (ofAvailableSpace * availableSpace).roundToInt()
51                 else -> 0
52             }
53 
54         return calculatedValue.coerceAtMost(maxSize)
55     }
56 
57     /**
58      * Calculates the [SizeSpec] value when remainder space value is defined. If no remainderSpace
59      * is 0, returns a default value.
60      */
getRemainderSpaceValuenull61     fun getRemainderSpaceValue(remainderSpace: Int, defaultValue: Int): Int {
62         val remainderSpaceValue =
63             if (ofRemainderSpace > 0) {
64                 (ofRemainderSpace * remainderSpace).roundToInt()
65             } else {
66                 defaultValue
67             }
68 
69         return remainderSpaceValue.coerceAtMost(maxSize)
70     }
71 
isValidnull72     fun isValid(): Boolean {
73         // All attributes are empty
74         if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f && !matchWorkspace) {
75             Log.e(TAG, "SizeSpec#isValid - all attributes are empty")
76             return false
77         }
78 
79         // More than one attribute is filled
80         val attrCount =
81             (if (fixedSize > 0) 1 else 0) +
82                 (if (ofAvailableSpace > 0) 1 else 0) +
83                 (if (ofRemainderSpace > 0) 1 else 0) +
84                 (if (matchWorkspace) 1 else 0)
85         if (attrCount > 1) {
86             Log.e(TAG, "SizeSpec#isValid - more than one attribute is filled")
87             return false
88         }
89 
90         // Values should be between 0 and 1
91         if (ofAvailableSpace !in 0f..1f || ofRemainderSpace !in 0f..1f) {
92             Log.e(TAG, "SizeSpec#isValid - values should be between 0 and 1")
93             return false
94         }
95 
96         // Invalid fixed or max size
97         if (fixedSize < 0f || maxSize < 0f) {
98             Log.e(TAG, "SizeSpec#isValid - values should be bigger or equal to zero.")
99             return false
100         }
101 
102         if (fixedSize > 0f && fixedSize > maxSize) {
103             Log.e(TAG, "SizeSpec#isValid - fixed size should be smaller than the max size.")
104             return false
105         }
106 
107         return true
108     }
109 
onlyFixedSizenull110     fun onlyFixedSize(): Boolean {
111         if (ofAvailableSpace > 0 || ofRemainderSpace > 0 || matchWorkspace) {
112             Log.e(TAG, "SizeSpec#onlyFixedSize - only fixed size allowed for this tag")
113             return false
114         }
115         return true
116     }
117 
118     object XmlTags {
119         const val START_PADDING = "startPadding"
120         const val END_PADDING = "endPadding"
121         const val GUTTER = "gutter"
122         const val CELL_SIZE = "cellSize"
123         const val HOTSEAT_QSB_SPACE = "hotseatQsbSpace"
124     }
125 
126     companion object {
127         private const val TAG = "SizeSpec"
128 
getValuenull129         private fun getValue(a: TypedArray, index: Int): Float {
130             return when (a.getType(index)) {
131                 TypedValue.TYPE_DIMENSION -> a.getDimensionPixelSize(index, 0).toFloat()
132                 TypedValue.TYPE_FLOAT -> a.getFloat(index, 0f)
133                 else -> 0f
134             }
135         }
136 
createnull137         fun create(resourceHelper: ResourceHelper, attrs: AttributeSet): SizeSpec {
138             val styledAttrs = resourceHelper.obtainStyledAttributes(attrs, R.styleable.SizeSpec)
139 
140             val fixedSize = getValue(styledAttrs, R.styleable.SizeSpec_fixedSize)
141             val ofAvailableSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofAvailableSpace)
142             val ofRemainderSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofRemainderSpace)
143             val matchWorkspace = styledAttrs.getBoolean(R.styleable.SizeSpec_matchWorkspace, false)
144             val maxSize =
145                 styledAttrs.getDimensionPixelSize(R.styleable.SizeSpec_maxSize, Int.MAX_VALUE)
146 
147             styledAttrs.recycle()
148 
149             return SizeSpec(fixedSize, ofAvailableSpace, ofRemainderSpace, matchWorkspace, maxSize)
150         }
151     }
152 }
153