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