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