1 /*
2  * Copyright (C) 2018 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.settings.testutils;
18 
19 import static android.app.slice.Slice.HINT_TITLE;
20 import static android.app.slice.Slice.SUBTYPE_COLOR;
21 import static android.app.slice.SliceItem.FORMAT_IMAGE;
22 import static android.app.slice.SliceItem.FORMAT_INT;
23 import static android.app.slice.SliceItem.FORMAT_TEXT;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import android.app.PendingIntent;
28 import android.content.Context;
29 import android.text.TextUtils;
30 
31 import androidx.core.graphics.drawable.IconCompat;
32 import androidx.slice.Slice;
33 import androidx.slice.SliceItem;
34 import androidx.slice.SliceMetadata;
35 import androidx.slice.builders.ListBuilder;
36 import androidx.slice.core.SliceAction;
37 import androidx.slice.core.SliceQuery;
38 import androidx.slice.widget.EventInfo;
39 
40 import com.android.settings.Utils;
41 import com.android.settings.slices.SettingsSliceProvider;
42 import com.android.settings.slices.SliceBuilderUtils;
43 import com.android.settings.slices.SliceData;
44 
45 import java.util.Arrays;
46 import java.util.List;
47 import java.util.Set;
48 import java.util.stream.Collectors;
49 
50 /**
51  * Testing utility class to verify the contents of the different Settings Slices.
52  *
53  * TODO (77712944) check Summary, range (metadata.getRange()), toggle icons.
54  */
55 public class SliceTester {
56 
57     /**
58      * Test the contents of an intent based slice, including:
59      * - No toggles
60      * - Correct intent
61      * - Correct title
62      * - Correct keywords
63      * - TTL
64      * - Color
65      */
testSettingsIntentSlice(Context context, Slice slice, SliceData sliceData)66     public static void testSettingsIntentSlice(Context context, Slice slice, SliceData sliceData) {
67         final SliceMetadata metadata = SliceMetadata.from(context, slice);
68 
69         final long sliceTTL = metadata.getExpiry();
70         assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
71 
72         final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
73         final int color = colorItem.getInt();
74         assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
75 
76         final List<SliceAction> toggles = metadata.getToggles();
77         assertThat(toggles).isEmpty();
78 
79         final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction();
80         assertThat(primaryPendingIntent).isEqualTo(
81                 SliceBuilderUtils.getContentPendingIntent(context, sliceData));
82 
83         assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
84 
85         assertKeywords(metadata, sliceData);
86     }
87 
88     /**
89      * Test the contents of an toggle based slice, including:
90      * - Contains one toggle
91      * - Correct toggle intent
92      * - Correct content intent
93      * - Correct title
94      * - Correct keywords
95      * - TTL
96      * - Color
97      */
testSettingsToggleSlice(Context context, Slice slice, SliceData sliceData)98     public static void testSettingsToggleSlice(Context context, Slice slice, SliceData sliceData) {
99         final SliceMetadata metadata = SliceMetadata.from(context, slice);
100 
101         final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
102         final int color = colorItem.getInt();
103         assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
104 
105         final List<SliceAction> toggles = metadata.getToggles();
106         assertThat(toggles).hasSize(1);
107 
108         final long sliceTTL = metadata.getExpiry();
109         assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
110 
111         final SliceAction mainToggleAction = toggles.get(0);
112 
113         assertThat(mainToggleAction.getIcon()).isNull();
114 
115         // Check intent in Toggle Action
116         final PendingIntent togglePendingIntent = mainToggleAction.getAction();
117         assertThat(togglePendingIntent).isEqualTo(SliceBuilderUtils.getActionIntent(context,
118                 SettingsSliceProvider.ACTION_TOGGLE_CHANGED, sliceData));
119 
120         // Check primary intent
121         final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction();
122         assertThat(primaryPendingIntent).isEqualTo(
123                 SliceBuilderUtils.getContentPendingIntent(context, sliceData));
124 
125         assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
126 
127         assertKeywords(metadata, sliceData);
128     }
129 
130     /**
131      * Test the contents of an slider based slice, including:
132      * - No intent
133      * - Correct title
134      * - Correct keywords
135      * - TTL
136      * - Color
137      */
testSettingsSliderSlice(Context context, Slice slice, SliceData sliceData)138     public static void testSettingsSliderSlice(Context context, Slice slice, SliceData sliceData) {
139         final SliceMetadata metadata = SliceMetadata.from(context, slice);
140 
141         final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
142         final int color = colorItem.getInt();
143         assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
144 
145         final SliceAction primaryAction = metadata.getPrimaryAction();
146 
147         final IconCompat expectedIcon = IconCompat.createWithResource(context,
148                 sliceData.getIconResource());
149         assertThat(expectedIcon.toString()).isEqualTo(primaryAction.getIcon().toString());
150 
151         final long sliceTTL = metadata.getExpiry();
152         assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
153 
154         final int headerType = metadata.getHeaderType();
155         assertThat(headerType).isEqualTo(EventInfo.ROW_TYPE_SLIDER);
156 
157         // Check primary intent
158         final PendingIntent primaryPendingIntent = primaryAction.getAction();
159         assertThat(primaryPendingIntent).isEqualTo(
160                 SliceBuilderUtils.getContentPendingIntent(context, sliceData));
161 
162         assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
163 
164         assertKeywords(metadata, sliceData);
165     }
166 
167     /**
168      * Test the copyable slice, including:
169      * - No intent
170      * - Correct title
171      * - Correct intent
172      * - Correct keywords
173      * - TTL
174      * - Color
175      */
testSettingsCopyableSlice(Context context, Slice slice, SliceData sliceData)176     public static void testSettingsCopyableSlice(Context context, Slice slice,
177             SliceData sliceData) {
178         final SliceMetadata metadata = SliceMetadata.from(context, slice);
179 
180         final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
181         final int color = colorItem.getInt();
182         assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
183 
184         final SliceAction primaryAction = metadata.getPrimaryAction();
185 
186         final IconCompat expectedIcon = IconCompat.createWithResource(context,
187                 sliceData.getIconResource());
188         assertThat(expectedIcon.toString()).isEqualTo(primaryAction.getIcon().toString());
189 
190         final long sliceTTL = metadata.getExpiry();
191         assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
192 
193         // Check primary intent
194         final PendingIntent primaryPendingIntent = primaryAction.getAction();
195         assertThat(primaryPendingIntent).isEqualTo(
196                 SliceBuilderUtils.getContentPendingIntent(context, sliceData));
197 
198         assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
199 
200         assertKeywords(metadata, sliceData);
201     }
202 
203     /**
204      * Test the contents of an unavailable slice, including:
205      * - No toggles
206      * - Correct title
207      * - Correct intent
208      * - Correct keywords
209      * - Color
210      * - TTL
211      */
testSettingsUnavailableSlice(Context context, Slice slice, SliceData sliceData)212     public static void testSettingsUnavailableSlice(Context context, Slice slice,
213             SliceData sliceData) {
214         final SliceMetadata metadata = SliceMetadata.from(context, slice);
215 
216         final long sliceTTL = metadata.getExpiry();
217         assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
218 
219         final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
220         final int color = colorItem.getInt();
221         assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
222 
223         final List<SliceAction> toggles = metadata.getToggles();
224         assertThat(toggles).isEmpty();
225 
226         final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction();
227         assertThat(primaryPendingIntent).isEqualTo(SliceBuilderUtils.getContentPendingIntent(
228                 context, sliceData));
229 
230         assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
231 
232         assertKeywords(metadata, sliceData);
233     }
234 
235     /**
236      * Assert any slice item contains title.
237      *
238      * @param sliceItems All slice items of a Slice.
239      * @param title Title for asserting.
240      */
assertAnySliceItemContainsTitle(List<SliceItem> sliceItems, String title)241     public static void assertAnySliceItemContainsTitle(List<SliceItem> sliceItems, String title) {
242         assertThat(hasText(sliceItems, title, HINT_TITLE)).isTrue();
243     }
244 
245     /**
246      * Assert any slice item contains subtitle.
247      *
248      * @param sliceItems All slice items of a Slice.
249      * @param subtitle Subtitle for asserting.
250      */
assertAnySliceItemContainsSubtitle(List<SliceItem> sliceItems, String subtitle)251     public static void assertAnySliceItemContainsSubtitle(List<SliceItem> sliceItems,
252             String subtitle) {
253         // Subtitle has no hints
254         assertThat(hasText(sliceItems, subtitle, null /* hints */)).isTrue();
255     }
256 
257     /**
258      * Assert no slice item contains subtitle.
259      *
260      * @param sliceItems All slice items of a Slice.
261      * @param subtitle Subtitle for asserting.
262      */
assertNoSliceItemContainsSubtitle(List<SliceItem> sliceItems, String subtitle)263     public static void assertNoSliceItemContainsSubtitle(List<SliceItem> sliceItems,
264             String subtitle) {
265         // Subtitle has no hints
266         assertThat(hasText(sliceItems, subtitle, null /* hints */)).isFalse();
267     }
268 
hasText(List<SliceItem> sliceItems, String text, String hints)269     private static boolean hasText(List<SliceItem> sliceItems, String text, String hints) {
270         boolean hasText = false;
271         for (SliceItem item : sliceItems) {
272             List<SliceItem> textItems = SliceQuery.findAll(item, FORMAT_TEXT, hints,
273                     null /* non-hints */);
274             if (textItems == null) {
275                 continue;
276             }
277 
278             for (SliceItem textItem : textItems) {
279                 if (TextUtils.equals(textItem.getText(), text)) {
280                     hasText = true;
281                     break;
282                 }
283             }
284         }
285         return hasText;
286     }
287 
288     /**
289      * Assert any slice item contains icon.
290      *
291      * @param sliceItems All slice items of a Slice.
292      * @param icon Icon for asserting.
293      */
assertAnySliceItemContainsIcon(List<SliceItem> sliceItems, IconCompat icon)294     public static void assertAnySliceItemContainsIcon(List<SliceItem> sliceItems, IconCompat icon) {
295         boolean hasIcon = false;
296         for (SliceItem item : sliceItems) {
297             List<SliceItem> iconItems = SliceQuery.findAll(item, FORMAT_IMAGE,
298                     (String) null /* hints */, null /* non-hints */);
299             if (iconItems == null) {
300                 continue;
301             }
302 
303             for (SliceItem iconItem : iconItems) {
304                 if (icon.toString().equals(iconItem.getIcon().toString())) {
305                     hasIcon = true;
306                     break;
307                 }
308             }
309         }
310         assertThat(hasIcon).isTrue();
311     }
312 
assertKeywords(SliceMetadata metadata, SliceData data)313     private static void assertKeywords(SliceMetadata metadata, SliceData data) {
314         final List<String> keywords = metadata.getSliceKeywords();
315         final Set<String> expectedKeywords = Arrays.stream(data.getKeywords().split(","))
316                 .map(s -> s = s.trim())
317                 .collect(Collectors.toSet());
318         expectedKeywords.add(data.getTitle());
319         expectedKeywords.add(data.getScreenTitle().toString());
320         assertThat(keywords).containsExactlyElementsIn(expectedKeywords);
321     }
322 }