blob: 346e9c39c4cdbfaec414101d349440f81e961427 [file] [log] [blame]
Jason Monk698ad8c2017-11-10 10:31:19 -05001/*
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 */
16package androidx.app.slice.widget;
17
Jason Monk698ad8c2017-11-10 10:31:19 -050018import android.arch.lifecycle.LiveData;
Jason Monka09cb672018-01-08 13:17:36 -050019import android.content.ContentProvider;
Jason Monk698ad8c2017-11-10 10:31:19 -050020import android.content.Context;
Jason Monked974952017-11-27 13:48:04 -050021import android.content.Intent;
Jason Monk698ad8c2017-11-10 10:31:19 -050022import android.database.ContentObserver;
23import android.net.Uri;
24import android.os.AsyncTask;
25import android.os.Handler;
Jason Monked974952017-11-27 13:48:04 -050026import android.support.annotation.NonNull;
Jason Monka09cb672018-01-08 13:17:36 -050027import android.support.annotation.Nullable;
28import android.support.annotation.RestrictTo;
Jason Monk698ad8c2017-11-10 10:31:19 -050029
Jason Monk6fa0c9b2017-12-12 20:55:35 -050030import java.util.Arrays;
31import java.util.List;
32
Jason Monkdcb5e2f2017-11-15 20:19:43 -050033import androidx.app.slice.Slice;
Jason Monk6fa0c9b2017-12-12 20:55:35 -050034import androidx.app.slice.SliceSpec;
Jason Monka09cb672018-01-08 13:17:36 -050035import androidx.app.slice.SliceSpecs;
Jason Monk0c76d302017-11-21 14:02:27 -050036
Jason Monk698ad8c2017-11-10 10:31:19 -050037/**
38 * Class with factory methods for creating LiveData that observes slices.
39 *
40 * @see #fromUri(Context, Uri)
41 * @see LiveData
42 */
43public final class SliceLiveData {
44
Jason Monka09cb672018-01-08 13:17:36 -050045 private static final List<SliceSpec> SUPPORTED_SPECS = Arrays.asList(SliceSpecs.BASIC,
Mady Mellorc7791012018-01-16 17:25:01 -080046 SliceSpecs.LIST);
Jason Monka09cb672018-01-08 13:17:36 -050047
48 /**
49 * Turns a slice Uri into slice content.
50 *
51 * @param context Context to be used.
52 * @param uri The URI to a slice provider
53 * @return The Slice provided by the app or null if none is given.
54 * @see Slice
55 * @hide
56 */
57 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
58 public static @Nullable Slice bindSlice(Context context, @NonNull Uri uri) {
59 return Slice.bindSlice(context, uri, SUPPORTED_SPECS);
60 }
61
62
63 /**
64 * Turns a slice intent into slice content. Expects an explicit intent. If there is no
65 * {@link ContentProvider} associated with the given intent this will throw
66 * {@link IllegalArgumentException}.
67 *
68 * @param context The context to use.
69 * @param intent The intent associated with a slice.
70 * @return The Slice provided by the app or null if none is given.
71 * @see Slice
72 * @see androidx.app.slice.SliceProvider#onMapIntentToUri(Intent)
73 * @see Intent
74 * @hide
75 */
76 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
77 public static @Nullable Slice bindSlice(Context context, @NonNull Intent intent) {
78 return Slice.bindSlice(context, intent, SUPPORTED_SPECS);
79 }
Jason Monk6fa0c9b2017-12-12 20:55:35 -050080
Jason Monk698ad8c2017-11-10 10:31:19 -050081 /**
82 * Produces an {@link LiveData} that tracks a Slice for a given Uri. To use
83 * this method your app must have the permission to the slice Uri or hold
84 * {@link android.Manifest.permission#BIND_SLICE}).
85 */
86 public static LiveData<Slice> fromUri(Context context, Uri uri) {
87 return new SliceLiveDataImpl(context.getApplicationContext(), uri);
88 }
89
Jason Monked974952017-11-27 13:48:04 -050090 /**
91 * Produces an {@link LiveData} that tracks a Slice for a given Intent. To use
92 * this method your app must have the permission to the slice Uri or hold
93 * {@link android.Manifest.permission#BIND_SLICE}).
94 */
95 public static LiveData<Slice> fromIntent(@NonNull Context context, @NonNull Intent intent) {
96 return new SliceLiveDataImpl(context.getApplicationContext(), intent);
97 }
98
Jason Monk698ad8c2017-11-10 10:31:19 -050099 private static class SliceLiveDataImpl extends LiveData<Slice> {
Jason Monk698ad8c2017-11-10 10:31:19 -0500100 private final Context mContext;
Jason Monked974952017-11-27 13:48:04 -0500101 private final Intent mIntent;
102 private Uri mUri;
Jason Monk698ad8c2017-11-10 10:31:19 -0500103
104 private SliceLiveDataImpl(Context context, Uri uri) {
105 super();
106 mContext = context;
107 mUri = uri;
Jason Monked974952017-11-27 13:48:04 -0500108 mIntent = null;
Jason Monk698ad8c2017-11-10 10:31:19 -0500109 // TODO: Check if uri points at a Slice?
110 }
111
Jason Monked974952017-11-27 13:48:04 -0500112 private SliceLiveDataImpl(Context context, Intent intent) {
113 super();
114 mContext = context;
115 mUri = null;
116 mIntent = intent;
117 }
118
Jason Monk698ad8c2017-11-10 10:31:19 -0500119 @Override
120 protected void onActive() {
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500121 AsyncTask.execute(mUpdateSlice);
Jason Monked974952017-11-27 13:48:04 -0500122 if (mUri != null) {
123 mContext.getContentResolver().registerContentObserver(mUri, false, mObserver);
124 }
Jason Monk698ad8c2017-11-10 10:31:19 -0500125 }
126
127 @Override
128 protected void onInactive() {
Jason Monked974952017-11-27 13:48:04 -0500129 if (mUri != null) {
130 mContext.getContentResolver().unregisterContentObserver(mObserver);
131 }
Jason Monk698ad8c2017-11-10 10:31:19 -0500132 }
133
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500134 private final Runnable mUpdateSlice = new Runnable() {
135 @Override
136 public void run() {
Jason Monka09cb672018-01-08 13:17:36 -0500137 Slice s = mUri != null ? Slice.bindSlice(mContext, mUri, SUPPORTED_SPECS)
138 : Slice.bindSlice(mContext, mIntent, SUPPORTED_SPECS);
Jason Monked974952017-11-27 13:48:04 -0500139 if (mUri == null && s != null) {
140 mContext.getContentResolver().registerContentObserver(s.getUri(),
141 false, mObserver);
142 mUri = s.getUri();
143 }
144 postValue(s);
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500145 }
146 };
Jason Monk698ad8c2017-11-10 10:31:19 -0500147
148 private final ContentObserver mObserver = new ContentObserver(new Handler()) {
149 @Override
150 public void onChange(boolean selfChange) {
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500151 AsyncTask.execute(mUpdateSlice);
Jason Monk698ad8c2017-11-10 10:31:19 -0500152 }
153 };
154 }
155}