SampleSliceProvider.java revision 87a9bf551f300ae379245a3edcb836f628439237
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                        .addEndItem(Icon.createWithResource(getContext(), R.drawable.mady)))
158                .addGrid(b -> b
159                        .addCell(cb -> cb
160                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call))
161                            .addText("Call")
162                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call")))
163                        .addCell(cb -> cb
164                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text))
165                            .addText("Text")
166                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text")))
167                        .addCell(cb ->cb
168                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_video))
169                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video"))
170                            .addText("Video"))
171                        .addCell(cb -> cb
172                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_email))
173                            .addText("Email")
174                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email"))))
175                .build();
176    }
177
178    private Slice createMessagingSlice(Uri sliceUri) {
179        // TODO: Remote input.
180        return new MessagingSliceBuilder(getContext(), sliceUri)
181                .add(b -> b
182                        .addText("yo home \uD83C\uDF55, I emailed you the info")
183                        .addTimestamp(System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS)
184                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
185                .add(b -> b
186                        .addText("just bought my tickets")
187                        .addTimestamp(System.currentTimeMillis() - 10 * DateUtils.MINUTE_IN_MILLIS))
188                .add(b -> b
189                        .addText("yay! can't wait for getContext() weekend!\n"
190                                + "\uD83D\uDE00")
191                        .addTimestamp(System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS)
192                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
193                .build();
194
195    }
196
197    private Slice createNoteSlice(Uri sliceUri) {
198        // TODO: Remote input.
199        return new ListBuilder(getContext(), sliceUri)
200                .setColor(0xfff4b400)
201                .addRow(b -> b
202                    .setTitle("Create new note")
203                    .setSubtitle("with this note taking app")
204                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_create),
205                            getBroadcastIntent(ACTION_TOAST, "create note"))
206                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_voice),
207                            getBroadcastIntent(ACTION_TOAST, "voice note"))
208                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_camera),
209                            getIntent("android.media.action.IMAGE_CAPTURE")))
210                .build();
211    }
212
213    private Slice createReservationSlice(Uri sliceUri) {
214        return new ListBuilder(getContext(), sliceUri)
215                .setColor(0xffFF5252)
216                .addRow(b -> b
217                    .setTitle("Upcoming trip to Seattle")
218                    .setSubtitle("Feb 1 - 19 | 2 guests")
219                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_location),
220                            getBroadcastIntent(ACTION_TOAST, "show reservation location on map"))
221                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_text),
222                            getBroadcastIntent(ACTION_TOAST, "contact host")))
223                .addGrid(b -> b
224                    .addCell(cb -> cb
225                        .addLargeImage(
226                                Icon.createWithResource(getContext(), R.drawable.reservation))))
227                .addGrid(b -> b
228                    .addCell(cb -> cb
229                        .addTitleText("Check In")
230                        .addText("12:00 PM, Feb 1"))
231                    .addCell(cb -> cb
232                        .addTitleText("Check Out")
233                        .addText("11:00 AM, Feb 19")))
234                .build();
235    }
236
237    private Slice createRideSlice(Uri sliceUri) {
238        final ForegroundColorSpan colorSpan = new ForegroundColorSpan(0xff0F9D58);
239        SpannableString headerSubtitle = new SpannableString("Ride in 4 min");
240        headerSubtitle.setSpan(colorSpan, 8, headerSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
241        SpannableString homeSubtitle = new SpannableString("12 miles | 12 min | $9.00");
242        homeSubtitle.setSpan(colorSpan, 20, homeSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
243        SpannableString workSubtitle = new SpannableString("44 miles | 1 hour 45 min | $31.41");
244        workSubtitle.setSpan(colorSpan, 27, workSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
245
246        return new ListBuilder(getContext(), sliceUri)
247                .setColor(0xff0F9D58)
248                .addRow(b -> b
249                    .setContentIntent(getBroadcastIntent(ACTION_TOAST, "work"))
250                    .setTitle("Work")
251                    .setSubtitle(workSubtitle)
252                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_work),
253                            getBroadcastIntent(ACTION_TOAST, "work")))
254                .addRow(b -> b
255                    .setContentIntent(getBroadcastIntent(ACTION_TOAST, "home"))
256                    .setTitle("Home")
257                    .setSubtitle(homeSubtitle)
258                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_home),
259                            getBroadcastIntent(ACTION_TOAST, "home")))
260                .build();
261    }
262
263    private Slice createCustomToggleSlice(Uri sliceUri) {
264        return new ListBuilder(getContext(), sliceUri)
265                .setColor(0xffff4081)
266                .addRow(b -> b
267                    .setTitle("Custom toggle")
268                    .setSubtitle("It can support two states")
269                    .addToggle(getBroadcastIntent(ACTION_TOAST, "star toggled"),
270                            true /* isChecked */,
271                            Icon.createWithResource(getContext(), R.drawable.toggle_star)))
272                .build();
273    }
274
275    private Slice createTwoCustomToggleSlices(Uri sliceUri) {
276        return new ListBuilder(getContext(), sliceUri)
277                .setColor(0xffff4081)
278                .addRow(b -> b
279                        .setTitle("2 toggles")
280                        .setSubtitle("each supports two states")
281                        .addToggle(getBroadcastIntent(ACTION_TOAST, "first star toggled"),
282                                true /* isChecked */,
283                                Icon.createWithResource(getContext(), R.drawable.toggle_star))
284                        .addToggle(getBroadcastIntent(ACTION_TOAST, "second star toggled"),
285                                false /* isChecked */,
286                                Icon.createWithResource(getContext(), R.drawable.toggle_star)))
287                .build();
288    }
289
290    private Slice createWifiSlice(Uri sliceUri) {
291        // Get wifi state
292        WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
293        int wifiState = wifiManager.getWifiState();
294        boolean wifiEnabled = false;
295        String state;
296        switch (wifiState) {
297            case WifiManager.WIFI_STATE_DISABLED:
298            case WifiManager.WIFI_STATE_DISABLING:
299                state = "disconnected";
300                break;
301            case WifiManager.WIFI_STATE_ENABLED:
302            case WifiManager.WIFI_STATE_ENABLING:
303                state = wifiManager.getConnectionInfo().getSSID();
304                wifiEnabled = true;
305                break;
306            case WifiManager.WIFI_STATE_UNKNOWN:
307            default:
308                state = ""; // just don't show anything?
309                break;
310        }
311        boolean finalWifiEnabled = wifiEnabled;
312        return new ListBuilder(getContext(), sliceUri)
313                .setColor(0xff4285f4)
314                .addRow(b -> b
315                    .setTitle("Wi-fi")
316                    .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi))
317                    .setSubtitle(state)
318                    .addToggle(getBroadcastIntent(ACTION_WIFI_CHANGED, null), finalWifiEnabled)
319                    .setContentIntent(getIntent(Settings.ACTION_WIFI_SETTINGS)))
320            .build();
321    }
322
323    private PendingIntent getIntent(String action) {
324        Intent intent = new Intent(action);
325        PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
326        return pi;
327    }
328
329    private PendingIntent getBroadcastIntent(String action, String message) {
330        Intent intent = new Intent(action);
331        intent.setClass(getContext(), SliceBroadcastReceiver.class);
332        // Ensure a new PendingIntent is created for each message.
333        int requestCode = 0;
334        if (message != null) {
335            intent.putExtra(EXTRA_TOAST_MESSAGE, message);
336            requestCode = message.hashCode();
337        }
338        return PendingIntent.getBroadcast(getContext(), requestCode, intent,
339                PendingIntent.FLAG_UPDATE_CURRENT);
340    }
341}
342