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 package androidx.slice.widget;
17 
18 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
19 
20 import android.content.Context;
21 import android.content.Intent;
22 import android.net.Uri;
23 import android.os.AsyncTask;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.RestrictTo;
27 import androidx.collection.ArraySet;
28 import androidx.lifecycle.LiveData;
29 import androidx.slice.Slice;
30 import androidx.slice.SliceManager;
31 import androidx.slice.SliceSpec;
32 import androidx.slice.SliceSpecs;
33 
34 import java.util.Arrays;
35 import java.util.Set;
36 
37 /**
38  * Class with factory methods for creating LiveData that observes slices.
39  *
40  * @see #fromUri(Context, Uri)
41  * @see LiveData
42  */
43 public final class SliceLiveData {
44 
45     /**
46      * @hide
47      */
48     @RestrictTo(LIBRARY)
49     public static final SliceSpec OLD_BASIC = new SliceSpec("androidx.app.slice.BASIC", 1);
50 
51     /**
52      * @hide
53      */
54     @RestrictTo(LIBRARY)
55     public static final SliceSpec OLD_LIST = new SliceSpec("androidx.app.slice.LIST", 1);
56 
57     /**
58      * @hide
59      */
60     @RestrictTo(LIBRARY)
61     public static final Set<SliceSpec> SUPPORTED_SPECS = new ArraySet<>(
62             Arrays.asList(SliceSpecs.BASIC, SliceSpecs.LIST, OLD_BASIC, OLD_LIST));
63 
64     /**
65      * Produces an {@link LiveData} that tracks a Slice for a given Uri. To use
66      * this method your app must have the permission to the slice Uri.
67      */
fromUri(Context context, Uri uri)68     public static LiveData<Slice> fromUri(Context context, Uri uri) {
69         return new SliceLiveDataImpl(context.getApplicationContext(), uri);
70     }
71 
72     /**
73      * Produces an {@link LiveData} that tracks a Slice for a given Intent. To use
74      * this method your app must have the permission to the slice Uri.
75      */
fromIntent(@onNull Context context, @NonNull Intent intent)76     public static LiveData<Slice> fromIntent(@NonNull Context context, @NonNull Intent intent) {
77         return new SliceLiveDataImpl(context.getApplicationContext(), intent);
78     }
79 
80     private static class SliceLiveDataImpl extends LiveData<Slice> {
81         private final Intent mIntent;
82         private final SliceManager mSliceManager;
83         private Uri mUri;
84 
SliceLiveDataImpl(Context context, Uri uri)85         private SliceLiveDataImpl(Context context, Uri uri) {
86             super();
87             mSliceManager = SliceManager.getInstance(context);
88             mUri = uri;
89             mIntent = null;
90             // TODO: Check if uri points at a Slice?
91         }
92 
SliceLiveDataImpl(Context context, Intent intent)93         private SliceLiveDataImpl(Context context, Intent intent) {
94             super();
95             mSliceManager = SliceManager.getInstance(context);
96             mUri = null;
97             mIntent = intent;
98         }
99 
100         @Override
onActive()101         protected void onActive() {
102             AsyncTask.execute(mUpdateSlice);
103             if (mUri != null) {
104                 mSliceManager.registerSliceCallback(mUri, mSliceCallback);
105             }
106         }
107 
108         @Override
onInactive()109         protected void onInactive() {
110             if (mUri != null) {
111                 mSliceManager.unregisterSliceCallback(mUri, mSliceCallback);
112             }
113         }
114 
115         private final Runnable mUpdateSlice = new Runnable() {
116             @Override
117             public void run() {
118                 Slice s = mUri != null ? mSliceManager.bindSlice(mUri)
119                         : mSliceManager.bindSlice(mIntent);
120                 if (mUri == null && s != null) {
121                     mUri = s.getUri();
122                     mSliceManager.registerSliceCallback(mUri, mSliceCallback);
123                 }
124                 postValue(s);
125             }
126         };
127 
128         private final SliceManager.SliceCallback mSliceCallback = new SliceManager.SliceCallback() {
129             @Override
130             public void onSliceUpdated(@NonNull Slice s) {
131                 postValue(s);
132             }
133         };
134     }
135 
SliceLiveData()136     private SliceLiveData() {
137     }
138 }
139