mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-19 02:38:20 +00:00
Merge "Create an XML parser for WorkspaceSpecs" into tm-qpr-dev am: 5d5aad3024
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/20643018 Change-Id: I6a3f38e28b5a381bfa2ac42cdeba77c1527fb028 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -19,7 +19,7 @@ import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.launcher3.DeviceProfileBaseTest
|
||||
import com.android.launcher3.FakeInvariantDeviceProfileTest
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
|
||||
import com.android.quickstep.views.TaskView.FullscreenDrawParams
|
||||
@@ -36,7 +36,7 @@ import org.mockito.Mockito.mock
|
||||
/** Test for FullscreenDrawParams class. */
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
|
||||
class FullscreenDrawParamsTest : FakeInvariantDeviceProfileTest() {
|
||||
|
||||
private val TASK_SCALE = 0.7f
|
||||
private var mThumbnailData: ThumbnailData = mock(ThumbnailData::class.java)
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.android.quickstep
|
||||
import android.graphics.Rect
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.launcher3.DeviceProfileBaseTest
|
||||
import com.android.launcher3.FakeInvariantDeviceProfileTest
|
||||
import com.android.launcher3.util.WindowBounds
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
@@ -26,7 +26,7 @@ import org.junit.runner.RunWith
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
|
||||
class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() {
|
||||
|
||||
/**
|
||||
* This is a case when after setting the hotseat, the space needs to be recalculated but it
|
||||
|
||||
@@ -224,6 +224,21 @@
|
||||
<attr name="alignOnIcon" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Responsive grids attributes -->
|
||||
<declare-styleable name="WorkspaceSpec">
|
||||
<attr name="specType" format="integer">
|
||||
<enum name="height" value="0" />
|
||||
<enum name="width" value="1" />
|
||||
</attr>
|
||||
<attr name="maxAvailableSize" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="SpecSize">
|
||||
<attr name="fixedSize" format="dimension" />
|
||||
<attr name="ofAvailableSpace" format="float" />
|
||||
<attr name="ofRemainderSpace" format="float" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="ProfileDisplayOption">
|
||||
<attr name="name" />
|
||||
<attr name="minWidthDps" format="float" />
|
||||
|
||||
37
src/com/android/launcher3/util/ResourceHelper.kt
Normal file
37
src/com/android/launcher3/util/ResourceHelper.kt
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.TypedArray
|
||||
import android.content.res.XmlResourceParser
|
||||
import android.util.AttributeSet
|
||||
import kotlin.IntArray
|
||||
|
||||
/**
|
||||
* This class is a helper that can be subclassed in tests to provide a way to parse attributes
|
||||
* correctly.
|
||||
*/
|
||||
open class ResourceHelper(private val context: Context, private val specsFileId: Int) {
|
||||
open fun getXml(): XmlResourceParser {
|
||||
return context.resources.getXml(specsFileId)
|
||||
}
|
||||
|
||||
open fun obtainStyledAttributes(attrs: AttributeSet, styleId: IntArray): TypedArray {
|
||||
return context.obtainStyledAttributes(attrs, styleId)
|
||||
}
|
||||
}
|
||||
252
src/com/android/launcher3/workspace/WorkspaceSpecs.kt
Normal file
252
src/com/android/launcher3/workspace/WorkspaceSpecs.kt
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* 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.workspace
|
||||
|
||||
import android.content.res.TypedArray
|
||||
import android.content.res.XmlResourceParser
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.util.Xml
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.util.ResourceHelper
|
||||
import java.io.IOException
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import org.xmlpull.v1.XmlPullParserException
|
||||
|
||||
private const val TAG = "WorkspaceSpecs"
|
||||
|
||||
class WorkspaceSpecs(resourceHelper: ResourceHelper) {
|
||||
object XmlTags {
|
||||
const val WORKSPACE_SPECS = "workspaceSpecs"
|
||||
|
||||
const val WORKSPACE_SPEC = "workspaceSpec"
|
||||
const val START_PADDING = "startPadding"
|
||||
const val END_PADDING = "endPadding"
|
||||
const val GUTTER = "gutter"
|
||||
const val CELL_SIZE = "cellSize"
|
||||
}
|
||||
|
||||
val workspaceHeightSpecList = mutableListOf<WorkspaceSpec>()
|
||||
val workspaceWidthSpecList = mutableListOf<WorkspaceSpec>()
|
||||
|
||||
init {
|
||||
try {
|
||||
val parser: XmlResourceParser = 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.WORKSPACE_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.WORKSPACE_SPEC == parser.name
|
||||
) {
|
||||
val attrs =
|
||||
resourceHelper.obtainStyledAttributes(
|
||||
Xml.asAttributeSet(parser),
|
||||
R.styleable.WorkspaceSpec
|
||||
)
|
||||
val maxAvailableSize =
|
||||
attrs.getDimensionPixelSize(
|
||||
R.styleable.WorkspaceSpec_maxAvailableSize,
|
||||
0
|
||||
)
|
||||
val specType =
|
||||
WorkspaceSpec.SpecType.values()[
|
||||
attrs.getInt(
|
||||
R.styleable.WorkspaceSpec_specType,
|
||||
WorkspaceSpec.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) {
|
||||
when (parser.name) {
|
||||
XmlTags.START_PADDING -> {
|
||||
startPadding = SizeSpec(resourceHelper, attr)
|
||||
}
|
||||
XmlTags.END_PADDING -> {
|
||||
endPadding = SizeSpec(resourceHelper, attr)
|
||||
}
|
||||
XmlTags.GUTTER -> {
|
||||
gutter = SizeSpec(resourceHelper, attr)
|
||||
}
|
||||
XmlTags.CELL_SIZE -> {
|
||||
cellSize = SizeSpec(resourceHelper, attr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
startPadding == null ||
|
||||
endPadding == null ||
|
||||
gutter == null ||
|
||||
cellSize == null
|
||||
) {
|
||||
throw IllegalStateException(
|
||||
"All attributes in workspaceSpec must be defined"
|
||||
)
|
||||
}
|
||||
|
||||
val workspaceSpec =
|
||||
WorkspaceSpec(
|
||||
maxAvailableSize,
|
||||
specType,
|
||||
startPadding,
|
||||
endPadding,
|
||||
gutter,
|
||||
cellSize
|
||||
)
|
||||
if (workspaceSpec.isValid()) {
|
||||
if (workspaceSpec.specType == WorkspaceSpec.SpecType.HEIGHT)
|
||||
workspaceHeightSpecList.add(workspaceSpec)
|
||||
else workspaceWidthSpecList.add(workspaceSpec)
|
||||
} else {
|
||||
throw IllegalStateException("Invalid workspaceSpec found.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (workspaceWidthSpecList.isEmpty() || workspaceHeightSpecList.isEmpty()) {
|
||||
throw IllegalStateException(
|
||||
"WorkspaceSpecs is incomplete - " +
|
||||
"height list size = ${workspaceHeightSpecList.size}; " +
|
||||
"width list size = ${workspaceWidthSpecList.size}."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
parser.close()
|
||||
} catch (e: Exception) {
|
||||
when (e) {
|
||||
is IOException,
|
||||
is XmlPullParserException -> {
|
||||
throw RuntimeException("Failure parsing workspaces specs file.", e)
|
||||
}
|
||||
else -> throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class WorkspaceSpec(
|
||||
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(TAG, "WorkspaceSpec#isValid - maxAvailableSize <= 0")
|
||||
return false
|
||||
}
|
||||
|
||||
// All specs need to be individually valid
|
||||
if (!allSpecsAreValid()) {
|
||||
Log.e(TAG, "WorkspaceSpec#isValid - !allSpecsAreValid()")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun allSpecsAreValid(): Boolean =
|
||||
startPadding.isValid() && endPadding.isValid() && gutter.isValid() && cellSize.isValid()
|
||||
}
|
||||
|
||||
class SizeSpec(resourceHelper: ResourceHelper, attrs: AttributeSet) {
|
||||
val fixedSize: Float
|
||||
val ofAvailableSpace: Float
|
||||
val ofRemainderSpace: Float
|
||||
|
||||
init {
|
||||
val styledAttrs = resourceHelper.obtainStyledAttributes(attrs, R.styleable.SpecSize)
|
||||
|
||||
fixedSize = getValue(styledAttrs, R.styleable.SpecSize_fixedSize)
|
||||
ofAvailableSpace = getValue(styledAttrs, R.styleable.SpecSize_ofAvailableSpace)
|
||||
ofRemainderSpace = getValue(styledAttrs, R.styleable.SpecSize_ofRemainderSpace)
|
||||
|
||||
styledAttrs.recycle()
|
||||
}
|
||||
|
||||
private fun getValue(a: TypedArray, index: Int): Float {
|
||||
if (a.getType(index) == TypedValue.TYPE_DIMENSION) {
|
||||
return a.getDimensionPixelSize(index, 0).toFloat()
|
||||
} else if (a.getType(index) == TypedValue.TYPE_FLOAT) {
|
||||
return a.getFloat(index, 0f)
|
||||
}
|
||||
return 0f
|
||||
}
|
||||
|
||||
fun isValid(): Boolean {
|
||||
// All attributes are empty
|
||||
if (fixedSize <= 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) {
|
||||
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 (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
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "SizeSpec(fixedSize=$fixedSize, ofAvailableSpace=$ofAvailableSpace, " +
|
||||
"ofRemainderSpace=$ofRemainderSpace)"
|
||||
}
|
||||
}
|
||||
35
tests/res/values/attrs.xml
Normal file
35
tests/res/values/attrs.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
/* Copyright 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!-- Attributes have to be copied to test for correct parsing of files -->
|
||||
<resources>
|
||||
<!-- Responsive grids attributes -->
|
||||
<declare-styleable name="WorkspaceSpec">
|
||||
<attr name="specType" format="integer">
|
||||
<enum name="height" value="0" />
|
||||
<enum name="width" value="1" />
|
||||
</attr>
|
||||
<attr name="maxAvailableSize" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="SpecSize">
|
||||
<attr name="fixedSize" format="dimension" />
|
||||
<attr name="ofAvailableSpace" format="float" />
|
||||
<attr name="ofRemainderSpace" format="float" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
56
tests/res/xml/invalid_workspace_file_case_1.xml
Normal file
56
tests/res/xml/invalid_workspace_file_case_1.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<workspaceSpec
|
||||
launcher:specType="height"
|
||||
launcher:maxAvailableSize="648dp">
|
||||
<!-- missing startPadding -->
|
||||
<endPadding
|
||||
launcher:ofAvailableSpace="0.05" />
|
||||
<gutter
|
||||
launcher:fixedSize="16dp" />
|
||||
<cellSize
|
||||
launcher:ofRemainderSpace="0.2" />
|
||||
</workspaceSpec>
|
||||
|
||||
<workspaceSpec
|
||||
launcher:specType="height"
|
||||
launcher:maxAvailableSize="9999dp">
|
||||
<startPadding
|
||||
launcher:ofAvailableSpace="0.0306" />
|
||||
<endPadding
|
||||
launcher:ofAvailableSpace="0.068" />
|
||||
<gutter
|
||||
launcher:fixedSize="16dp" />
|
||||
<cellSize
|
||||
launcher:ofRemainderSpace="0.2" />
|
||||
</workspaceSpec>
|
||||
|
||||
<!-- Width spec is always the same -->
|
||||
<workspaceSpec
|
||||
launcher:specType="width"
|
||||
launcher:maxAvailableSize="9999dp">
|
||||
<startPadding
|
||||
launcher:ofRemainderSpace="0.21436227" />
|
||||
<endPadding
|
||||
launcher:ofRemainderSpace="0.21436227" />
|
||||
<gutter
|
||||
launcher:ofRemainderSpace="0.11425509" />
|
||||
<cellSize
|
||||
launcher:fixedSize="120dp" />
|
||||
</workspaceSpec>
|
||||
</workspaceSpecs>
|
||||
59
tests/res/xml/invalid_workspace_file_case_2.xml
Normal file
59
tests/res/xml/invalid_workspace_file_case_2.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<workspaceSpec
|
||||
launcher:specType="height"
|
||||
launcher:maxAvailableSize="648dp">
|
||||
<startPadding
|
||||
launcher:ofAvailableSpace="0.0125" />
|
||||
<endPadding
|
||||
launcher:ofAvailableSpace="0.05" />
|
||||
<!-- more than 1 value in one tag -->
|
||||
<gutter
|
||||
launcher:ofAvailableSpace="0.0125"
|
||||
launcher:fixedSize="16dp" />
|
||||
<cellSize
|
||||
launcher:ofRemainderSpace="0.2" />
|
||||
</workspaceSpec>
|
||||
|
||||
<workspaceSpec
|
||||
launcher:specType="height"
|
||||
launcher:maxAvailableSize="9999dp">
|
||||
<startPadding
|
||||
launcher:ofAvailableSpace="0.0306" />
|
||||
<endPadding
|
||||
launcher:ofAvailableSpace="0.068" />
|
||||
<gutter
|
||||
launcher:fixedSize="16dp" />
|
||||
<cellSize
|
||||
launcher:ofRemainderSpace="0.2" />
|
||||
</workspaceSpec>
|
||||
|
||||
<!-- Width spec is always the same -->
|
||||
<workspaceSpec
|
||||
launcher:specType="width"
|
||||
launcher:maxAvailableSize="9999dp">
|
||||
<startPadding
|
||||
launcher:ofRemainderSpace="0.21436227" />
|
||||
<endPadding
|
||||
launcher:ofRemainderSpace="0.21436227" />
|
||||
<gutter
|
||||
launcher:ofRemainderSpace="0.11425509" />
|
||||
<cellSize
|
||||
launcher:fixedSize="120dp" />
|
||||
</workspaceSpec>
|
||||
</workspaceSpecs>
|
||||
58
tests/res/xml/invalid_workspace_file_case_3.xml
Normal file
58
tests/res/xml/invalid_workspace_file_case_3.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<workspaceSpec
|
||||
launcher:specType="height"
|
||||
launcher:maxAvailableSize="648dp">
|
||||
<startPadding
|
||||
launcher:ofAvailableSpace="0.0125" />
|
||||
<endPadding
|
||||
launcher:ofAvailableSpace="0.05" />
|
||||
<gutter
|
||||
launcher:fixedSize="16dp" />
|
||||
<!-- value bigger than 1 -->
|
||||
<cellSize
|
||||
launcher:ofRemainderSpace="1.001" />
|
||||
</workspaceSpec>
|
||||
|
||||
<workspaceSpec
|
||||
launcher:specType="height"
|
||||
launcher:maxAvailableSize="9999dp">
|
||||
<startPadding
|
||||
launcher:ofAvailableSpace="0.0306" />
|
||||
<endPadding
|
||||
launcher:ofAvailableSpace="0.068" />
|
||||
<gutter
|
||||
launcher:fixedSize="16dp" />
|
||||
<cellSize
|
||||
launcher:ofRemainderSpace="0.2" />
|
||||
</workspaceSpec>
|
||||
|
||||
<!-- Width spec is always the same -->
|
||||
<workspaceSpec
|
||||
launcher:specType="width"
|
||||
launcher:maxAvailableSize="9999dp">
|
||||
<startPadding
|
||||
launcher:ofRemainderSpace="0.21436227" />
|
||||
<endPadding
|
||||
launcher:ofRemainderSpace="0.21436227" />
|
||||
<gutter
|
||||
launcher:ofRemainderSpace="0.11425509" />
|
||||
<cellSize
|
||||
launcher:fixedSize="120dp" />
|
||||
</workspaceSpec>
|
||||
</workspaceSpecs>
|
||||
57
tests/res/xml/valid_workspace_file.xml
Normal file
57
tests/res/xml/valid_workspace_file.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
|
||||
<workspaceSpec
|
||||
launcher:specType="height"
|
||||
launcher:maxAvailableSize="648dp">
|
||||
<startPadding
|
||||
launcher:ofAvailableSpace="0.0125" />
|
||||
<endPadding
|
||||
launcher:ofAvailableSpace="0.05" />
|
||||
<gutter
|
||||
launcher:fixedSize="16dp" />
|
||||
<cellSize
|
||||
launcher:ofRemainderSpace="0.2" />
|
||||
</workspaceSpec>
|
||||
|
||||
<workspaceSpec
|
||||
launcher:specType="height"
|
||||
launcher:maxAvailableSize="9999dp">
|
||||
<startPadding
|
||||
launcher:ofAvailableSpace="0.0306" />
|
||||
<endPadding
|
||||
launcher:ofAvailableSpace="0.068" />
|
||||
<gutter
|
||||
launcher:fixedSize="16dp" />
|
||||
<cellSize
|
||||
launcher:ofRemainderSpace="0.2" />
|
||||
</workspaceSpec>
|
||||
|
||||
<!-- Width spec is always the same -->
|
||||
<workspaceSpec
|
||||
launcher:specType="width"
|
||||
launcher:maxAvailableSize="9999dp">
|
||||
<startPadding
|
||||
launcher:ofRemainderSpace="0.21436227" />
|
||||
<endPadding
|
||||
launcher:ofRemainderSpace="0.21436227" />
|
||||
<gutter
|
||||
launcher:ofRemainderSpace="0.11425509" />
|
||||
<cellSize
|
||||
launcher:fixedSize="120dp" />
|
||||
</workspaceSpec>
|
||||
</workspaceSpecs>
|
||||
272
tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
Normal file
272
tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.Surface
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.android.launcher3.util.DisplayController
|
||||
import com.android.launcher3.util.NavigationMode
|
||||
import com.android.launcher3.util.WindowBounds
|
||||
import com.android.launcher3.util.window.CachedDisplayInfo
|
||||
import com.android.launcher3.util.window.WindowManagerProxy
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
/**
|
||||
* This is an abstract class for DeviceProfile tests that create an InvariantDeviceProfile based on
|
||||
* a real device spec.
|
||||
*
|
||||
* For an implementation that mocks InvariantDeviceProfile, use [FakeInvariantDeviceProfileTest]
|
||||
*/
|
||||
abstract class AbstractDeviceProfileTest {
|
||||
protected var context: Context? = null
|
||||
protected open val runningContext: Context = ApplicationProvider.getApplicationContext()
|
||||
private var displayController: DisplayController = mock(DisplayController::class.java)
|
||||
private var windowManagerProxy: WindowManagerProxy = mock(WindowManagerProxy::class.java)
|
||||
private lateinit var originalDisplayController: DisplayController
|
||||
private lateinit var originalWindowManagerProxy: WindowManagerProxy
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val appContext: Context = ApplicationProvider.getApplicationContext()
|
||||
originalWindowManagerProxy = WindowManagerProxy.INSTANCE.get(appContext)
|
||||
originalDisplayController = DisplayController.INSTANCE.get(appContext)
|
||||
WindowManagerProxy.INSTANCE.initializeForTesting(windowManagerProxy)
|
||||
DisplayController.INSTANCE.initializeForTesting(displayController)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
WindowManagerProxy.INSTANCE.initializeForTesting(originalWindowManagerProxy)
|
||||
DisplayController.INSTANCE.initializeForTesting(originalDisplayController)
|
||||
}
|
||||
|
||||
class DeviceSpec(
|
||||
val naturalSize: Pair<Int, Int>,
|
||||
val densityDpi: Int,
|
||||
val statusBarNaturalPx: Int,
|
||||
val statusBarRotatedPx: Int,
|
||||
val gesturePx: Int,
|
||||
val cutoutPx: Int
|
||||
)
|
||||
|
||||
open val deviceSpecs =
|
||||
mapOf(
|
||||
"phone" to
|
||||
DeviceSpec(
|
||||
Pair(1080, 2400),
|
||||
densityDpi = 420,
|
||||
statusBarNaturalPx = 118,
|
||||
statusBarRotatedPx = 74,
|
||||
gesturePx = 63,
|
||||
cutoutPx = 118
|
||||
),
|
||||
"tablet" to
|
||||
DeviceSpec(
|
||||
Pair(2560, 1600),
|
||||
densityDpi = 320,
|
||||
statusBarNaturalPx = 104,
|
||||
statusBarRotatedPx = 104,
|
||||
gesturePx = 0,
|
||||
cutoutPx = 0
|
||||
),
|
||||
)
|
||||
|
||||
protected fun initializeVarsForPhone(
|
||||
deviceSpec: DeviceSpec,
|
||||
isGestureMode: Boolean = true,
|
||||
isVerticalBar: Boolean = false
|
||||
) {
|
||||
val (naturalX, naturalY) = deviceSpec.naturalSize
|
||||
val windowsBounds = phoneWindowsBounds(deviceSpec, isGestureMode, naturalX, naturalY)
|
||||
val displayInfo =
|
||||
CachedDisplayInfo(Point(naturalX, naturalY), Surface.ROTATION_0, Rect(0, 0, 0, 0))
|
||||
val perDisplayBoundsCache = mapOf(displayInfo to windowsBounds)
|
||||
|
||||
initializeCommonVars(
|
||||
perDisplayBoundsCache,
|
||||
displayInfo,
|
||||
rotation = if (isVerticalBar) Surface.ROTATION_90 else Surface.ROTATION_0,
|
||||
isGestureMode,
|
||||
densityDpi = deviceSpec.densityDpi
|
||||
)
|
||||
}
|
||||
|
||||
protected fun initializeVarsForTablet(
|
||||
deviceSpec: DeviceSpec,
|
||||
isLandscape: Boolean = false,
|
||||
isGestureMode: Boolean = true
|
||||
) {
|
||||
val (naturalX, naturalY) = deviceSpec.naturalSize
|
||||
val windowsBounds = tabletWindowsBounds(deviceSpec, naturalX, naturalY)
|
||||
val displayInfo =
|
||||
CachedDisplayInfo(Point(naturalX, naturalY), Surface.ROTATION_0, Rect(0, 0, 0, 0))
|
||||
val perDisplayBoundsCache = mapOf(displayInfo to windowsBounds)
|
||||
|
||||
initializeCommonVars(
|
||||
perDisplayBoundsCache,
|
||||
displayInfo,
|
||||
rotation = if (isLandscape) Surface.ROTATION_0 else Surface.ROTATION_90,
|
||||
isGestureMode,
|
||||
densityDpi = deviceSpec.densityDpi
|
||||
)
|
||||
}
|
||||
|
||||
protected fun initializeVarsForTwoPanel(
|
||||
deviceTabletSpec: DeviceSpec,
|
||||
deviceSpec: DeviceSpec,
|
||||
isLandscape: Boolean = false,
|
||||
isGestureMode: Boolean = true
|
||||
) {
|
||||
val (tabletNaturalX, tabletNaturalY) = deviceTabletSpec.naturalSize
|
||||
val tabletWindowsBounds =
|
||||
tabletWindowsBounds(deviceTabletSpec, tabletNaturalX, tabletNaturalY)
|
||||
val tabletDisplayInfo =
|
||||
CachedDisplayInfo(
|
||||
Point(tabletNaturalX, tabletNaturalY),
|
||||
Surface.ROTATION_0,
|
||||
Rect(0, 0, 0, 0)
|
||||
)
|
||||
|
||||
val (phoneNaturalX, phoneNaturalY) = deviceSpec.naturalSize
|
||||
val phoneWindowsBounds =
|
||||
phoneWindowsBounds(deviceSpec, isGestureMode, phoneNaturalX, phoneNaturalY)
|
||||
val phoneDisplayInfo =
|
||||
CachedDisplayInfo(
|
||||
Point(phoneNaturalX, phoneNaturalY),
|
||||
Surface.ROTATION_0,
|
||||
Rect(0, 0, 0, 0)
|
||||
)
|
||||
|
||||
val perDisplayBoundsCache =
|
||||
mapOf(tabletDisplayInfo to tabletWindowsBounds, phoneDisplayInfo to phoneWindowsBounds)
|
||||
|
||||
initializeCommonVars(
|
||||
perDisplayBoundsCache,
|
||||
tabletDisplayInfo,
|
||||
rotation = if (isLandscape) Surface.ROTATION_0 else Surface.ROTATION_90,
|
||||
isGestureMode,
|
||||
densityDpi = deviceTabletSpec.densityDpi
|
||||
)
|
||||
}
|
||||
|
||||
private fun phoneWindowsBounds(
|
||||
deviceSpec: DeviceSpec,
|
||||
isGestureMode: Boolean,
|
||||
naturalX: Int,
|
||||
naturalY: Int
|
||||
): Array<WindowBounds> {
|
||||
val buttonsNavHeight = Utilities.dpToPx(48f, deviceSpec.densityDpi)
|
||||
|
||||
val rotation0Insets =
|
||||
Rect(
|
||||
0,
|
||||
max(deviceSpec.statusBarNaturalPx, deviceSpec.cutoutPx),
|
||||
0,
|
||||
if (isGestureMode) deviceSpec.gesturePx else buttonsNavHeight
|
||||
)
|
||||
val rotation90Insets =
|
||||
Rect(
|
||||
deviceSpec.cutoutPx,
|
||||
deviceSpec.statusBarRotatedPx,
|
||||
if (isGestureMode) 0 else buttonsNavHeight,
|
||||
if (isGestureMode) deviceSpec.gesturePx else 0
|
||||
)
|
||||
val rotation180Insets =
|
||||
Rect(
|
||||
0,
|
||||
deviceSpec.statusBarNaturalPx,
|
||||
0,
|
||||
max(
|
||||
if (isGestureMode) deviceSpec.gesturePx else buttonsNavHeight,
|
||||
deviceSpec.cutoutPx
|
||||
)
|
||||
)
|
||||
val rotation270Insets =
|
||||
Rect(
|
||||
if (isGestureMode) 0 else buttonsNavHeight,
|
||||
deviceSpec.statusBarRotatedPx,
|
||||
deviceSpec.cutoutPx,
|
||||
if (isGestureMode) deviceSpec.gesturePx else 0
|
||||
)
|
||||
|
||||
return arrayOf(
|
||||
WindowBounds(Rect(0, 0, naturalX, naturalY), rotation0Insets, Surface.ROTATION_0),
|
||||
WindowBounds(Rect(0, 0, naturalY, naturalX), rotation90Insets, Surface.ROTATION_90),
|
||||
WindowBounds(Rect(0, 0, naturalX, naturalY), rotation180Insets, Surface.ROTATION_180),
|
||||
WindowBounds(Rect(0, 0, naturalY, naturalX), rotation270Insets, Surface.ROTATION_270)
|
||||
)
|
||||
}
|
||||
|
||||
private fun tabletWindowsBounds(
|
||||
deviceSpec: DeviceSpec,
|
||||
naturalX: Int,
|
||||
naturalY: Int
|
||||
): Array<WindowBounds> {
|
||||
val naturalInsets = Rect(0, deviceSpec.statusBarNaturalPx, 0, 0)
|
||||
val rotatedInsets = Rect(0, deviceSpec.statusBarRotatedPx, 0, 0)
|
||||
|
||||
return arrayOf(
|
||||
WindowBounds(Rect(0, 0, naturalX, naturalY), naturalInsets, Surface.ROTATION_0),
|
||||
WindowBounds(Rect(0, 0, naturalY, naturalX), rotatedInsets, Surface.ROTATION_90),
|
||||
WindowBounds(Rect(0, 0, naturalX, naturalY), naturalInsets, Surface.ROTATION_180),
|
||||
WindowBounds(Rect(0, 0, naturalY, naturalX), rotatedInsets, Surface.ROTATION_270)
|
||||
)
|
||||
}
|
||||
|
||||
private fun initializeCommonVars(
|
||||
perDisplayBoundsCache: Map<CachedDisplayInfo, Array<WindowBounds>>,
|
||||
displayInfo: CachedDisplayInfo,
|
||||
rotation: Int,
|
||||
isGestureMode: Boolean = true,
|
||||
densityDpi: Int
|
||||
) {
|
||||
val windowsBounds = perDisplayBoundsCache[displayInfo]!!
|
||||
val realBounds = windowsBounds[rotation]
|
||||
whenever(windowManagerProxy.getDisplayInfo(ArgumentMatchers.any())).thenReturn(displayInfo)
|
||||
whenever(windowManagerProxy.getRealBounds(ArgumentMatchers.any(), ArgumentMatchers.any()))
|
||||
.thenReturn(realBounds)
|
||||
whenever(windowManagerProxy.getRotation(ArgumentMatchers.any())).thenReturn(rotation)
|
||||
whenever(windowManagerProxy.getNavigationMode(ArgumentMatchers.any()))
|
||||
.thenReturn(
|
||||
if (isGestureMode) NavigationMode.NO_BUTTON else NavigationMode.THREE_BUTTONS
|
||||
)
|
||||
|
||||
val density = densityDpi / DisplayMetrics.DENSITY_DEFAULT.toFloat()
|
||||
val config =
|
||||
Configuration(runningContext.resources.configuration).apply {
|
||||
this.densityDpi = densityDpi
|
||||
screenWidthDp = (realBounds.bounds.width() / density).toInt()
|
||||
screenHeightDp = (realBounds.bounds.height() / density).toInt()
|
||||
smallestScreenWidthDp = min(screenWidthDp, screenHeightDp)
|
||||
}
|
||||
context = runningContext.createConfigurationContext(config)
|
||||
|
||||
val info = DisplayController.Info(context, windowManagerProxy, perDisplayBoundsCache)
|
||||
whenever(displayController.info).thenReturn(info)
|
||||
whenever(displayController.isTransientTaskbar).thenReturn(isGestureMode)
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,13 @@ import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
abstract class DeviceProfileBaseTest {
|
||||
/**
|
||||
* This is an abstract class for DeviceProfile tests that don't need the real Context and mock an
|
||||
* InvariantDeviceProfile instead of creating one based on real values.
|
||||
*
|
||||
* For an implementation that creates InvariantDeviceProfile, use [AbstractDeviceProfileTest]
|
||||
*/
|
||||
abstract class FakeInvariantDeviceProfileTest {
|
||||
|
||||
protected var context: Context? = null
|
||||
protected var inv: InvariantDeviceProfile? = null
|
||||
@@ -18,7 +18,7 @@ package com.android.launcher3.nonquickstep
|
||||
import android.graphics.Rect
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.launcher3.DeviceProfileBaseTest
|
||||
import com.android.launcher3.FakeInvariantDeviceProfileTest
|
||||
import com.android.launcher3.util.WindowBounds
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
@@ -26,7 +26,7 @@ import org.junit.runner.RunWith
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
|
||||
class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() {
|
||||
|
||||
/**
|
||||
* This is a case when after setting the hotseat, the space needs to be recalculated but it
|
||||
|
||||
34
tests/src/com/android/launcher3/util/TestResourceHelper.kt
Normal file
34
tests/src/com/android/launcher3/util/TestResourceHelper.kt
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.TypedArray
|
||||
import android.util.AttributeSet
|
||||
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) :
|
||||
ResourceHelper(context, specsFileId) {
|
||||
override fun obtainStyledAttributes(attrs: AttributeSet, styleId: IntArray): TypedArray {
|
||||
var clone = styleId.clone()
|
||||
if (styleId == R.styleable.SpecSize) clone = TestR.styleable.SpecSize
|
||||
else if (styleId == R.styleable.WorkspaceSpec) clone = TestR.styleable.WorkspaceSpec
|
||||
return context.obtainStyledAttributes(attrs, clone)
|
||||
}
|
||||
}
|
||||
120
tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
Normal file
120
tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.workspace
|
||||
|
||||
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.tests.R as TestR
|
||||
import com.android.launcher3.util.TestResourceHelper
|
||||
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 WorkspaceSpecsTest : AbstractDeviceProfileTest() {
|
||||
override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
initializeVarsForPhone(deviceSpecs["phone"]!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseValidFile() {
|
||||
val workspaceSpecs =
|
||||
WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
|
||||
assertThat(workspaceSpecs.workspaceHeightSpecList.size).isEqualTo(2)
|
||||
assertThat(workspaceSpecs.workspaceHeightSpecList[0].toString())
|
||||
.isEqualTo(
|
||||
"WorkspaceSpec(" +
|
||||
"maxAvailableSize=1701, " +
|
||||
"specType=HEIGHT, " +
|
||||
"startPadding=SizeSpec(fixedSize=0.0, " +
|
||||
"ofAvailableSpace=0.0125, " +
|
||||
"ofRemainderSpace=0.0), " +
|
||||
"endPadding=SizeSpec(fixedSize=0.0, " +
|
||||
"ofAvailableSpace=0.05, " +
|
||||
"ofRemainderSpace=0.0), " +
|
||||
"gutter=SizeSpec(fixedSize=42.0, " +
|
||||
"ofAvailableSpace=0.0, " +
|
||||
"ofRemainderSpace=0.0), " +
|
||||
"cellSize=SizeSpec(fixedSize=0.0, " +
|
||||
"ofAvailableSpace=0.0, " +
|
||||
"ofRemainderSpace=0.2)" +
|
||||
")"
|
||||
)
|
||||
assertThat(workspaceSpecs.workspaceHeightSpecList[1].toString())
|
||||
.isEqualTo(
|
||||
"WorkspaceSpec(" +
|
||||
"maxAvailableSize=26247, " +
|
||||
"specType=HEIGHT, " +
|
||||
"startPadding=SizeSpec(fixedSize=0.0, " +
|
||||
"ofAvailableSpace=0.0306, " +
|
||||
"ofRemainderSpace=0.0), " +
|
||||
"endPadding=SizeSpec(fixedSize=0.0, " +
|
||||
"ofAvailableSpace=0.068, " +
|
||||
"ofRemainderSpace=0.0), " +
|
||||
"gutter=SizeSpec(fixedSize=42.0, " +
|
||||
"ofAvailableSpace=0.0, " +
|
||||
"ofRemainderSpace=0.0), " +
|
||||
"cellSize=SizeSpec(fixedSize=0.0, " +
|
||||
"ofAvailableSpace=0.0, " +
|
||||
"ofRemainderSpace=0.2)" +
|
||||
")"
|
||||
)
|
||||
assertThat(workspaceSpecs.workspaceWidthSpecList.size).isEqualTo(1)
|
||||
assertThat(workspaceSpecs.workspaceWidthSpecList[0].toString())
|
||||
.isEqualTo(
|
||||
"WorkspaceSpec(" +
|
||||
"maxAvailableSize=26247, " +
|
||||
"specType=WIDTH, " +
|
||||
"startPadding=SizeSpec(fixedSize=0.0, " +
|
||||
"ofAvailableSpace=0.0, " +
|
||||
"ofRemainderSpace=0.21436226), " +
|
||||
"endPadding=SizeSpec(fixedSize=0.0, " +
|
||||
"ofAvailableSpace=0.0, " +
|
||||
"ofRemainderSpace=0.21436226), " +
|
||||
"gutter=SizeSpec(fixedSize=0.0, " +
|
||||
"ofAvailableSpace=0.0, " +
|
||||
"ofRemainderSpace=0.11425509), " +
|
||||
"cellSize=SizeSpec(fixedSize=315.0, " +
|
||||
"ofAvailableSpace=0.0, " +
|
||||
"ofRemainderSpace=0.0)" +
|
||||
")"
|
||||
)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun parseInvalidFile_missingTag_throwsError() {
|
||||
WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_1))
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
|
||||
WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_2))
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun parseInvalidFile_valueBiggerThan1_throwsError() {
|
||||
WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_3))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user