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