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