1 /*
2  * Copyright (C) 2021 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 package com.android.launcher3.widget;
17 
18 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
19 
20 import static com.google.common.truth.Truth.assertThat;
21 
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.Mockito.doAnswer;
24 
25 import android.appwidget.AppWidgetHostView;
26 import android.content.Context;
27 import android.graphics.Point;
28 import android.graphics.Rect;
29 
30 import androidx.test.ext.junit.runners.AndroidJUnit4;
31 import androidx.test.filters.SmallTest;
32 
33 import com.android.launcher3.DeviceProfile;
34 import com.android.launcher3.InvariantDeviceProfile;
35 import com.android.launcher3.LauncherAppState;
36 
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 import org.mockito.Mockito;
41 
42 import java.util.ArrayList;
43 import java.util.Collections;
44 import java.util.List;
45 
46 @SmallTest
47 @RunWith(AndroidJUnit4.class)
48 public final class LauncherAppWidgetProviderInfoTest {
49 
50     private static final int SPACE_SIZE = 10;
51     private static final int CELL_SIZE = 50;
52     private static final int NUM_OF_COLS = 4;
53     private static final int NUM_OF_ROWS = 5;
54 
55     private Context mContext;
56 
57     @Before
setUp()58     public void setUp() {
59         mContext = getApplicationContext();
60     }
61 
62     @Test
initSpans_minWidthSmallerThanCellWidth_shouldInitializeSpansToOne()63     public void initSpans_minWidthSmallerThanCellWidth_shouldInitializeSpansToOne() {
64         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
65         info.minWidth = 20;
66         info.minHeight = 20;
67         InvariantDeviceProfile idp = createIDP();
68 
69         info.initSpans(mContext, idp);
70 
71         assertThat(info.spanX).isEqualTo(1);
72         assertThat(info.spanY).isEqualTo(1);
73     }
74 
75     @Test
initSpans_minWidthLargerThanCellWidth_shouldInitializeSpans()76     public void initSpans_minWidthLargerThanCellWidth_shouldInitializeSpans() {
77         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
78         info.minWidth = 80;
79         info.minHeight = 80;
80         InvariantDeviceProfile idp = createIDP();
81 
82         info.initSpans(mContext, idp);
83 
84         assertThat(info.spanX).isEqualTo(2);
85         assertThat(info.spanY).isEqualTo(2);
86     }
87 
88     @Test
89     public void
initSpans_minWidthLargerThanGridColumns_shouldInitializeSpansToAtMostTheGridColumns()90             initSpans_minWidthLargerThanGridColumns_shouldInitializeSpansToAtMostTheGridColumns() {
91         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
92         info.minWidth = CELL_SIZE * (NUM_OF_COLS + 1);
93         info.minHeight = 20;
94         InvariantDeviceProfile idp = createIDP();
95 
96         info.initSpans(mContext, idp);
97 
98         assertThat(info.spanX).isEqualTo(NUM_OF_COLS);
99         assertThat(info.spanY).isEqualTo(1);
100     }
101 
102     @Test
initSpans_minHeightLargerThanGridRows_shouldInitializeSpansToAtMostTheGridRows()103     public void initSpans_minHeightLargerThanGridRows_shouldInitializeSpansToAtMostTheGridRows() {
104         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
105         info.minWidth = 20;
106         info.minHeight = 50 * (NUM_OF_ROWS + 1);
107         InvariantDeviceProfile idp = createIDP();
108 
109         info.initSpans(mContext, idp);
110 
111         assertThat(info.spanX).isEqualTo(1);
112         assertThat(info.spanY).isEqualTo(NUM_OF_ROWS);
113     }
114 
115     @Test
initSpans_minResizeWidthUnspecified_shouldInitializeMinSpansToOne()116     public void initSpans_minResizeWidthUnspecified_shouldInitializeMinSpansToOne() {
117         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
118         InvariantDeviceProfile idp = createIDP();
119 
120         info.initSpans(mContext, idp);
121 
122         assertThat(info.minSpanX).isEqualTo(1);
123         assertThat(info.minSpanY).isEqualTo(1);
124     }
125 
126     @Test
initSpans_minResizeWidthSmallerThanCellWidth_shouldInitializeMinSpansToOne()127     public void initSpans_minResizeWidthSmallerThanCellWidth_shouldInitializeMinSpansToOne() {
128         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
129         info.minWidth = 100;
130         info.minHeight = 100;
131         info.minResizeWidth = 20;
132         info.minResizeHeight = 20;
133         InvariantDeviceProfile idp = createIDP();
134 
135         info.initSpans(mContext, idp);
136 
137         assertThat(info.minSpanX).isEqualTo(1);
138         assertThat(info.minSpanY).isEqualTo(1);
139     }
140 
141     @Test
initSpans_minResizeWidthLargerThanCellWidth_shouldInitializeMinSpans()142     public void initSpans_minResizeWidthLargerThanCellWidth_shouldInitializeMinSpans() {
143         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
144         info.minWidth = 100;
145         info.minHeight = 100;
146         info.minResizeWidth = 80;
147         info.minResizeHeight = 80;
148         InvariantDeviceProfile idp = createIDP();
149 
150         info.initSpans(mContext, idp);
151 
152         assertThat(info.minSpanX).isEqualTo(2);
153         assertThat(info.minSpanY).isEqualTo(2);
154     }
155 
156     @Test
initSpans_minResizeWidthWithCellSpacingAndWidgetInset_shouldInitializeMinSpans()157     public void initSpans_minResizeWidthWithCellSpacingAndWidgetInset_shouldInitializeMinSpans() {
158         InvariantDeviceProfile idp = createIDP();
159         DeviceProfile dp = idp.supportedProfiles.get(0);
160         Rect padding = new Rect();
161         AppWidgetHostView.getDefaultPaddingForWidget(mContext, null, padding);
162         int maxPadding = Math.max(Math.max(padding.left, padding.right),
163                 Math.max(padding.top, padding.bottom));
164         dp.cellLayoutBorderSpacePx.x = dp.cellLayoutBorderSpacePx.y = maxPadding + 1;
165 
166         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
167         info.minWidth = CELL_SIZE * 3;
168         info.minHeight = CELL_SIZE * 3;
169         info.minResizeWidth = CELL_SIZE * 2 + maxPadding;
170         info.minResizeHeight = CELL_SIZE * 2 + maxPadding;
171 
172         info.initSpans(mContext, idp);
173 
174         assertThat(info.minSpanX).isEqualTo(2);
175         assertThat(info.minSpanY).isEqualTo(2);
176     }
177 
178     @Test
initSpans_minResizeWidthWithCellSpacingAndNoWidgetInset_shouldInitializeMinSpans()179     public void initSpans_minResizeWidthWithCellSpacingAndNoWidgetInset_shouldInitializeMinSpans() {
180         InvariantDeviceProfile idp = createIDP();
181         DeviceProfile dp = idp.supportedProfiles.get(0);
182         Rect padding = new Rect();
183         AppWidgetHostView.getDefaultPaddingForWidget(mContext, null, padding);
184         int maxPadding = Math.max(Math.max(padding.left, padding.right),
185                 Math.max(padding.top, padding.bottom));
186         dp.cellLayoutBorderSpacePx.x = dp.cellLayoutBorderSpacePx.y = maxPadding - 1;
187         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
188         info.minWidth = CELL_SIZE * 3;
189         info.minHeight = CELL_SIZE * 3;
190         info.minResizeWidth = CELL_SIZE * 2 + maxPadding;
191         info.minResizeHeight = CELL_SIZE * 2 + maxPadding;
192 
193         info.initSpans(mContext, idp);
194 
195         assertThat(info.minSpanX).isEqualTo(3);
196         assertThat(info.minSpanY).isEqualTo(3);
197     }
198 
199     @Test
200     public void
initSpans_minResizeWidthHeightLargerThanMinWidth_shouldUseMinWidthHeightAsMinSpans()201             initSpans_minResizeWidthHeightLargerThanMinWidth_shouldUseMinWidthHeightAsMinSpans() {
202         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
203         info.minWidth = 20;
204         info.minHeight = 20;
205         info.minResizeWidth = 80;
206         info.minResizeHeight = 80;
207         InvariantDeviceProfile idp = createIDP();
208 
209         info.initSpans(mContext, idp);
210 
211         assertThat(info.minSpanX).isEqualTo(1);
212         assertThat(info.minSpanY).isEqualTo(1);
213     }
214 
215     @Test
isMinSizeFulfilled_minWidthAndHeightWithinGridSize_shouldReturnTrue()216     public void isMinSizeFulfilled_minWidthAndHeightWithinGridSize_shouldReturnTrue() {
217         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
218         info.minWidth = 80;
219         info.minHeight = 80;
220         info.minResizeWidth = 50;
221         info.minResizeHeight = 50;
222         InvariantDeviceProfile idp = createIDP();
223 
224         info.initSpans(mContext, idp);
225 
226         assertThat(info.isMinSizeFulfilled()).isTrue();
227     }
228 
229     @Test
230     public void
isMinSizeFulfilled_minWidthAndMinResizeWidthExceededGridColumns_shouldReturnFalse()231             isMinSizeFulfilled_minWidthAndMinResizeWidthExceededGridColumns_shouldReturnFalse() {
232         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
233         info.minWidth = CELL_SIZE * (NUM_OF_COLS + 2);
234         info.minHeight = 80;
235         info.minResizeWidth = CELL_SIZE * (NUM_OF_COLS + 1);
236         info.minResizeHeight = 50;
237         InvariantDeviceProfile idp = createIDP();
238 
239         info.initSpans(mContext, idp);
240 
241         assertThat(info.isMinSizeFulfilled()).isFalse();
242     }
243 
244     @Test
isMinSizeFulfilled_minHeightAndMinResizeHeightExceededGridRows_shouldReturnFalse()245     public void isMinSizeFulfilled_minHeightAndMinResizeHeightExceededGridRows_shouldReturnFalse() {
246         LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
247         info.minWidth = 80;
248         info.minHeight = CELL_SIZE * (NUM_OF_ROWS + 2);
249         info.minResizeWidth = 50;
250         info.minResizeHeight = CELL_SIZE * (NUM_OF_ROWS + 1);
251         InvariantDeviceProfile idp = createIDP();
252 
253         info.initSpans(mContext, idp);
254 
255         assertThat(info.isMinSizeFulfilled()).isFalse();
256     }
257 
createIDP()258     private InvariantDeviceProfile createIDP() {
259         DeviceProfile dp = LauncherAppState.getIDP(mContext)
260                 .getDeviceProfile(mContext).copy(mContext);
261         DeviceProfile profile = Mockito.spy(dp);
262         doAnswer(i -> {
263             ((Point) i.getArgument(0)).set(CELL_SIZE, CELL_SIZE);
264             return null;
265         }).when(profile).getCellSize(any(Point.class));
266         Mockito.when(profile.getCellSize()).thenReturn(new Point(CELL_SIZE, CELL_SIZE));
267         profile.cellLayoutBorderSpacePx = new Point(SPACE_SIZE, SPACE_SIZE);
268         profile.widgetPadding.setEmpty();
269 
270         InvariantDeviceProfile idp = new InvariantDeviceProfile();
271         List<DeviceProfile> supportedProfiles = new ArrayList<>(idp.supportedProfiles);
272         supportedProfiles.add(profile);
273         idp.supportedProfiles = Collections.unmodifiableList(supportedProfiles);
274         idp.numColumns = NUM_OF_COLS;
275         idp.numRows = NUM_OF_ROWS;
276         return idp;
277     }
278 }
279