SampleSliceProvider.java revision e7f1c6cf75ce36c633075445bd676572a9fe0f47
1/* 2 * Copyright 2017 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 17package com.example.androidx.slice.demos; 18 19import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; 20 21import static androidx.slice.builders.ListBuilder.ICON_IMAGE; 22import static androidx.slice.builders.ListBuilder.INFINITY; 23import static androidx.slice.builders.ListBuilder.LARGE_IMAGE; 24import static androidx.slice.builders.ListBuilder.SMALL_IMAGE; 25 26import android.app.PendingIntent; 27import android.content.ContentResolver; 28import android.content.Context; 29import android.content.Intent; 30import android.graphics.drawable.Icon; 31import android.net.Uri; 32import android.net.wifi.WifiManager; 33import android.os.Handler; 34import android.provider.Settings; 35import android.text.SpannableString; 36import android.text.format.DateUtils; 37import android.text.style.ForegroundColorSpan; 38import android.util.SparseArray; 39 40import androidx.annotation.NonNull; 41import androidx.slice.Slice; 42import androidx.slice.SliceProvider; 43import androidx.slice.builders.GridRowBuilder; 44import androidx.slice.builders.ListBuilder; 45import androidx.slice.builders.MessagingSliceBuilder; 46import androidx.slice.builders.SliceAction; 47 48import java.util.Arrays; 49import java.util.Calendar; 50 51/** 52 * Examples of using slice template builders. 53 */ 54public class SampleSliceProvider extends SliceProvider { 55 56 private static final boolean TEST_CUSTOM_SEE_MORE = false; 57 58 public static final String ACTION_WIFI_CHANGED = 59 "com.example.androidx.slice.action.WIFI_CHANGED"; 60 public static final String ACTION_TOAST = 61 "com.example.androidx.slice.action.TOAST"; 62 public static final String EXTRA_TOAST_MESSAGE = "com.example.androidx.extra.TOAST_MESSAGE"; 63 public static final String ACTION_TOAST_RANGE_VALUE = 64 "com.example.androidx.slice.action.TOAST_RANGE_VALUE"; 65 66 public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle", 67 "toggle2", "contact", "gallery", "weather", "reservation", "loadlist", "loadgrid", 68 "inputrange", "range", "contact2", "subscription"}; 69 70 /** 71 * @return Uri with the provided path 72 */ 73 public static Uri getUri(String path, Context context) { 74 return new Uri.Builder() 75 .scheme(ContentResolver.SCHEME_CONTENT) 76 .authority(context.getPackageName()) 77 .appendPath(path) 78 .build(); 79 } 80 81 @Override 82 public boolean onCreateSliceProvider() { 83 return true; 84 } 85 86 @NonNull 87 @Override 88 public Uri onMapIntentToUri(Intent intent) { 89 return getUri("wifi", getContext()); 90 } 91 92 @Override 93 public Slice onBindSlice(Uri sliceUri) { 94 String path = sliceUri.getPath(); 95 if (!path.equals("/loadlist")) { 96 mListSummaries.clear(); 97 mListLastUpdate = 0; 98 } 99 if (!path.equals("/loadgrid")) { 100 mGridSummaries.clear(); 101 mGridLastUpdate = 0; 102 } 103 switch (path) { 104 // TODO: add list / grid slices with 'see more' options 105 case "/message": 106 return createMessagingSlice(sliceUri); 107 case "/wifi": 108 return createWifiSlice(sliceUri); 109 case "/note": 110 return createNoteSlice(sliceUri); 111 case "/ride": 112 return createRideSlice(sliceUri); 113 case "/toggle": 114 return createCustomToggleSlice(sliceUri); 115 case "/toggle2": 116 return createTwoCustomToggleSlices(sliceUri); 117 case "/contact": 118 return createContact(sliceUri); 119 case "/contact2": 120 return createContact2(sliceUri); 121 case "/gallery": 122 return createGallery(sliceUri); 123 case "/weather": 124 return createWeather(sliceUri); 125 case "/reservation": 126 return createReservationSlice(sliceUri); 127 case "/loadlist": 128 return createLoadingListSlice(sliceUri); 129 case "/loadgrid": 130 return createLoadingGridSlice(sliceUri); 131 case "/inputrange": 132 return createStarRatingInputRange(sliceUri); 133 case "/range": 134 return createDownloadProgressRange(sliceUri); 135 case "/subscription": 136 return createCatSlice(sliceUri, false /* customSeeMore */); 137 } 138 throw new IllegalArgumentException("Unknown uri " + sliceUri); 139 } 140 141 private Slice createWeather(Uri sliceUri) { 142 SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST, 143 "open weather app"), Icon.createWithResource(getContext(), R.drawable.weather_1), 144 "Weather is happening!"); 145 return new ListBuilder(getContext(), sliceUri, INFINITY) 146 .addGrid(gb -> gb 147 .setPrimaryAction(primaryAction) 148 .addCell(cb -> cb 149 .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1), 150 SMALL_IMAGE) 151 .addText("MON") 152 .addTitleText("69\u00B0")) 153 .addCell(cb -> cb 154 .addImage(Icon.createWithResource(getContext(), R.drawable.weather_2), 155 SMALL_IMAGE) 156 .addText("TUE") 157 .addTitleText("71\u00B0")) 158 .addCell(cb -> cb 159 .addImage(Icon.createWithResource(getContext(), R.drawable.weather_3), 160 SMALL_IMAGE) 161 .addText("WED") 162 .addTitleText("76\u00B0")) 163 .addCell(cb -> cb 164 .addImage(Icon.createWithResource(getContext(), R.drawable.weather_4), 165 SMALL_IMAGE) 166 .addText("THU") 167 .addTitleText("72\u00B0")) 168 .addCell(cb -> cb 169 .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1), 170 SMALL_IMAGE) 171 .addText("FRI") 172 .addTitleText("68\u00B0"))) 173 .build(); 174 } 175 176 private Slice createGallery(Uri sliceUri) { 177 return new ListBuilder(getContext(), sliceUri, INFINITY) 178 .setColor(0xff4285F4) 179 .addRow(b -> b 180 .setTitle("Family trip to Hawaii") 181 .setSubtitle("Sep 30, 2017 - Oct 2, 2017")) 182 .addAction(new SliceAction( 183 getBroadcastIntent(ACTION_TOAST, "cast photo album"), 184 Icon.createWithResource(getContext(), R.drawable.ic_cast), 185 "Cast photo album")) 186 .addAction(new SliceAction( 187 getBroadcastIntent(ACTION_TOAST, "share photo album"), 188 Icon.createWithResource(getContext(), R.drawable.ic_share), 189 "Share photo album")) 190 .addGrid(b -> b 191 .addCell(cb -> cb 192 .addImage(Icon.createWithResource(getContext(), R.drawable.slices_1), 193 LARGE_IMAGE)) 194 .addCell(cb -> cb 195 .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2), 196 LARGE_IMAGE)) 197 .addCell(cb -> cb 198 .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3), 199 LARGE_IMAGE)) 200 .addCell(cb -> cb 201 .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4), 202 LARGE_IMAGE)) 203 .addCell(cb -> cb 204 .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2), 205 LARGE_IMAGE)) 206 .addCell(cb -> cb 207 .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3), 208 LARGE_IMAGE)) 209 .addCell(cb -> cb 210 .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4), 211 LARGE_IMAGE)) 212 .addSeeMoreAction(getBroadcastIntent(ACTION_TOAST, "see your gallery")) 213 .setContentDescription("Images from your trip to Hawaii")) 214 .build(); 215 } 216 217 private Slice createCatSlice(Uri sliceUri, boolean customSeeMore) { 218 ListBuilder b = new ListBuilder(getContext(), sliceUri, INFINITY); 219 GridRowBuilder gb = new GridRowBuilder(b); 220 PendingIntent pi = getBroadcastIntent(ACTION_TOAST, "See cats you follow"); 221 if (customSeeMore) { 222 GridRowBuilder.CellBuilder cb = new GridRowBuilder.CellBuilder(gb); 223 cb.addImage(Icon.createWithResource(getContext(), R.drawable.ic_right_caret), 224 ICON_IMAGE); 225 cb.setContentIntent(pi); 226 cb.addTitleText("All cats"); 227 gb.addSeeMoreCell(cb); 228 } else { 229 gb.addSeeMoreAction(pi); 230 } 231 gb.addCell(new GridRowBuilder.CellBuilder(gb) 232 .addImage(Icon.createWithResource(getContext(), R.drawable.cat_1), SMALL_IMAGE) 233 .addTitleText("Oreo")) 234 .addCell(new GridRowBuilder.CellBuilder(gb) 235 .addImage(Icon.createWithResource(getContext(), R.drawable.cat_2), 236 SMALL_IMAGE) 237 .addTitleText("Silver")) 238 .addCell(new GridRowBuilder.CellBuilder(gb) 239 .addImage(Icon.createWithResource(getContext(), R.drawable.cat_3), 240 SMALL_IMAGE) 241 .addTitleText("Drake")) 242 .addCell(new GridRowBuilder.CellBuilder(gb) 243 .addImage(Icon.createWithResource(getContext(), R.drawable.cat_5), 244 SMALL_IMAGE) 245 .addTitleText("Olive")) 246 .addCell(new GridRowBuilder.CellBuilder(gb) 247 .addImage(Icon.createWithResource(getContext(), R.drawable.cat_4), 248 SMALL_IMAGE) 249 .addTitleText("Lady Marmalade")) 250 .addCell(new GridRowBuilder.CellBuilder(gb) 251 .addImage(Icon.createWithResource(getContext(), R.drawable.cat_6), 252 SMALL_IMAGE) 253 .addTitleText("Grapefruit")); 254 return b.addGridRow(gb).build(); 255 } 256 257 private Slice createContact2(Uri sliceUri) { 258 ListBuilder b = new ListBuilder(getContext(), sliceUri, INFINITY); 259 ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(b); 260 GridRowBuilder gb = new GridRowBuilder(b); 261 return b.setColor(0xff3949ab) 262 .addRow(rb 263 .setTitle("Mady Pitza") 264 .setSubtitle("Frequently contacted contact") 265 .addEndItem(Icon.createWithResource(getContext(), R.drawable.mady), 266 SMALL_IMAGE)) 267 .addGridRow(gb 268 .addCell(new GridRowBuilder.CellBuilder(gb) 269 .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call), 270 ICON_IMAGE) 271 .addText("Call") 272 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call"))) 273 .addCell(new GridRowBuilder.CellBuilder(gb) 274 .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text), 275 ICON_IMAGE) 276 .addText("Text") 277 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text"))) 278 .addCell(new GridRowBuilder.CellBuilder(gb) 279 .addImage(Icon.createWithResource(getContext(), 280 R.drawable.ic_video), ICON_IMAGE) 281 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video")) 282 .addText("Video")) 283 .addCell(new GridRowBuilder.CellBuilder(gb) 284 .addImage(Icon.createWithResource(getContext(), 285 R.drawable.ic_email), ICON_IMAGE) 286 .addText("Email") 287 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email")))) 288 .build(); 289 } 290 291 private Slice createContact(Uri sliceUri) { 292 final long lastCalled = System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS; 293 CharSequence lastCalledString = DateUtils.getRelativeTimeSpanString(lastCalled, 294 Calendar.getInstance().getTimeInMillis(), 295 DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE); 296 SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST, 297 "See contact info"), Icon.createWithResource(getContext(), 298 R.drawable.mady), SMALL_IMAGE, "Mady"); 299 300 return new ListBuilder(getContext(), sliceUri, INFINITY) 301 .setColor(0xff3949ab) 302 .setHeader(b -> b 303 .setTitle("Mady Pitza") 304 .setSummarySubtitle("Called " + lastCalledString) 305 .setPrimaryAction(primaryAction)) 306 .addRow(b -> b 307 .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_call), 308 ICON_IMAGE) 309 .setTitle("314-259-2653") 310 .setSubtitle("Call lasted 1 hr 17 min") 311 .addEndItem(lastCalled)) 312 .addRow(b -> b 313 .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_text), 314 ICON_IMAGE) 315 .setTitle("You: Coooooool see you then") 316 .addEndItem(System.currentTimeMillis() - 40 * DateUtils.MINUTE_IN_MILLIS)) 317 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "call"), 318 Icon.createWithResource(getContext(), R.drawable.ic_call), "Call mady")) 319 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "text"), 320 Icon.createWithResource(getContext(), R.drawable.ic_text), "Text mady")) 321 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "video"), 322 Icon.createWithResource(getContext(), R.drawable.ic_video), 323 "Video call mady")) 324 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "email"), 325 Icon.createWithResource(getContext(), R.drawable.ic_email), "Email mady")) 326 .build(); 327 } 328 329 private Slice createMessagingSlice(Uri sliceUri) { 330 // TODO: Remote input. 331 return new MessagingSliceBuilder(getContext(), sliceUri) 332 .add(b -> b 333 .addText("yo home \uD83C\uDF55, I emailed you the info") 334 .addTimestamp(System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS) 335 .addSource(Icon.createWithResource(getContext(), R.drawable.mady))) 336 .add(b -> b 337 .addText("just bought my tickets") 338 .addTimestamp(System.currentTimeMillis() - 10 * DateUtils.MINUTE_IN_MILLIS)) 339 .add(b -> b 340 .addText("yay! can't wait for getContext() weekend!\n" 341 + "\uD83D\uDE00") 342 .addTimestamp(System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS) 343 .addSource(Icon.createWithResource(getContext(), R.drawable.mady))) 344 .build(); 345 346 } 347 348 private Slice createNoteSlice(Uri sliceUri) { 349 // TODO: Remote input. 350 return new ListBuilder(getContext(), sliceUri, INFINITY) 351 .setColor(0xfff4b400) 352 .addRow(b -> b.setTitle("Create new note")) 353 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "create note"), 354 Icon.createWithResource(getContext(), R.drawable.ic_create), 355 "Create note")) 356 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "voice note"), 357 Icon.createWithResource(getContext(), R.drawable.ic_voice), 358 "Voice note")) 359 .addAction(new SliceAction(getIntent("android.media.action.IMAGE_CAPTURE"), 360 Icon.createWithResource(getContext(), R.drawable.ic_camera), 361 "Photo note")) 362 .build(); 363 } 364 365 private Slice createReservationSlice(Uri sliceUri) { 366 return new ListBuilder(getContext(), sliceUri, INFINITY) 367 .setColor(0xffFF5252) 368 .setHeader(b -> b 369 .setTitle("Upcoming trip to Seattle") 370 .setSubtitle("Feb 1 - 19 | 2 guests")) 371 .addAction(new SliceAction( 372 getBroadcastIntent(ACTION_TOAST, "show location on map"), 373 Icon.createWithResource(getContext(), R.drawable.ic_location), 374 "Show reservation location")) 375 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "contact host"), 376 Icon.createWithResource(getContext(), R.drawable.ic_text), 377 "Contact host")) 378 .addGrid(b -> b 379 .addCell(cb -> cb 380 .addImage(Icon.createWithResource(getContext(), R.drawable.reservation), 381 LARGE_IMAGE) 382 .setContentDescription("Image of your reservation in Seattle"))) 383 .addGrid(b -> b 384 .addCell(cb -> cb 385 .addTitleText("Check In") 386 .addText("12:00 PM, Feb 1")) 387 .addCell(cb -> cb 388 .addTitleText("Check Out") 389 .addText("11:00 AM, Feb 19"))) 390 .build(); 391 } 392 393 private Slice createRideSlice(Uri sliceUri) { 394 final ForegroundColorSpan colorSpan = new ForegroundColorSpan(0xff0F9D58); 395 SpannableString headerSubtitle = new SpannableString("Ride in 4 min"); 396 headerSubtitle.setSpan(colorSpan, 8, headerSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE); 397 SpannableString homeSubtitle = new SpannableString("12 miles | 12 min | $9.00"); 398 homeSubtitle.setSpan(colorSpan, 20, homeSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE); 399 SpannableString workSubtitle = new SpannableString("44 miles | 1 hour 45 min | $31.41"); 400 workSubtitle.setSpan(colorSpan, 27, workSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE); 401 402 SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST, "get ride"), 403 Icon.createWithResource(getContext(), R.drawable.ic_car), "Get Ride"); 404 return new ListBuilder(getContext(), sliceUri, INFINITY) 405 .setColor(0xff0F9D58) 406 .setHeader(b -> b 407 .setTitle("Get ride") 408 .setSubtitle(headerSubtitle) 409 .setSummarySubtitle("Ride to work in 12 min | Ride home in 1 hour 45 min") 410 .setPrimaryAction(primaryAction)) 411 .addRow(b -> b 412 .setTitle("Work") 413 .setSubtitle(workSubtitle) 414 .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "work"), 415 Icon.createWithResource(getContext(), R.drawable.ic_work), 416 "Get ride to work"))) 417 .addRow(b -> b 418 .setTitle("Home") 419 .setSubtitle(homeSubtitle) 420 .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "home"), 421 Icon.createWithResource(getContext(), R.drawable.ic_home), 422 "Get ride home"))) 423 .build(); 424 } 425 426 private Slice createCustomToggleSlice(Uri sliceUri) { 427 return new ListBuilder(getContext(), sliceUri, INFINITY) 428 .setColor(0xffff4081) 429 .addRow(b -> b 430 .setTitle("Custom toggle") 431 .setSubtitle("It can support two states") 432 .setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, 433 "star toggled"), 434 Icon.createWithResource(getContext(), R.drawable.toggle_star), 435 "Toggle star", true /* isChecked */))) 436 .build(); 437 } 438 439 private Slice createTwoCustomToggleSlices(Uri sliceUri) { 440 return new ListBuilder(getContext(), sliceUri, INFINITY) 441 .setColor(0xffff4081) 442 .addRow(b -> b 443 .setTitle("2 toggles") 444 .setSubtitle("each supports two states") 445 .addEndItem(new SliceAction( 446 getBroadcastIntent(ACTION_TOAST, "first star toggled"), 447 Icon.createWithResource(getContext(), R.drawable.toggle_star), 448 "Toggle star", true /* isChecked */)) 449 .addEndItem(new SliceAction( 450 getBroadcastIntent(ACTION_TOAST, "second star toggled"), 451 Icon.createWithResource(getContext(), R.drawable.toggle_star), 452 "Toggle star", false /* isChecked */))) 453 .build(); 454 } 455 456 private Slice createWifiSlice(Uri sliceUri) { 457 // Get wifi state 458 WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); 459 int wifiState = wifiManager.getWifiState(); 460 boolean wifiEnabled = false; 461 String state; 462 switch (wifiState) { 463 case WifiManager.WIFI_STATE_DISABLED: 464 case WifiManager.WIFI_STATE_DISABLING: 465 state = "disconnected"; 466 break; 467 case WifiManager.WIFI_STATE_ENABLED: 468 case WifiManager.WIFI_STATE_ENABLING: 469 state = wifiManager.getConnectionInfo().getSSID(); 470 wifiEnabled = true; 471 break; 472 case WifiManager.WIFI_STATE_UNKNOWN: 473 default: 474 state = ""; // just don't show anything? 475 break; 476 } 477 478 // Set the first row as a toggle 479 boolean finalWifiEnabled = wifiEnabled; 480 SliceAction primaryAction = new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS), 481 Icon.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings"); 482 String toggleCDString = wifiEnabled ? "Turn wifi off" : "Turn wifi on"; 483 String sliceCDString = wifiEnabled ? "Wifi connected to " + state 484 : "Wifi disconnected, 10 networks available"; 485 ListBuilder lb = new ListBuilder(getContext(), sliceUri, INFINITY) 486 .setColor(0xff4285f4) 487 .setHeader(b -> b 488 .setTitle("Wi-fi") 489 .setSubtitle(state) 490 .setContentDescription(sliceCDString) 491 .setPrimaryAction(primaryAction)) 492 .addAction((new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null), 493 toggleCDString, finalWifiEnabled))); 494 495 // Add fake wifi networks 496 int[] wifiIcons = new int[] {R.drawable.ic_wifi_full, R.drawable.ic_wifi_low, 497 R.drawable.ic_wifi_fair}; 498 for (int i = 0; i < 10; i++) { 499 final int iconId = wifiIcons[i % wifiIcons.length]; 500 Icon icon = Icon.createWithResource(getContext(), iconId); 501 final String networkName = "Network" + i; 502 ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(lb); 503 rb.setTitleItem(icon, ICON_IMAGE).setTitle(networkName); 504 boolean locked = i % 3 == 0; 505 if (locked) { 506 rb.addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_lock), 507 ICON_IMAGE); 508 rb.setContentDescription("Connect to " + networkName + ", password needed"); 509 } else { 510 rb.setContentDescription("Connect to " + networkName); 511 } 512 String message = locked ? "Open wifi password dialog" : "Connect to " + networkName; 513 rb.setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, message), icon, 514 message)); 515 lb.addRow(rb); 516 } 517 518 // Add keywords 519 String[] keywords = new String[] {"internet", "wifi", "data", "network"}; 520 lb.setKeywords(Arrays.asList(keywords)); 521 522 // Add see more intent 523 if (TEST_CUSTOM_SEE_MORE) { 524 lb.addSeeMoreRow(rb -> rb 525 .setTitle("See all available networks") 526 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_right_caret), 527 SMALL_IMAGE) 528 .setPrimaryAction(primaryAction)); 529 } else { 530 lb.addSeeMoreAction(primaryAction.getAction()); 531 } 532 return lb.build(); 533 } 534 535 private Slice createStarRatingInputRange(Uri sliceUri) { 536 return new ListBuilder(getContext(), sliceUri, INFINITY) 537 .setColor(0xffff4081) 538 .addInputRange(c -> c 539 .setTitle("Star rating") 540 .setThumb(Icon.createWithResource(getContext(), R.drawable.ic_star_on)) 541 .setAction(getBroadcastIntent(ACTION_TOAST_RANGE_VALUE, null)) 542 .setMax(5) 543 .setValue(3) 544 .setContentDescription("Slider for star ratings")) 545 .build(); 546 } 547 548 private Slice createDownloadProgressRange(Uri sliceUri) { 549 return new ListBuilder(getContext(), sliceUri, INFINITY) 550 .setColor(0xffff4081) 551 .addRange(c -> c 552 .setTitle("Download progress") 553 .setMax(100) 554 .setValue(75)) 555 .build(); 556 } 557 558 private Handler mHandler = new Handler(); 559 private SparseArray<String> mListSummaries = new SparseArray<>(); 560 private long mListLastUpdate; 561 private SparseArray<String> mGridSummaries = new SparseArray<>(); 562 private long mGridLastUpdate; 563 564 private void update(long delay, SparseArray<String> summaries, int id, String s, Uri uri, 565 Runnable r) { 566 mHandler.postDelayed(() -> { 567 summaries.put(id, s); 568 getContext().getContentResolver().notifyChange(uri, null); 569 r.run(); 570 }, delay); 571 } 572 573 private Slice createLoadingListSlice(Uri sliceUri) { 574 boolean updating = mListLastUpdate == 0 575 || mListLastUpdate < (System.currentTimeMillis() - 10 * System.currentTimeMillis()); 576 if (updating) { 577 Runnable r = () -> mListLastUpdate = System.currentTimeMillis(); 578 update(1000, mListSummaries, 0, "44 miles | 1 hour 45 min | $31.41", sliceUri, r); 579 update(1500, mListSummaries, 1, "12 miles | 12 min | $9.00", sliceUri, r); 580 update(1700, mListSummaries, 2, "5 miles | 10 min | $8.00", sliceUri, r); 581 } 582 Slice s = new ListBuilder(getContext(), sliceUri, INFINITY) 583 .addRow(b -> b 584 .setTitle("Work") 585 .setSubtitle(mListSummaries.get(0, ""), updating) 586 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_work), 587 ICON_IMAGE)) 588 .addRow(b -> b 589 .setTitle("Home") 590 .setSubtitle(mListSummaries.get(1, ""), updating) 591 .addEndItem( 592 Icon.createWithResource(getContext(), R.drawable.ic_home), 593 ICON_IMAGE)) 594 .addRow(b -> b 595 .setTitle("School") 596 .setSubtitle(mListSummaries.get(2, ""), updating) 597 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_school), 598 ICON_IMAGE)) 599 .build(); 600 return s; 601 } 602 603 private Slice createLoadingGridSlice(Uri sliceUri) { 604 boolean updating = mGridLastUpdate == 0 605 || mGridLastUpdate < (System.currentTimeMillis() - 10 * System.currentTimeMillis()); 606 if (updating) { 607 Runnable r = () -> mGridLastUpdate = System.currentTimeMillis(); 608 update(2000, mGridSummaries, 0, "Heavy traffic in your area", sliceUri, r); 609 update(3500, mGridSummaries, 1, "Typical conditions with delays up to 28 min", 610 sliceUri, r); 611 update(3000, mGridSummaries, 2, "41 min", sliceUri, r); 612 update(1500, mGridSummaries, 3, "33 min", sliceUri, r); 613 update(1000, mGridSummaries, 4, "12 min", sliceUri, r); 614 } 615 Slice s = new ListBuilder(getContext(), sliceUri, INFINITY) 616 .setHeader(hb -> hb 617 .setTitle(mGridSummaries.get(0, ""), updating) 618 .setSubtitle(mGridSummaries.get(1, ""), updating)) 619 .addGrid(gb -> gb 620 .addCell(cb -> cb 621 .addImage(Icon.createWithResource(getContext(), R.drawable.ic_home), 622 ICON_IMAGE) 623 .addTitleText("Home") 624 .addText(mGridSummaries.get(2, ""), updating)) 625 .addCell(cb -> cb 626 .addImage(Icon.createWithResource(getContext(), R.drawable.ic_work), 627 ICON_IMAGE) 628 .addTitleText("Work") 629 .addText(mGridSummaries.get(3, ""), updating)) 630 .addCell(cb -> cb 631 .addImage(Icon.createWithResource(getContext(), R.drawable.ic_school), 632 ICON_IMAGE) 633 .addTitleText("School") 634 .addText(mGridSummaries.get(4, ""), updating))) 635 .build(); 636 return s; 637 } 638 639 private PendingIntent getIntent(String action) { 640 Intent intent = new Intent(action); 641 PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0); 642 return pi; 643 } 644 645 private PendingIntent getBroadcastIntent(String action, String message) { 646 Intent intent = new Intent(action); 647 intent.setClass(getContext(), SliceBroadcastReceiver.class); 648 // Ensure a new PendingIntent is created for each message. 649 int requestCode = 0; 650 if (message != null) { 651 intent.putExtra(EXTRA_TOAST_MESSAGE, message); 652 requestCode = message.hashCode(); 653 } 654 return PendingIntent.getBroadcast(getContext(), requestCode, intent, 655 PendingIntent.FLAG_UPDATE_CURRENT); 656 } 657} 658