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 */
16package androidx.slice.widget;
17
18import static androidx.annotation.RestrictTo.Scope.LIBRARY;
19
20import android.content.Context;
21import android.content.Intent;
22import android.net.Uri;
23import android.os.AsyncTask;
24
25import androidx.annotation.NonNull;
26import androidx.annotation.RestrictTo;
27import androidx.collection.ArraySet;
28import androidx.lifecycle.LiveData;
29import androidx.slice.Slice;
30import androidx.slice.SliceManager;
31import androidx.slice.SliceSpec;
32import androidx.slice.SliceSpecs;
33
34import java.util.Arrays;
35import 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 */
43public 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     */
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     */
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
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
93        private SliceLiveDataImpl(Context context, Intent intent) {
94            super();
95            mSliceManager = SliceManager.getInstance(context);
96            mUri = null;
97            mIntent = intent;
98        }
99
100        @Override
101        protected void onActive() {
102            AsyncTask.execute(mUpdateSlice);
103            if (mUri != null) {
104                mSliceManager.registerSliceCallback(mUri, mSliceCallback);
105            }
106        }
107
108        @Override
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
136    private SliceLiveData() {
137    }
138}
139