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.Context
20 import androidx.test.ext.junit.runners.AndroidJUnit4
21 import androidx.test.filters.SmallTest
22 import androidx.test.platform.app.InstrumentationRegistry
23 import com.android.launcher3.AbstractDeviceProfileTest
24 import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
25 import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
26 import com.android.launcher3.util.TestResourceHelper
27 import com.google.common.truth.Truth.assertThat
28 import org.junit.Before
29 import org.junit.Test
30 import org.junit.runner.RunWith
31 
32 @SmallTest
33 @RunWith(AndroidJUnit4::class)
34 class FolderSpecTest : AbstractDeviceProfileTest() {
35     override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
36     val deviceSpec = deviceSpecs["tablet"]!!
37     val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
38 
39     @Before
setupnull40     fun setup() {
41         initializeVarsForPhone(deviceSpec)
42     }
43 
44     @Test
parseValidFilenull45     fun parseValidFile() {
46         val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
47         val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
48         val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
49 
50         val sizeSpec16 = SizeSpec(16f.dpToPx())
51         val widthSpecsExpected =
52             listOf(
53                 ResponsiveSpec(
54                     maxAvailableSize = 800.dpToPx(),
55                     dimensionType = DimensionType.WIDTH,
56                     specType = ResponsiveSpecType.Folder,
57                     startPadding = sizeSpec16,
58                     endPadding = sizeSpec16,
59                     gutter = sizeSpec16,
60                     cellSize = SizeSpec(matchWorkspace = true)
61                 ),
62                 ResponsiveSpec(
63                     maxAvailableSize = 9999.dpToPx(),
64                     dimensionType = DimensionType.WIDTH,
65                     specType = ResponsiveSpecType.Folder,
66                     startPadding = sizeSpec16,
67                     endPadding = sizeSpec16,
68                     gutter = sizeSpec16,
69                     cellSize = SizeSpec(102f.dpToPx())
70                 )
71             )
72 
73         val heightSpecsExpected =
74             ResponsiveSpec(
75                 maxAvailableSize = 9999.dpToPx(),
76                 dimensionType = DimensionType.HEIGHT,
77                 specType = ResponsiveSpecType.Folder,
78                 startPadding = SizeSpec(24f.dpToPx()),
79                 endPadding = SizeSpec(64f.dpToPx()),
80                 gutter = sizeSpec16,
81                 cellSize = SizeSpec(matchWorkspace = true)
82             )
83 
84         assertThat(specs.widthSpecs.size).isEqualTo(widthSpecsExpected.size)
85         assertThat(specs.widthSpecs[0]).isEqualTo(widthSpecsExpected[0])
86         assertThat(specs.widthSpecs[1]).isEqualTo(widthSpecsExpected[1])
87 
88         assertThat(specs.heightSpecs.size).isEqualTo(1)
89         assertThat(specs.heightSpecs[0]).isEqualTo(heightSpecsExpected)
90     }
91 
92     @Test(expected = IllegalStateException::class)
parseInvalidFile_missingTag_throwsErrornull93     fun parseInvalidFile_missingTag_throwsError() {
94         val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_1".xmlToId())
95         ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
96     }
97 
98     @Test(expected = IllegalStateException::class)
parseInvalidFile_moreThanOneValuePerTag_throwsErrornull99     fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
100         val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_2".xmlToId())
101         ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
102     }
103 
104     @Test(expected = IllegalStateException::class)
parseInvalidFile_valueBiggerThan1_throwsErrornull105     fun parseInvalidFile_valueBiggerThan1_throwsError() {
106         val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_3".xmlToId())
107         ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
108     }
109 
110     @Test(expected = IllegalStateException::class)
parseInvalidFile_missingSpecs_throwsErrornull111     fun parseInvalidFile_missingSpecs_throwsError() {
112         val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_4".xmlToId())
113         ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
114     }
115 
116     @Test(expected = IllegalStateException::class)
parseInvalidFile_missingWidthBreakpoint_throwsErrornull117     fun parseInvalidFile_missingWidthBreakpoint_throwsError() {
118         val availableSpace = 900.dpToPx()
119         val cells = 3
120 
121         val workspaceSpec =
122             ResponsiveSpec(
123                 maxAvailableSize = availableSpace,
124                 dimensionType = DimensionType.WIDTH,
125                 specType = ResponsiveSpecType.Folder,
126                 startPadding = SizeSpec(fixedSize = 10f),
127                 endPadding = SizeSpec(fixedSize = 10f),
128                 gutter = SizeSpec(fixedSize = 10f),
129                 cellSize = SizeSpec(fixedSize = 10f)
130             )
131         val calculatedWorkspaceSpec =
132             CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
133 
134         val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_5".xmlToId())
135         val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
136         folderSpecs.getCalculatedSpec(
137             aspectRatio,
138             DimensionType.WIDTH,
139             cells,
140             availableSpace,
141             calculatedWorkspaceSpec
142         )
143     }
144 
145     @Test(expected = IllegalStateException::class)
parseInvalidFile_missingHeightBreakpoint_throwsErrornull146     fun parseInvalidFile_missingHeightBreakpoint_throwsError() {
147         val availableSpace = 900.dpToPx()
148         val cells = 3
149 
150         val workspaceSpec =
151             ResponsiveSpec(
152                 maxAvailableSize = availableSpace,
153                 dimensionType = DimensionType.HEIGHT,
154                 specType = ResponsiveSpecType.Folder,
155                 startPadding = SizeSpec(fixedSize = 10f),
156                 endPadding = SizeSpec(fixedSize = 10f),
157                 gutter = SizeSpec(fixedSize = 10f),
158                 cellSize = SizeSpec(fixedSize = 10f)
159             )
160         val calculatedWorkspaceSpec =
161             CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
162 
163         val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_5".xmlToId())
164         val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
165         folderSpecs.getCalculatedSpec(
166             aspectRatio,
167             DimensionType.HEIGHT,
168             cells,
169             availableSpace,
170             calculatedWorkspaceSpec
171         )
172     }
173 
174     @Test
retrievesCalculatedWidthSpecnull175     fun retrievesCalculatedWidthSpec() {
176         val availableSpace = 800.dpToPx()
177         val cells = 3
178 
179         val workspaceSpec =
180             ResponsiveSpec(
181                 maxAvailableSize = availableSpace,
182                 dimensionType = DimensionType.WIDTH,
183                 specType = ResponsiveSpecType.Workspace,
184                 startPadding = SizeSpec(fixedSize = 10f),
185                 endPadding = SizeSpec(fixedSize = 10f),
186                 gutter = SizeSpec(fixedSize = 10f),
187                 cellSize = SizeSpec(fixedSize = 10f)
188             )
189         val calculatedWorkspaceSpec =
190             CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
191 
192         val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
193         val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
194         val calculatedWidthSpec =
195             folderSpecs.getCalculatedSpec(
196                 aspectRatio,
197                 DimensionType.WIDTH,
198                 cells,
199                 availableSpace,
200                 calculatedWorkspaceSpec
201             )
202 
203         assertThat(calculatedWidthSpec.cells).isEqualTo(cells)
204         assertThat(calculatedWidthSpec.availableSpace).isEqualTo(availableSpace)
205         assertThat(calculatedWidthSpec.startPaddingPx).isEqualTo(16.dpToPx())
206         assertThat(calculatedWidthSpec.endPaddingPx).isEqualTo(16.dpToPx())
207         assertThat(calculatedWidthSpec.gutterPx).isEqualTo(16.dpToPx())
208         assertThat(calculatedWidthSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
209     }
210 
211     @Test(expected = IllegalStateException::class)
retrievesCalculatedWidthSpec_invalidCalculatedResponsiveSpecType_throwsErrornull212     fun retrievesCalculatedWidthSpec_invalidCalculatedResponsiveSpecType_throwsError() {
213         val availableSpace = 10.dpToPx()
214         val cells = 3
215 
216         val workspaceSpec =
217             ResponsiveSpec(
218                 maxAvailableSize = availableSpace,
219                 dimensionType = DimensionType.HEIGHT,
220                 specType = ResponsiveSpecType.Folder,
221                 startPadding = SizeSpec(fixedSize = 10f),
222                 endPadding = SizeSpec(fixedSize = 10f),
223                 gutter = SizeSpec(fixedSize = 10f),
224                 cellSize = SizeSpec(fixedSize = 10f)
225             )
226         val calculatedWorkspaceSpec =
227             CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
228 
229         val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
230         val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
231         folderSpecs.getCalculatedSpec(
232             aspectRatio,
233             DimensionType.WIDTH,
234             cells,
235             availableSpace,
236             calculatedWorkspaceSpec
237         )
238     }
239 
240     @Test
retrievesCalculatedHeightSpecnull241     fun retrievesCalculatedHeightSpec() {
242         val availableSpace = 700.dpToPx()
243         val cells = 3
244 
245         val workspaceSpec =
246             ResponsiveSpec(
247                 maxAvailableSize = availableSpace,
248                 dimensionType = DimensionType.HEIGHT,
249                 specType = ResponsiveSpecType.Workspace,
250                 startPadding = SizeSpec(fixedSize = 10f),
251                 endPadding = SizeSpec(fixedSize = 10f),
252                 gutter = SizeSpec(fixedSize = 10f),
253                 cellSize = SizeSpec(fixedSize = 10f)
254             )
255         val calculatedWorkspaceSpec =
256             CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
257 
258         val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
259         val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
260         val calculatedHeightSpec =
261             folderSpecs.getCalculatedSpec(
262                 aspectRatio,
263                 DimensionType.HEIGHT,
264                 cells,
265                 availableSpace,
266                 calculatedWorkspaceSpec
267             )
268 
269         assertThat(calculatedHeightSpec.cells).isEqualTo(cells)
270         assertThat(calculatedHeightSpec.availableSpace).isEqualTo(availableSpace)
271         assertThat(calculatedHeightSpec.startPaddingPx).isEqualTo(24.dpToPx())
272         assertThat(calculatedHeightSpec.endPaddingPx).isEqualTo(64.dpToPx())
273         assertThat(calculatedHeightSpec.gutterPx).isEqualTo(16.dpToPx())
274         assertThat(calculatedHeightSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
275     }
276 
277     @Test(expected = IllegalStateException::class)
retrievesCalculatedHeightSpec_invalidCalculatedResponsiveSpecType_throwsErrornull278     fun retrievesCalculatedHeightSpec_invalidCalculatedResponsiveSpecType_throwsError() {
279         val availableSpace = 10.dpToPx()
280         val cells = 3
281 
282         val workspaceSpec =
283             ResponsiveSpec(
284                 maxAvailableSize = availableSpace,
285                 dimensionType = DimensionType.WIDTH,
286                 specType = ResponsiveSpecType.Folder,
287                 startPadding = SizeSpec(fixedSize = 10f),
288                 endPadding = SizeSpec(fixedSize = 10f),
289                 gutter = SizeSpec(fixedSize = 10f),
290                 cellSize = SizeSpec(fixedSize = 10f)
291             )
292         val calculatedWorkspaceSpec =
293             CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
294 
295         val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
296         val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
297         folderSpecs.getCalculatedSpec(
298             aspectRatio,
299             DimensionType.HEIGHT,
300             cells,
301             availableSpace,
302             calculatedWorkspaceSpec
303         )
304     }
305 }
306