• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 
17 package com.android.settings.slices;
18 
19 import android.app.PendingIntent;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.net.Uri;
23 
24 import androidx.slice.Slice;
25 
26 import java.lang.reflect.Constructor;
27 import java.lang.reflect.InvocationTargetException;
28 
29 
30 /**
31  * Common functions for custom Slices.
32  * <p>
33  *     A template for all Settings slices which are not represented by a Preference. By
34  *     standardizing the methods used by the Slice helpers, we can use generically take actions
35  *     rather than maintaining a list of all of the custom slices every time we reference Slices in
36  *     Settings.
37  * <p>
38  *     By default, all Slices in Settings should be built through Preference Controllers extending
39  *     {@link com.android.settings.core.BasePreferenceController}, which are automatically piped
40  *     into Settings-Slices infrastructure. Cases where you should implement this interface are:
41  *     <ul>
42  *         <li>Multi-line slices</li>
43  *         <li>Slices that don't exist in the UI</li>
44  *         <li>Preferences that use a supported component, like a Switch Bar</li>
45  *     </ul>
46  * <p>
47  *      Note that if your UI is supported because the Preference is not backed by a
48  *      {@link com.android.settings.dashboard.DashboardFragment}, then you should first convert the
49  *      existing fragment into a dashboard fragment, and then extend
50  *      {@link com.android.settings.core.BasePreferenceController}.
51  * <p>
52  *     If you implement this interface, you should add your Slice to {@link CustomSliceManager}.
53  */
54 public interface CustomSliceable extends Sliceable {
55 
56     /**
57      * The color representing not to be tinted for the slice.
58      */
59     int COLOR_NOT_TINTED = -1;
60 
61     /**
62      * @return an complete instance of the {@link Slice}.
63      */
getSlice()64     Slice getSlice();
65 
66     /**
67      * @return a {@link android.content.ContentResolver#SCHEME_CONTENT content} {@link Uri} which
68      * backs the {@link Slice} returned by {@link #getSlice()}.
69      */
getUri()70     Uri getUri();
71 
72     /**
73      * Handles the actions sent by the {@link Intent intents} bound to the {@link Slice} returned by
74      * {@link #getSlice()}.
75      *
76      * @param intent which has the action taken on a {@link Slice}.
77      */
onNotifyChange(Intent intent)78     default void onNotifyChange(Intent intent) {}
79 
80     /**
81      * @return an {@link Intent} to the source of the Slice data.
82      */
getIntent()83     Intent getIntent();
84 
85     /**
86      * Standardize the intents returned to indicate actions by the Slice.
87      * <p>
88      *     The {@link PendingIntent} is linked to {@link SliceBroadcastReceiver} where the Intent
89      *     Action is found by {@code getUri().toString()}.
90      *
91      * @return a {@link PendingIntent} linked to {@link SliceBroadcastReceiver}.
92      */
getBroadcastIntent(Context context)93     default PendingIntent getBroadcastIntent(Context context) {
94         final Intent intent = new Intent(getUri().toString())
95                 .setData(getUri())
96                 .setClass(context, SliceBroadcastReceiver.class);
97         return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
98                 PendingIntent.FLAG_CANCEL_CURRENT);
99     }
100 
101     @Override
isSliceable()102     default boolean isSliceable() {
103         return true;
104     }
105 
106     /**
107      * Build an instance of a {@link CustomSliceable} which has a {@link Context}-only constructor.
108      */
createInstance(Context context, Class<? extends CustomSliceable> sliceable)109     static CustomSliceable createInstance(Context context,
110             Class<? extends CustomSliceable> sliceable) {
111         try {
112             final Constructor<? extends CustomSliceable> constructor =
113                     sliceable.getConstructor(Context.class);
114             final Object[] params = new Object[]{context.getApplicationContext()};
115             return constructor.newInstance(params);
116         } catch (NoSuchMethodException | InstantiationException |
117                 IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
118             throw new IllegalStateException(
119                     "Invalid sliceable class: " + sliceable, e);
120         }
121     }
122 }