mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-27 15:26:58 +00:00
Refactoring the cellSize spec of responsive grid to divide the remainder space in code instead of dividing by cols/rows in the spec definition. For example, instead of using 0.2 in the spec for 5x5 grid (1 / number of rows), it is going to use 1 (100% of the remainder space) and divide the percentage by the number of cols or rows in code. Fix: 313621277 Flag: ACONFIG com.android.launcher3.enable_responsive_workspace TEAMFOOD Test: NexusLauncherImageTests Test: CalculatedWorkspaceSpecTest Test: DeviceProfileDumpTest Test: DeviceProfileAlternativeDisplaysDumpTest Change-Id: Ifaec838ac9751562ecedc1fe39b966ee3d092de3
162 lines
6.1 KiB
Kotlin
162 lines
6.1 KiB
Kotlin
/*
|
|
* 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.AttributeSet
|
|
import android.util.Log
|
|
import android.util.TypedValue
|
|
import com.android.launcher3.R
|
|
import com.android.launcher3.util.ResourceHelper
|
|
import kotlin.math.roundToInt
|
|
|
|
/**
|
|
* [SizeSpec] is an attribute used to represent a property in the responsive grid specs.
|
|
*
|
|
* @param fixedSize a fixed size in dp to be used
|
|
* @param ofAvailableSpace a percentage of the available space
|
|
* @param ofRemainderSpace a percentage of the remaining space (available space minus used space)
|
|
* @param matchWorkspace indicates whether the workspace value will be used or not.
|
|
* @param maxSize restricts the maximum value allowed for the [SizeSpec].
|
|
*/
|
|
data class SizeSpec(
|
|
val fixedSize: Float = 0f,
|
|
val ofAvailableSpace: Float = 0f,
|
|
val ofRemainderSpace: Float = 0f,
|
|
val matchWorkspace: Boolean = false,
|
|
val maxSize: Int = Int.MAX_VALUE
|
|
) {
|
|
|
|
/** Retrieves the correct value for [SizeSpec]. */
|
|
fun getCalculatedValue(availableSpace: Int, workspaceValue: Int = 0): Int {
|
|
val calculatedValue =
|
|
when {
|
|
fixedSize > 0 -> fixedSize.roundToInt()
|
|
matchWorkspace -> workspaceValue
|
|
ofAvailableSpace > 0 -> (ofAvailableSpace * availableSpace).roundToInt()
|
|
else -> 0
|
|
}
|
|
|
|
return calculatedValue.coerceAtMost(maxSize)
|
|
}
|
|
|
|
/**
|
|
* Calculates the [SizeSpec] value when remainder space value is defined. If no remainderSpace
|
|
* is 0, returns a default value.
|
|
*
|
|
* @param remainderSpace The remainder space to be used for the calculation
|
|
* @param defaultValue The default value to be returned when no ofRemainderSpace is defined
|
|
* @param factor A number to divide the remainder space. The default value is 1. This property
|
|
* is used to split equally the remainder space by the number of cells and gutters.
|
|
*/
|
|
fun getRemainderSpaceValue(remainderSpace: Int, defaultValue: Int, factor: Int = 1): Int {
|
|
val remainderSpaceValue =
|
|
if (ofRemainderSpace > 0) {
|
|
(ofRemainderSpace * remainderSpace / factor).roundToInt()
|
|
} else {
|
|
defaultValue
|
|
}
|
|
|
|
return remainderSpaceValue.coerceAtMost(maxSize)
|
|
}
|
|
|
|
fun isValid(): Boolean {
|
|
// All attributes are empty
|
|
if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f && !matchWorkspace) {
|
|
Log.e(TAG, "SizeSpec#isValid - all attributes are empty")
|
|
return false
|
|
}
|
|
|
|
// More than one attribute is filled
|
|
val attrCount =
|
|
(if (fixedSize > 0) 1 else 0) +
|
|
(if (ofAvailableSpace > 0) 1 else 0) +
|
|
(if (ofRemainderSpace > 0) 1 else 0) +
|
|
(if (matchWorkspace) 1 else 0)
|
|
if (attrCount > 1) {
|
|
Log.e(TAG, "SizeSpec#isValid - more than one attribute is filled")
|
|
return false
|
|
}
|
|
|
|
// Values should be between 0 and 1
|
|
if (ofAvailableSpace !in 0f..1f || ofRemainderSpace !in 0f..1f) {
|
|
Log.e(TAG, "SizeSpec#isValid - values should be between 0 and 1")
|
|
return false
|
|
}
|
|
|
|
// Invalid fixed or max size
|
|
if (fixedSize < 0f || maxSize < 0f) {
|
|
Log.e(TAG, "SizeSpec#isValid - values should be bigger or equal to zero.")
|
|
return false
|
|
}
|
|
|
|
if (fixedSize > 0f && fixedSize > maxSize) {
|
|
Log.e(TAG, "SizeSpec#isValid - fixed size should be smaller than the max size.")
|
|
return false
|
|
}
|
|
|
|
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"
|
|
const val EDGE_PADDING = "edgePadding"
|
|
const val ICON_SIZE = "iconSize"
|
|
const val ICON_TEXT_SIZE = "iconTextSize"
|
|
const val ICON_DRAWABLE_PADDING = "iconDrawablePadding"
|
|
}
|
|
|
|
companion object {
|
|
private const val TAG = "SizeSpec"
|
|
|
|
private fun getValue(a: TypedArray, index: Int): Float {
|
|
return when (a.getType(index)) {
|
|
TypedValue.TYPE_DIMENSION -> a.getDimensionPixelSize(index, 0).toFloat()
|
|
TypedValue.TYPE_FLOAT -> a.getFloat(index, 0f)
|
|
else -> 0f
|
|
}
|
|
}
|
|
|
|
fun create(resourceHelper: ResourceHelper, attrs: AttributeSet): SizeSpec {
|
|
val styledAttrs = resourceHelper.obtainStyledAttributes(attrs, R.styleable.SizeSpec)
|
|
|
|
val fixedSize = getValue(styledAttrs, R.styleable.SizeSpec_fixedSize)
|
|
val ofAvailableSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofAvailableSpace)
|
|
val ofRemainderSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofRemainderSpace)
|
|
val matchWorkspace = styledAttrs.getBoolean(R.styleable.SizeSpec_matchWorkspace, false)
|
|
val maxSize =
|
|
styledAttrs.getDimensionPixelSize(R.styleable.SizeSpec_maxSize, Int.MAX_VALUE)
|
|
|
|
styledAttrs.recycle()
|
|
|
|
return SizeSpec(fixedSize, ofAvailableSpace, ofRemainderSpace, matchWorkspace, maxSize)
|
|
}
|
|
}
|
|
}
|