Merge "Add FolderSpec for responsive grid support" into udc-qpr-dev
This commit is contained in:
@@ -259,6 +259,11 @@
|
||||
<attr name="matchWorkspace" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="FolderSpec">
|
||||
<attr name="specType" />
|
||||
<attr name="maxAvailableSize" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="ProfileDisplayOption">
|
||||
<attr name="name" />
|
||||
<attr name="minWidthDps" format="float" />
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
package com.android.launcher3.responsive
|
||||
|
||||
import android.content.res.XmlResourceParser
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.util.Xml
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.responsive.FolderSpec.*
|
||||
import com.android.launcher3.util.ResourceHelper
|
||||
import com.android.launcher3.workspace.CalculatedWorkspaceSpec
|
||||
import com.android.launcher3.workspace.WorkspaceSpec
|
||||
import java.io.IOException
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import org.xmlpull.v1.XmlPullParserException
|
||||
|
||||
private const val LOG_TAG = "FolderSpecs"
|
||||
|
||||
class FolderSpecs(resourceHelper: ResourceHelper) {
|
||||
|
||||
object XmlTags {
|
||||
const val FOLDER_SPECS = "folderSpecs"
|
||||
|
||||
const val FOLDER_SPEC = "folderSpec"
|
||||
const val START_PADDING = "startPadding"
|
||||
const val END_PADDING = "endPadding"
|
||||
const val GUTTER = "gutter"
|
||||
const val CELL_SIZE = "cellSize"
|
||||
}
|
||||
|
||||
private val _heightSpecs = mutableListOf<FolderSpec>()
|
||||
val heightSpecs: List<FolderSpec>
|
||||
get() = _heightSpecs
|
||||
|
||||
private val _widthSpecs = mutableListOf<FolderSpec>()
|
||||
val widthSpecs: List<FolderSpec>
|
||||
get() = _widthSpecs
|
||||
|
||||
// TODO(b/286538013) Remove this init after a more generic or reusable parser is created
|
||||
init {
|
||||
var parser: XmlResourceParser? = null
|
||||
try {
|
||||
parser = resourceHelper.getXml()
|
||||
val depth = parser.depth
|
||||
var type: Int
|
||||
while (
|
||||
(parser.next().also { type = it } != XmlPullParser.END_TAG ||
|
||||
parser.depth > depth) && type != XmlPullParser.END_DOCUMENT
|
||||
) {
|
||||
if (type == XmlPullParser.START_TAG && XmlTags.FOLDER_SPECS == parser.name) {
|
||||
val displayDepth = parser.depth
|
||||
while (
|
||||
(parser.next().also { type = it } != XmlPullParser.END_TAG ||
|
||||
parser.depth > displayDepth) && type != XmlPullParser.END_DOCUMENT
|
||||
) {
|
||||
if (type == XmlPullParser.START_TAG && XmlTags.FOLDER_SPEC == parser.name) {
|
||||
val attrs =
|
||||
resourceHelper.obtainStyledAttributes(
|
||||
Xml.asAttributeSet(parser),
|
||||
R.styleable.FolderSpec
|
||||
)
|
||||
val maxAvailableSize =
|
||||
attrs.getDimensionPixelSize(
|
||||
R.styleable.FolderSpec_maxAvailableSize,
|
||||
0
|
||||
)
|
||||
val specType =
|
||||
SpecType.values()[
|
||||
attrs.getInt(
|
||||
R.styleable.FolderSpec_specType,
|
||||
SpecType.HEIGHT.ordinal
|
||||
)]
|
||||
attrs.recycle()
|
||||
|
||||
var startPadding: SizeSpec? = null
|
||||
var endPadding: SizeSpec? = null
|
||||
var gutter: SizeSpec? = null
|
||||
var cellSize: SizeSpec? = null
|
||||
|
||||
val limitDepth = parser.depth
|
||||
while (
|
||||
(parser.next().also { type = it } != XmlPullParser.END_TAG ||
|
||||
parser.depth > limitDepth) && type != XmlPullParser.END_DOCUMENT
|
||||
) {
|
||||
val attr: AttributeSet = Xml.asAttributeSet(parser)
|
||||
if (type == XmlPullParser.START_TAG) {
|
||||
val sizeSpec = SizeSpec.create(resourceHelper, attr)
|
||||
when (parser.name) {
|
||||
XmlTags.START_PADDING -> startPadding = sizeSpec
|
||||
XmlTags.END_PADDING -> endPadding = sizeSpec
|
||||
XmlTags.GUTTER -> gutter = sizeSpec
|
||||
XmlTags.CELL_SIZE -> cellSize = sizeSpec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkNotNull(startPadding) {
|
||||
"Attr 'startPadding' in FolderSpec must be defined."
|
||||
}
|
||||
checkNotNull(endPadding) {
|
||||
"Attr 'endPadding' in FolderSpec must be defined."
|
||||
}
|
||||
checkNotNull(gutter) { "Attr 'gutter' in FolderSpec must be defined." }
|
||||
checkNotNull(cellSize) {
|
||||
"Attr 'cellSize' in FolderSpec must be defined."
|
||||
}
|
||||
|
||||
val folderSpec =
|
||||
FolderSpec(
|
||||
maxAvailableSize,
|
||||
specType,
|
||||
startPadding,
|
||||
endPadding,
|
||||
gutter,
|
||||
cellSize
|
||||
)
|
||||
|
||||
check(folderSpec.isValid()) { "Invalid FolderSpec found." }
|
||||
|
||||
if (folderSpec.specType == SpecType.HEIGHT) {
|
||||
_heightSpecs += folderSpec
|
||||
} else {
|
||||
_widthSpecs += folderSpec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check(_widthSpecs.isNotEmpty() && _heightSpecs.isNotEmpty()) {
|
||||
"FolderSpecs is incomplete - " +
|
||||
"height list size = ${_heightSpecs.size}; " +
|
||||
"width list size = ${_widthSpecs.size}."
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
when (e) {
|
||||
is IOException,
|
||||
is XmlPullParserException -> {
|
||||
throw RuntimeException("Failure parsing folder specs file.", e)
|
||||
}
|
||||
else -> throw e
|
||||
}
|
||||
} finally {
|
||||
parser?.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [CalculatedFolderSpec] for width, based on the available width, FolderSpecs and
|
||||
* WorkspaceSpecs.
|
||||
*/
|
||||
fun getWidthSpec(
|
||||
columns: Int,
|
||||
availableWidth: Int,
|
||||
workspaceSpec: CalculatedWorkspaceSpec
|
||||
): CalculatedFolderSpec {
|
||||
check(workspaceSpec.workspaceSpec.specType == WorkspaceSpec.SpecType.WIDTH) {
|
||||
"Invalid specType for CalculatedWorkspaceSpec. " +
|
||||
"Expected: ${WorkspaceSpec.SpecType.WIDTH} - " +
|
||||
"Found: ${workspaceSpec.workspaceSpec.specType}}"
|
||||
}
|
||||
|
||||
val widthSpec = _widthSpecs.firstOrNull { availableWidth <= it.maxAvailableSize }
|
||||
check(widthSpec != null) { "No FolderSpec for width spec found with $availableWidth." }
|
||||
|
||||
return convertToCalculatedFolderSpec(widthSpec, availableWidth, columns, workspaceSpec)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [CalculatedFolderSpec] for height, based on the available height, FolderSpecs and
|
||||
* WorkspaceSpecs.
|
||||
*/
|
||||
fun getHeightSpec(
|
||||
rows: Int,
|
||||
availableHeight: Int,
|
||||
workspaceSpec: CalculatedWorkspaceSpec
|
||||
): CalculatedFolderSpec {
|
||||
check(workspaceSpec.workspaceSpec.specType == WorkspaceSpec.SpecType.HEIGHT) {
|
||||
"Invalid specType for CalculatedWorkspaceSpec. " +
|
||||
"Expected: ${WorkspaceSpec.SpecType.HEIGHT} - " +
|
||||
"Found: ${workspaceSpec.workspaceSpec.specType}}"
|
||||
}
|
||||
|
||||
val heightSpec = _heightSpecs.firstOrNull { availableHeight <= it.maxAvailableSize }
|
||||
check(heightSpec != null) { "No FolderSpec for height spec found with $availableHeight." }
|
||||
|
||||
return convertToCalculatedFolderSpec(heightSpec, availableHeight, rows, workspaceSpec)
|
||||
}
|
||||
}
|
||||
|
||||
data class CalculatedFolderSpec(
|
||||
val startPaddingPx: Int,
|
||||
val endPaddingPx: Int,
|
||||
val gutterPx: Int,
|
||||
val cellSizePx: Int,
|
||||
val availableSpace: Int,
|
||||
val cells: Int
|
||||
)
|
||||
|
||||
/**
|
||||
* Responsive folder specs to be used to calculate the paddings, gutter and cell size for folders in
|
||||
* the workspace.
|
||||
*
|
||||
* @param maxAvailableSize indicates the breakpoint to use this specification.
|
||||
* @param specType indicates whether the paddings and gutters will be applied vertically or
|
||||
* horizontally.
|
||||
* @param startPadding padding used at the top or left (right in RTL) in the workspace folder.
|
||||
* @param endPadding padding used at the bottom or right (left in RTL) in the workspace folder.
|
||||
* @param gutter the space between the cells vertically or horizontally depending on the [specType].
|
||||
* @param cellSize height or width of the cell depending on the [specType].
|
||||
*/
|
||||
data class FolderSpec(
|
||||
val maxAvailableSize: Int,
|
||||
val specType: SpecType,
|
||||
val startPadding: SizeSpec,
|
||||
val endPadding: SizeSpec,
|
||||
val gutter: SizeSpec,
|
||||
val cellSize: SizeSpec
|
||||
) {
|
||||
|
||||
enum class SpecType {
|
||||
HEIGHT,
|
||||
WIDTH
|
||||
}
|
||||
|
||||
fun isValid(): Boolean {
|
||||
if (maxAvailableSize <= 0) {
|
||||
Log.e(LOG_TAG, "FolderSpec#isValid - maxAvailableSize <= 0")
|
||||
return false
|
||||
}
|
||||
|
||||
// All specs are valid
|
||||
if (
|
||||
!(startPadding.isValid() &&
|
||||
endPadding.isValid() &&
|
||||
gutter.isValid() &&
|
||||
cellSize.isValid())
|
||||
) {
|
||||
Log.e(LOG_TAG, "FolderSpec#isValid - !allSpecsAreValid()")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper function to convert [FolderSpec] to [CalculatedFolderSpec] */
|
||||
private fun convertToCalculatedFolderSpec(
|
||||
folderSpec: FolderSpec,
|
||||
availableSpace: Int,
|
||||
cells: Int,
|
||||
workspaceSpec: CalculatedWorkspaceSpec
|
||||
): CalculatedFolderSpec {
|
||||
// Map if is fixedSize, ofAvailableSpace or matchWorkspace
|
||||
var startPaddingPx =
|
||||
folderSpec.startPadding.getCalculatedValue(availableSpace, workspaceSpec.startPaddingPx)
|
||||
var endPaddingPx =
|
||||
folderSpec.endPadding.getCalculatedValue(availableSpace, workspaceSpec.endPaddingPx)
|
||||
var gutterPx = folderSpec.gutter.getCalculatedValue(availableSpace, workspaceSpec.gutterPx)
|
||||
var cellSizePx =
|
||||
folderSpec.cellSize.getCalculatedValue(availableSpace, workspaceSpec.cellSizePx)
|
||||
|
||||
// Remainder space
|
||||
val gutters = cells - 1
|
||||
val usedSpace = startPaddingPx + endPaddingPx + (gutterPx * gutters) + (cellSizePx * cells)
|
||||
val remainderSpace = availableSpace - usedSpace
|
||||
|
||||
startPaddingPx = folderSpec.startPadding.getRemainderSpaceValue(remainderSpace, startPaddingPx)
|
||||
endPaddingPx = folderSpec.endPadding.getRemainderSpaceValue(remainderSpace, endPaddingPx)
|
||||
gutterPx = folderSpec.gutter.getRemainderSpaceValue(remainderSpace, gutterPx)
|
||||
cellSizePx = folderSpec.cellSize.getRemainderSpaceValue(remainderSpace, cellSizePx)
|
||||
|
||||
return CalculatedFolderSpec(
|
||||
startPaddingPx = startPaddingPx,
|
||||
endPaddingPx = endPaddingPx,
|
||||
gutterPx = gutterPx,
|
||||
cellSizePx = cellSizePx,
|
||||
availableSpace = availableSpace,
|
||||
cells = cells
|
||||
)
|
||||
}
|
||||
@@ -6,14 +6,45 @@ 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.
|
||||
*/
|
||||
data class SizeSpec(
|
||||
val fixedSize: Float,
|
||||
val ofAvailableSpace: Float,
|
||||
val ofRemainderSpace: Float,
|
||||
val matchWorkspace: Boolean
|
||||
val fixedSize: Float = 0f,
|
||||
val ofAvailableSpace: Float = 0f,
|
||||
val ofRemainderSpace: Float = 0f,
|
||||
val matchWorkspace: Boolean = false
|
||||
) {
|
||||
|
||||
/** Retrieves the correct value for [SizeSpec]. */
|
||||
fun getCalculatedValue(availableSpace: Int, workspaceValue: Int): Int {
|
||||
return when {
|
||||
fixedSize > 0 -> fixedSize.roundToInt()
|
||||
ofAvailableSpace > 0 -> (ofAvailableSpace * availableSpace).roundToInt()
|
||||
matchWorkspace -> workspaceValue
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the [SizeSpec] value when remainder space value is defined. If no remainderSpace
|
||||
* is 0, returns a default value.
|
||||
*/
|
||||
fun getRemainderSpaceValue(remainderSpace: Int, defaultValue: Int): Int {
|
||||
return if (ofRemainderSpace > 0) {
|
||||
(ofRemainderSpace * remainderSpace).roundToInt()
|
||||
} else {
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
fun isValid(): Boolean {
|
||||
// All attributes are empty
|
||||
if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f && !matchWorkspace) {
|
||||
@@ -48,7 +79,8 @@ data class SizeSpec(
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "WorkspaceSpecs::SizeSpec"
|
||||
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()
|
||||
|
||||
@@ -44,6 +44,7 @@ class WorkspaceSpecs(resourceHelper: ResourceHelper) {
|
||||
val workspaceHeightSpecList = mutableListOf<WorkspaceSpec>()
|
||||
val workspaceWidthSpecList = mutableListOf<WorkspaceSpec>()
|
||||
|
||||
// TODO(b/286538013) Remove this init after a more generic or reusable parser is created
|
||||
init {
|
||||
try {
|
||||
val parser: XmlResourceParser = resourceHelper.getXml()
|
||||
|
||||
@@ -32,4 +32,10 @@
|
||||
<attr name="ofRemainderSpace" format="float" />
|
||||
<attr name="matchWorkspace" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="FolderSpec">
|
||||
<attr name="specType" />
|
||||
<attr name="maxAvailableSize" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!-- Tablet - 6x5 portrait -->
|
||||
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
|
||||
<!-- missing startPadding -->
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:matchWorkspace="true" />
|
||||
</folderSpec>
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
|
||||
<startPadding launcher:fixedSize="16dp" />
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:fixedSize="102dp" />
|
||||
</folderSpec>
|
||||
|
||||
<!-- Height spec is fixed -->
|
||||
<folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
|
||||
<startPadding launcher:fixedSize="24dp" />
|
||||
<!-- mapped to footer height size -->
|
||||
<endPadding launcher:fixedSize="64dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:fixedSize="104dp" />
|
||||
</folderSpec>
|
||||
</folderSpecs>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!-- Tablet - 6x5 portrait -->
|
||||
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
|
||||
<startPadding launcher:fixedSize="16dp" />
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<!-- more than 1 value in one tag -->
|
||||
<gutter
|
||||
launcher:ofAvailableSpace="0.0125"
|
||||
launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:matchWorkspace="true" />
|
||||
</folderSpec>
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
|
||||
<startPadding launcher:fixedSize="16dp" />
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:fixedSize="102dp" />
|
||||
</folderSpec>
|
||||
|
||||
<!-- Height spec is fixed -->
|
||||
<folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
|
||||
<startPadding launcher:fixedSize="24dp" />
|
||||
<!-- mapped to footer height size -->
|
||||
<endPadding launcher:fixedSize="64dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:fixedSize="104dp" />
|
||||
</folderSpec>
|
||||
</folderSpecs>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!-- Tablet - 6x5 portrait - More the one value first gutter -->
|
||||
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
|
||||
<startPadding launcher:fixedSize="16dp" />
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<!-- value bigger than 1 -->
|
||||
<cellSize launcher:ofRemainderSpace="1.001" />
|
||||
</folderSpec>
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
|
||||
<startPadding launcher:fixedSize="16dp" />
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:fixedSize="102dp" />
|
||||
</folderSpec>
|
||||
|
||||
<!-- Height spec is fixed -->
|
||||
<folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
|
||||
<startPadding launcher:fixedSize="24dp" />
|
||||
<!-- mapped to footer height size -->
|
||||
<endPadding launcher:fixedSize="64dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:fixedSize="104dp" />
|
||||
</folderSpec>
|
||||
</folderSpecs>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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.
|
||||
-->
|
||||
<!-- missing height spec -->
|
||||
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
|
||||
<startPadding launcher:fixedSize="16dp" />
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:matchWorkspace="true" />
|
||||
</folderSpec>
|
||||
</folderSpecs>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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.
|
||||
-->
|
||||
<!-- missing breakpoints > 800dp -->
|
||||
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
|
||||
<startPadding launcher:fixedSize="16dp" />
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:matchWorkspace="true" />
|
||||
</folderSpec>
|
||||
|
||||
<!-- Height spec is fixed -->
|
||||
<folderSpec launcher:specType="height" launcher:maxAvailableSize="800dp">
|
||||
<startPadding launcher:fixedSize="24dp" />
|
||||
<!-- mapped to footer height size -->
|
||||
<endPadding launcher:fixedSize="64dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:fixedSize="104dp" />
|
||||
</folderSpec>
|
||||
</folderSpecs>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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.
|
||||
-->
|
||||
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
|
||||
<startPadding launcher:fixedSize="16dp" />
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:matchWorkspace="true" />
|
||||
</folderSpec>
|
||||
<folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
|
||||
<startPadding launcher:fixedSize="16dp" />
|
||||
<endPadding launcher:fixedSize="16dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:fixedSize="102dp" />
|
||||
</folderSpec>
|
||||
|
||||
<!-- Height spec is fixed -->
|
||||
<folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
|
||||
<startPadding launcher:fixedSize="24dp" />
|
||||
<!-- mapped to footer height size -->
|
||||
<endPadding launcher:fixedSize="64dp" />
|
||||
<gutter launcher:fixedSize="16dp" />
|
||||
<cellSize launcher:matchWorkspace="true" />
|
||||
</folderSpec>
|
||||
</folderSpecs>
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.Context
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.android.launcher3.AbstractDeviceProfileTest
|
||||
import com.android.launcher3.testing.shared.ResourceUtils
|
||||
import com.android.launcher3.tests.R
|
||||
import com.android.launcher3.util.TestResourceHelper
|
||||
import com.android.launcher3.workspace.WorkspaceSpecs
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class CalculatedFolderSpecsTest : AbstractDeviceProfileTest() {
|
||||
override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
|
||||
|
||||
private val deviceSpec = deviceSpecs["phone"]!!
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
initializeVarsForPhone(deviceSpec)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validate_matchWidthWorkspace() {
|
||||
val columns = 6
|
||||
|
||||
// Loading workspace specs
|
||||
val resourceHelperWorkspace = TestResourceHelper(context!!, R.xml.valid_workspace_file)
|
||||
val workspaceSpecs = WorkspaceSpecs(resourceHelperWorkspace)
|
||||
|
||||
// Loading folders specs
|
||||
val resourceHelperFolder = TestResourceHelper(context!!, R.xml.valid_folders_specs)
|
||||
val folderSpecs = FolderSpecs(resourceHelperFolder)
|
||||
|
||||
assertThat(folderSpecs.widthSpecs.size).isEqualTo(2)
|
||||
assertThat(folderSpecs.widthSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
|
||||
assertThat(folderSpecs.widthSpecs[1].cellSize.matchWorkspace).isEqualTo(false)
|
||||
|
||||
// Validate width spec <= 800
|
||||
var availableWidth = deviceSpec.naturalSize.first
|
||||
var calculatedWorkspace = workspaceSpecs.getCalculatedWidthSpec(columns, availableWidth)
|
||||
var calculatedWidthFolderSpec =
|
||||
folderSpecs.getWidthSpec(columns, availableWidth, calculatedWorkspace)
|
||||
with(calculatedWidthFolderSpec) {
|
||||
assertThat(availableSpace).isEqualTo(availableWidth)
|
||||
assertThat(cells).isEqualTo(columns)
|
||||
assertThat(startPaddingPx).isEqualTo(16.dpToPx())
|
||||
assertThat(endPaddingPx).isEqualTo(16.dpToPx())
|
||||
assertThat(gutterPx).isEqualTo(16.dpToPx())
|
||||
assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
|
||||
}
|
||||
|
||||
// Validate width spec > 800
|
||||
availableWidth = 2000.dpToPx()
|
||||
calculatedWorkspace = workspaceSpecs.getCalculatedWidthSpec(columns, availableWidth)
|
||||
calculatedWidthFolderSpec =
|
||||
folderSpecs.getWidthSpec(columns, availableWidth, calculatedWorkspace)
|
||||
with(calculatedWidthFolderSpec) {
|
||||
assertThat(availableSpace).isEqualTo(availableWidth)
|
||||
assertThat(cells).isEqualTo(columns)
|
||||
assertThat(startPaddingPx).isEqualTo(16.dpToPx())
|
||||
assertThat(endPaddingPx).isEqualTo(16.dpToPx())
|
||||
assertThat(gutterPx).isEqualTo(16.dpToPx())
|
||||
assertThat(cellSizePx).isEqualTo(102.dpToPx())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validate_matchHeightWorkspace() {
|
||||
// Hotseat is roughly 495px on a real device, it doesn't need to be precise on unit tests
|
||||
val hotseatSize = 495
|
||||
val statusBarHeight = deviceSpec.statusBarNaturalPx
|
||||
val availableHeight = deviceSpec.naturalSize.second - statusBarHeight - hotseatSize
|
||||
val rows = 5
|
||||
|
||||
// Loading workspace specs
|
||||
val resourceHelperWorkspace = TestResourceHelper(context!!, R.xml.valid_workspace_file)
|
||||
val workspaceSpecs = WorkspaceSpecs(resourceHelperWorkspace)
|
||||
|
||||
// Loading folders specs
|
||||
val resourceHelperFolder = TestResourceHelper(context!!, R.xml.valid_folders_specs)
|
||||
val folderSpecs = FolderSpecs(resourceHelperFolder)
|
||||
|
||||
assertThat(folderSpecs.heightSpecs.size).isEqualTo(1)
|
||||
assertThat(folderSpecs.heightSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
|
||||
|
||||
// Validate height spec
|
||||
val calculatedWorkspace = workspaceSpecs.getCalculatedHeightSpec(rows, availableHeight)
|
||||
val calculatedFolderSpec =
|
||||
folderSpecs.getHeightSpec(rows, availableHeight, calculatedWorkspace)
|
||||
with(calculatedFolderSpec) {
|
||||
assertThat(availableSpace).isEqualTo(availableHeight)
|
||||
assertThat(cells).isEqualTo(rows)
|
||||
assertThat(startPaddingPx).isEqualTo(24.dpToPx())
|
||||
assertThat(endPaddingPx).isEqualTo(64.dpToPx())
|
||||
assertThat(gutterPx).isEqualTo(16.dpToPx())
|
||||
assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Int.dpToPx(): Int {
|
||||
return ResourceUtils.pxFromDp(this.toFloat(), context!!.resources.displayMetrics)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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.Context
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.android.launcher3.AbstractDeviceProfileTest
|
||||
import com.android.launcher3.testing.shared.ResourceUtils
|
||||
import com.android.launcher3.tests.R
|
||||
import com.android.launcher3.util.TestResourceHelper
|
||||
import com.android.launcher3.workspace.CalculatedWorkspaceSpec
|
||||
import com.android.launcher3.workspace.WorkspaceSpec
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class FolderSpecsTest : AbstractDeviceProfileTest() {
|
||||
override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
initializeVarsForPhone(deviceSpecs["tablet"]!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseValidFile() {
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
|
||||
val folderSpecs = FolderSpecs(resourceHelper)
|
||||
|
||||
val sizeSpec16 = SizeSpec(16f.dpToPx())
|
||||
val widthSpecsExpected =
|
||||
listOf(
|
||||
FolderSpec(
|
||||
maxAvailableSize = 800.dpToPx(),
|
||||
specType = FolderSpec.SpecType.WIDTH,
|
||||
startPadding = sizeSpec16,
|
||||
endPadding = sizeSpec16,
|
||||
gutter = sizeSpec16,
|
||||
cellSize = SizeSpec(matchWorkspace = true)
|
||||
),
|
||||
FolderSpec(
|
||||
maxAvailableSize = 9999.dpToPx(),
|
||||
specType = FolderSpec.SpecType.WIDTH,
|
||||
startPadding = sizeSpec16,
|
||||
endPadding = sizeSpec16,
|
||||
gutter = sizeSpec16,
|
||||
cellSize = SizeSpec(102f.dpToPx())
|
||||
)
|
||||
)
|
||||
|
||||
val heightSpecsExpected =
|
||||
FolderSpec(
|
||||
maxAvailableSize = 9999.dpToPx(),
|
||||
specType = FolderSpec.SpecType.HEIGHT,
|
||||
startPadding = SizeSpec(24f.dpToPx()),
|
||||
endPadding = SizeSpec(64f.dpToPx()),
|
||||
gutter = sizeSpec16,
|
||||
cellSize = SizeSpec(matchWorkspace = true)
|
||||
)
|
||||
|
||||
assertThat(folderSpecs.widthSpecs.size).isEqualTo(widthSpecsExpected.size)
|
||||
assertThat(folderSpecs.widthSpecs[0]).isEqualTo(widthSpecsExpected[0])
|
||||
assertThat(folderSpecs.widthSpecs[1]).isEqualTo(widthSpecsExpected[1])
|
||||
|
||||
assertThat(folderSpecs.heightSpecs.size).isEqualTo(1)
|
||||
assertThat(folderSpecs.heightSpecs[0]).isEqualTo(heightSpecsExpected)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun parseInvalidFile_missingTag_throwsError() {
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_1)
|
||||
FolderSpecs(resourceHelper)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_2)
|
||||
FolderSpecs(resourceHelper)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun parseInvalidFile_valueBiggerThan1_throwsError() {
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_3)
|
||||
FolderSpecs(resourceHelper)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun parseInvalidFile_missingSpecs_throwsError() {
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_4)
|
||||
FolderSpecs(resourceHelper)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun parseInvalidFile_missingWidthBreakpoint_throwsError() {
|
||||
val availableSpace = 900.dpToPx()
|
||||
val cells = 3
|
||||
|
||||
val workspaceSpec =
|
||||
WorkspaceSpec(
|
||||
maxAvailableSize = availableSpace,
|
||||
specType = WorkspaceSpec.SpecType.WIDTH,
|
||||
startPadding = SizeSpec(fixedSize = 10f),
|
||||
endPadding = SizeSpec(fixedSize = 10f),
|
||||
gutter = SizeSpec(fixedSize = 10f),
|
||||
cellSize = SizeSpec(fixedSize = 10f)
|
||||
)
|
||||
val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
|
||||
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_5)
|
||||
val folderSpecs = FolderSpecs(resourceHelper)
|
||||
folderSpecs.getWidthSpec(cells, availableSpace, calculatedWorkspaceSpec)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun parseInvalidFile_missingHeightBreakpoint_throwsError() {
|
||||
val availableSpace = 900.dpToPx()
|
||||
val cells = 3
|
||||
|
||||
val workspaceSpec =
|
||||
WorkspaceSpec(
|
||||
maxAvailableSize = availableSpace,
|
||||
specType = WorkspaceSpec.SpecType.HEIGHT,
|
||||
startPadding = SizeSpec(fixedSize = 10f),
|
||||
endPadding = SizeSpec(fixedSize = 10f),
|
||||
gutter = SizeSpec(fixedSize = 10f),
|
||||
cellSize = SizeSpec(fixedSize = 10f)
|
||||
)
|
||||
val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
|
||||
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_5)
|
||||
val folderSpecs = FolderSpecs(resourceHelper)
|
||||
folderSpecs.getHeightSpec(cells, availableSpace, calculatedWorkspaceSpec)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun retrievesCalculatedWidthSpec() {
|
||||
val availableSpace = 800.dpToPx()
|
||||
val cells = 3
|
||||
|
||||
val workspaceSpec =
|
||||
WorkspaceSpec(
|
||||
maxAvailableSize = availableSpace,
|
||||
specType = WorkspaceSpec.SpecType.WIDTH,
|
||||
startPadding = SizeSpec(fixedSize = 10f),
|
||||
endPadding = SizeSpec(fixedSize = 10f),
|
||||
gutter = SizeSpec(fixedSize = 10f),
|
||||
cellSize = SizeSpec(fixedSize = 10f)
|
||||
)
|
||||
val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
|
||||
|
||||
val expectedResult =
|
||||
CalculatedFolderSpec(
|
||||
startPaddingPx = 16.dpToPx(),
|
||||
endPaddingPx = 16.dpToPx(),
|
||||
gutterPx = 16.dpToPx(),
|
||||
cellSizePx = calculatedWorkspaceSpec.cellSizePx,
|
||||
availableSpace = availableSpace,
|
||||
cells = cells
|
||||
)
|
||||
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
|
||||
val folderSpecs = FolderSpecs(resourceHelper)
|
||||
val calculatedWidthSpec =
|
||||
folderSpecs.getWidthSpec(cells, availableSpace, calculatedWorkspaceSpec)
|
||||
assertThat(calculatedWidthSpec).isEqualTo(expectedResult)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun retrievesCalculatedWidthSpec_invalidCalculatedWorkspaceSpecType_throwsError() {
|
||||
val availableSpace = 10.dpToPx()
|
||||
val cells = 3
|
||||
|
||||
val workspaceSpec =
|
||||
WorkspaceSpec(
|
||||
maxAvailableSize = availableSpace,
|
||||
specType = WorkspaceSpec.SpecType.HEIGHT,
|
||||
startPadding = SizeSpec(fixedSize = 10f),
|
||||
endPadding = SizeSpec(fixedSize = 10f),
|
||||
gutter = SizeSpec(fixedSize = 10f),
|
||||
cellSize = SizeSpec(fixedSize = 10f)
|
||||
)
|
||||
val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
|
||||
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
|
||||
val folderSpecs = FolderSpecs(resourceHelper)
|
||||
folderSpecs.getWidthSpec(cells, availableSpace, calculatedWorkspaceSpec)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun retrievesCalculatedHeightSpec() {
|
||||
val availableSpace = 700.dpToPx()
|
||||
val cells = 3
|
||||
|
||||
val workspaceSpec =
|
||||
WorkspaceSpec(
|
||||
maxAvailableSize = availableSpace,
|
||||
specType = WorkspaceSpec.SpecType.HEIGHT,
|
||||
startPadding = SizeSpec(fixedSize = 10f),
|
||||
endPadding = SizeSpec(fixedSize = 10f),
|
||||
gutter = SizeSpec(fixedSize = 10f),
|
||||
cellSize = SizeSpec(fixedSize = 10f)
|
||||
)
|
||||
val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
|
||||
|
||||
val expectedResult =
|
||||
CalculatedFolderSpec(
|
||||
startPaddingPx = 24.dpToPx(),
|
||||
endPaddingPx = 64.dpToPx(),
|
||||
gutterPx = 16.dpToPx(),
|
||||
cellSizePx = calculatedWorkspaceSpec.cellSizePx,
|
||||
availableSpace = availableSpace,
|
||||
cells = cells
|
||||
)
|
||||
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
|
||||
val folderSpecs = FolderSpecs(resourceHelper)
|
||||
val calculatedHeightSpec =
|
||||
folderSpecs.getHeightSpec(cells, availableSpace, calculatedWorkspaceSpec)
|
||||
assertThat(calculatedHeightSpec).isEqualTo(expectedResult)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun retrievesCalculatedHeightSpec_invalidCalculatedWorkspaceSpecType_throwsError() {
|
||||
val availableSpace = 10.dpToPx()
|
||||
val cells = 3
|
||||
|
||||
val workspaceSpec =
|
||||
WorkspaceSpec(
|
||||
maxAvailableSize = availableSpace,
|
||||
specType = WorkspaceSpec.SpecType.WIDTH,
|
||||
startPadding = SizeSpec(fixedSize = 10f),
|
||||
endPadding = SizeSpec(fixedSize = 10f),
|
||||
gutter = SizeSpec(fixedSize = 10f),
|
||||
cellSize = SizeSpec(fixedSize = 10f)
|
||||
)
|
||||
val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
|
||||
|
||||
val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
|
||||
val folderSpecs = FolderSpecs(resourceHelper)
|
||||
folderSpecs.getHeightSpec(cells, availableSpace, calculatedWorkspaceSpec)
|
||||
}
|
||||
|
||||
private fun Float.dpToPx(): Float {
|
||||
return ResourceUtils.pxFromDp(this, context!!.resources.displayMetrics).toFloat()
|
||||
}
|
||||
|
||||
private fun Int.dpToPx(): Int {
|
||||
return ResourceUtils.pxFromDp(this.toFloat(), context!!.resources.displayMetrics)
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import androidx.test.filters.SmallTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.android.launcher3.AbstractDeviceProfileTest
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlin.math.roundToInt
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -52,6 +53,42 @@ class SizeSpecTest : AbstractDeviceProfileTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validate_getCalculatedValue() {
|
||||
val availableSpace = 100
|
||||
val matchWorkspaceValue = 101
|
||||
val combinations =
|
||||
listOf(
|
||||
SizeSpec(100f) to 100,
|
||||
SizeSpec(ofAvailableSpace = .5f) to (availableSpace * .5f).roundToInt(),
|
||||
SizeSpec(ofRemainderSpace = .5f) to 0,
|
||||
SizeSpec(matchWorkspace = true) to matchWorkspaceValue
|
||||
)
|
||||
|
||||
for ((sizeSpec, expectedValue) in combinations) {
|
||||
val value = sizeSpec.getCalculatedValue(availableSpace, matchWorkspaceValue)
|
||||
assertThat(value).isEqualTo(expectedValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validate_getRemainderSpaceValue() {
|
||||
val remainderSpace = 100
|
||||
val defaultValue = 10
|
||||
val combinations =
|
||||
listOf(
|
||||
SizeSpec(100f) to defaultValue,
|
||||
SizeSpec(ofAvailableSpace = .5f) to defaultValue,
|
||||
SizeSpec(ofRemainderSpace = .5f) to (remainderSpace * .5f).roundToInt(),
|
||||
SizeSpec(matchWorkspace = true) to defaultValue
|
||||
)
|
||||
|
||||
for ((sizeSpec, expectedValue) in combinations) {
|
||||
val value = sizeSpec.getRemainderSpaceValue(remainderSpace, defaultValue)
|
||||
assertThat(value).isEqualTo(expectedValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun multiple_values_assigned() {
|
||||
val combinations =
|
||||
|
||||
@@ -23,12 +23,17 @@ import com.android.launcher3.R
|
||||
import com.android.launcher3.tests.R as TestR
|
||||
import kotlin.IntArray
|
||||
|
||||
class TestResourceHelper(private val context: Context, private val specsFileId: Int) :
|
||||
class TestResourceHelper(private val context: Context, specsFileId: Int) :
|
||||
ResourceHelper(context, specsFileId) {
|
||||
override fun obtainStyledAttributes(attrs: AttributeSet, styleId: IntArray): TypedArray {
|
||||
var clone = styleId.clone()
|
||||
if (styleId == R.styleable.SizeSpec) clone = TestR.styleable.SizeSpec
|
||||
else if (styleId == R.styleable.WorkspaceSpec) clone = TestR.styleable.WorkspaceSpec
|
||||
val clone =
|
||||
when {
|
||||
styleId.contentEquals(R.styleable.SizeSpec) -> TestR.styleable.SizeSpec
|
||||
styleId.contentEquals(R.styleable.WorkspaceSpec) -> TestR.styleable.WorkspaceSpec
|
||||
styleId.contentEquals(R.styleable.FolderSpec) -> TestR.styleable.FolderSpec
|
||||
else -> styleId.clone()
|
||||
}
|
||||
|
||||
return context.obtainStyledAttributes(attrs, clone)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user