SampleSliceProvider.java revision 0922d59222960ed7c88c5e5098399e33a343c9c6
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 android.app.PendingIntent; 22import android.content.ContentResolver; 23import android.content.Context; 24import android.content.Intent; 25import android.graphics.drawable.Icon; 26import android.net.Uri; 27import android.net.wifi.WifiManager; 28import android.provider.Settings; 29import android.support.annotation.NonNull; 30import android.text.SpannableString; 31import android.text.format.DateUtils; 32import android.text.style.ForegroundColorSpan; 33 34import androidx.app.slice.Slice; 35import androidx.app.slice.SliceProvider; 36import androidx.app.slice.builders.GridBuilder; 37import androidx.app.slice.builders.ListBuilder; 38import androidx.app.slice.builders.MessagingSliceBuilder; 39 40/** 41 * Examples of using slice template builders. 42 */ 43public class SampleSliceProvider extends SliceProvider { 44 45 public static final String ACTION_WIFI_CHANGED = 46 "com.example.androidx.slice.action.WIFI_CHANGED"; 47 public static final String ACTION_TOAST = 48 "com.example.androidx.slice.action.TOAST"; 49 public static final String EXTRA_TOAST_MESSAGE = "com.example.androidx.extra.TOAST_MESSAGE"; 50 51 public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle", 52 "toggle2", "contact", "gallery", "weather", "reservation"}; 53 54 /** 55 * @return Uri with the provided path 56 */ 57 public static Uri getUri(String path, Context context) { 58 return new Uri.Builder() 59 .scheme(ContentResolver.SCHEME_CONTENT) 60 .authority(context.getPackageName()) 61 .appendPath(path) 62 .build(); 63 } 64 65 @Override 66 public boolean onCreateSliceProvider() { 67 return true; 68 } 69 70 @NonNull 71 @Override 72 public Uri onMapIntentToUri(Intent intent) { 73 return getUri("wifi", getContext()); 74 } 75 76 @Override 77 public Slice onBindSlice(Uri sliceUri) { 78 String path = sliceUri.getPath(); 79 switch (path) { 80 case "/message": 81 return createMessagingSlice(sliceUri); 82 case "/wifi": 83 return createWifiSlice(sliceUri); 84 case "/note": 85 return createNoteSlice(sliceUri); 86 case "/ride": 87 return createRideSlice(sliceUri); 88 case "/toggle": 89 return createCustomToggleSlice(sliceUri); 90 case "/toggle2": 91 return createTwoCustomToggleSlices(sliceUri); 92 case "/contact": 93 return createContact(sliceUri); 94 case "/gallery": 95 return createGallery(sliceUri); 96 case "/weather": 97 return createWeather(sliceUri); 98 case "/reservation": 99 return createReservationSlice(sliceUri); 100 } 101 throw new IllegalArgumentException("Unknown uri " + sliceUri); 102 } 103 104 private Slice createWeather(Uri sliceUri) { 105 return new GridBuilder(getContext(), sliceUri) 106 .addCell(cb -> cb 107 .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1)) 108 .addText("MON") 109 .addTitleText("69\u00B0")) 110 .addCell(cb -> cb 111 .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_2)) 112 .addText("TUE") 113 .addTitleText("71\u00B0")) 114 .addCell(cb -> cb 115 .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_3)) 116 .addText("WED") 117 .addTitleText("76\u00B0")) 118 .addCell(cb -> cb 119 .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_4)) 120 .addText("THU") 121 .addTitleText("72\u00B0")) 122 .addCell(cb -> cb 123 .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1)) 124 .addText("FRI") 125 .addTitleText("68\u00B0")) 126 .build(); 127 } 128 129 private Slice createGallery(Uri sliceUri) { 130 return new ListBuilder(getContext(), sliceUri) 131 .setColor(0xff4285F4) 132 .addRow(b -> b 133 .setTitle("Family trip to Hawaii") 134 .setSubtitle("Sep 30, 2017 - Oct 2, 2017") 135 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_cast), 136 getBroadcastIntent(ACTION_TOAST, "cast photo album")) 137 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_share), 138 getBroadcastIntent(ACTION_TOAST, "share photo album"))) 139 .addGrid(b -> b 140 .addCell(cb -> cb 141 .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_1))) 142 .addCell(cb -> cb 143 .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_2))) 144 .addCell(cb -> cb 145 .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_3))) 146 .addCell(cb -> cb 147 .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_4)))) 148 .build(); 149 } 150 151 private Slice createContact(Uri sliceUri) { 152 return new ListBuilder(getContext(), sliceUri) 153 .setColor(0xff3949ab) 154 .addRow(b -> b 155 .setTitle("Mady Pitza") 156 .setSubtitle("Frequently contacted contact") 157 .setIsHeader(true) 158 .addEndItem(Icon.createWithResource(getContext(), R.drawable.mady))) 159 .addGrid(b -> b 160 .addCell(cb -> cb 161 .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call)) 162 .addText("Call") 163 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call"))) 164 .addCell(cb -> cb 165 .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text)) 166 .addText("Text") 167 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text"))) 168 .addCell(cb ->cb 169 .addImage(Icon.createWithResource(getContext(), R.drawable.ic_video)) 170 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video")) 171 .addText("Video")) 172 .addCell(cb -> cb 173 .addImage(Icon.createWithResource(getContext(), R.drawable.ic_email)) 174 .addText("Email") 175 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email")))) 176 .build(); 177 } 178 179 private Slice createMessagingSlice(Uri sliceUri) { 180 // TODO: Remote input. 181 return new MessagingSliceBuilder(getContext(), sliceUri) 182 .add(b -> b 183 .addText("yo home \uD83C\uDF55, I emailed you the info") 184 .addTimestamp(System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS) 185 .addSource(Icon.createWithResource(getContext(), R.drawable.mady))) 186 .add(b -> b 187 .addText("just bought my tickets") 188 .addTimestamp(System.currentTimeMillis() - 10 * DateUtils.MINUTE_IN_MILLIS)) 189 .add(b -> b 190 .addText("yay! can't wait for getContext() weekend!\n" 191 + "\uD83D\uDE00") 192 .addTimestamp(System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS) 193 .addSource(Icon.createWithResource(getContext(), R.drawable.mady))) 194 .build(); 195 196 } 197 198 private Slice createNoteSlice(Uri sliceUri) { 199 // TODO: Remote input. 200 return new ListBuilder(getContext(), sliceUri) 201 .setColor(0xfff4b400) 202 .addRow(b -> b 203 .setTitle("Create new note") 204 .setSubtitle("with this note taking app") 205 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_create), 206 getBroadcastIntent(ACTION_TOAST, "create note")) 207 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_voice), 208 getBroadcastIntent(ACTION_TOAST, "voice note")) 209 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_camera), 210 getIntent("android.media.action.IMAGE_CAPTURE"))) 211 .build(); 212 } 213 214 private Slice createReservationSlice(Uri sliceUri) { 215 return new ListBuilder(getContext(), sliceUri) 216 .setColor(0xffFF5252) 217 .addRow(b -> b 218 .setTitle("Upcoming trip to Seattle") 219 .setSubtitle("Feb 1 - 19 | 2 guests") 220 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_location), 221 getBroadcastIntent(ACTION_TOAST, "show reservation location on map")) 222 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_text), 223 getBroadcastIntent(ACTION_TOAST, "contact host"))) 224 .addGrid(b -> b 225 .addCell(cb -> cb 226 .addLargeImage( 227 Icon.createWithResource(getContext(), R.drawable.reservation)))) 228 .addGrid(b -> b 229 .addCell(cb -> cb 230 .addTitleText("Check In") 231 .addText("12:00 PM, Feb 1")) 232 .addCell(cb -> cb 233 .addTitleText("Check Out") 234 .addText("11:00 AM, Feb 19"))) 235 .build(); 236 } 237 238 private Slice createRideSlice(Uri sliceUri) { 239 final ForegroundColorSpan colorSpan = new ForegroundColorSpan(0xff0F9D58); 240 SpannableString headerSubtitle = new SpannableString("Ride in 4 min"); 241 headerSubtitle.setSpan(colorSpan, 8, headerSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE); 242 SpannableString homeSubtitle = new SpannableString("12 miles | 12 min | $9.00"); 243 homeSubtitle.setSpan(colorSpan, 20, homeSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE); 244 SpannableString workSubtitle = new SpannableString("44 miles | 1 hour 45 min | $31.41"); 245 workSubtitle.setSpan(colorSpan, 27, workSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE); 246 247 return new ListBuilder(getContext(), sliceUri) 248 .setColor(0xff0F9D58) 249 .addSummaryRow(b -> b 250 .setTitle("Get ride") 251 .setSubtitle(headerSubtitle) 252 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_home), 253 getBroadcastIntent(ACTION_TOAST, "home")) 254 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_work), 255 getBroadcastIntent(ACTION_TOAST, "work"))) 256 .addRow(b -> b 257 .setTitle("Work") 258 .setSubtitle(workSubtitle) 259 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_work), 260 getBroadcastIntent(ACTION_TOAST, "work"))) 261 .addRow(b -> b 262 .setTitle("Home") 263 .setSubtitle("2 hours 33 min via 101") 264 .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_home), 265 getBroadcastIntent(ACTION_TOAST, "home"))) 266 .build(); 267 } 268 269 private Slice createCustomToggleSlice(Uri sliceUri) { 270 return new ListBuilder(getContext(), sliceUri) 271 .setColor(0xffff4081) 272 .addRow(b -> b 273 .setTitle("Custom toggle") 274 .setSubtitle("It can support two states") 275 .addToggle(getBroadcastIntent(ACTION_TOAST, "star toggled"), 276 true /* isChecked */, 277 Icon.createWithResource(getContext(), R.drawable.toggle_star))) 278 .build(); 279 } 280 281 private Slice createTwoCustomToggleSlices(Uri sliceUri) { 282 return new ListBuilder(getContext(), sliceUri) 283 .setColor(0xffff4081) 284 .addRow(b -> b 285 .setTitle("2 toggles") 286 .setSubtitle("each supports two states") 287 .addToggle(getBroadcastIntent(ACTION_TOAST, "first star toggled"), 288 true /* isChecked */, 289 Icon.createWithResource(getContext(), R.drawable.toggle_star)) 290 .addToggle(getBroadcastIntent(ACTION_TOAST, "second star toggled"), 291 false /* isChecked */, 292 Icon.createWithResource(getContext(), R.drawable.toggle_star))) 293 .build(); 294 } 295 296 private Slice createWifiSlice(Uri sliceUri) { 297 // Get wifi state 298 WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); 299 int wifiState = wifiManager.getWifiState(); 300 boolean wifiEnabled = false; 301 String state; 302 switch (wifiState) { 303 case WifiManager.WIFI_STATE_DISABLED: 304 case WifiManager.WIFI_STATE_DISABLING: 305 state = "disconnected"; 306 break; 307 case WifiManager.WIFI_STATE_ENABLED: 308 case WifiManager.WIFI_STATE_ENABLING: 309 state = wifiManager.getConnectionInfo().getSSID(); 310 wifiEnabled = true; 311 break; 312 case WifiManager.WIFI_STATE_UNKNOWN: 313 default: 314 state = ""; // just don't show anything? 315 break; 316 } 317 boolean finalWifiEnabled = wifiEnabled; 318 return new ListBuilder(getContext(), sliceUri) 319 .setColor(0xff4285f4) 320 .addRow(b -> b 321 .setTitle("Wi-fi") 322 .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi)) 323 .setSubtitle(state) 324 .addToggle(getBroadcastIntent(ACTION_WIFI_CHANGED, null), finalWifiEnabled) 325 .setContentIntent(getIntent(Settings.ACTION_WIFI_SETTINGS))) 326 .build(); 327 } 328 329 private PendingIntent getIntent(String action) { 330 Intent intent = new Intent(action); 331 PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0); 332 return pi; 333 } 334 335 private PendingIntent getBroadcastIntent(String action, String message) { 336 Intent intent = new Intent(action); 337 intent.setClass(getContext(), SliceBroadcastReceiver.class); 338 // Ensure a new PendingIntent is created for each message. 339 int requestCode = 0; 340 if (message != null) { 341 intent.putExtra(EXTRA_TOAST_MESSAGE, message); 342 requestCode = message.hashCode(); 343 } 344 return PendingIntent.getBroadcast(getContext(), requestCode, intent, 345 PendingIntent.FLAG_UPDATE_CURRENT); 346 } 347} 348