1 /*
2  * Copyright (C) 2019 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.settingslib.drawer;
18 
19 import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_SUMMARY;
20 import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_TITLE;
21 import static com.android.settingslib.drawer.SwitchesProvider.METHOD_IS_CHECKED;
22 import static com.android.settingslib.drawer.TileUtils.EXTRA_CATEGORY_KEY;
23 import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER;
24 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
25 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB;
26 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_HINT;
27 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE;
28 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
29 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
30 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
31 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI;
32 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
33 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
34 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE_URI;
35 
36 import android.content.ContentResolver;
37 import android.content.Context;
38 import android.net.Uri;
39 import android.os.Bundle;
40 
41 import androidx.annotation.DrawableRes;
42 import androidx.annotation.NonNull;
43 import androidx.annotation.StringRes;
44 
45 /**
46  * A controller that manages events for switch.
47  */
48 public abstract class SwitchController {
49 
50     private String mAuthority;
51 
52     /**
53      * Returns the key for this switch.
54      */
getSwitchKey()55     public abstract String getSwitchKey();
56 
57     /**
58      * Returns the {@link MetaData} for this switch.
59      */
getMetaData()60     protected abstract MetaData getMetaData();
61 
62     /**
63      * Returns the checked state of this switch.
64      */
isChecked()65     protected abstract boolean isChecked();
66 
67     /**
68      * Called when the checked state of this switch is changed.
69      *
70      * @return true if the checked state was successfully changed, otherwise false
71      */
onCheckedChanged(boolean checked)72     protected abstract boolean onCheckedChanged(boolean checked);
73 
74     /**
75      * Returns the error message which will be toasted when {@link #onCheckedChanged} returns false.
76      */
getErrorMessage(boolean attemptedChecked)77     protected abstract String getErrorMessage(boolean attemptedChecked);
78 
79     /**
80      * Notify registered observers that title was updated and attempt to sync changes.
81      */
notifyTitleChanged(Context context)82     public void notifyTitleChanged(Context context) {
83         if (this instanceof DynamicTitle) {
84             notifyChanged(context, METHOD_GET_DYNAMIC_TITLE);
85         }
86     }
87 
88     /**
89      * Notify registered observers that summary was updated and attempt to sync changes.
90      */
notifySummaryChanged(Context context)91     public void notifySummaryChanged(Context context) {
92         if (this instanceof DynamicSummary) {
93             notifyChanged(context, METHOD_GET_DYNAMIC_SUMMARY);
94         }
95     }
96 
97     /**
98      * Notify registered observers that checked state was updated and attempt to sync changes.
99      */
notifyCheckedChanged(Context context)100     public void notifyCheckedChanged(Context context) {
101         notifyChanged(context, METHOD_IS_CHECKED);
102     }
103 
setAuthority(String authority)104     void setAuthority(String authority) {
105         mAuthority = authority;
106     }
107 
getBundle()108     Bundle getBundle() {
109         final MetaData metaData = getMetaData();
110         if (metaData == null) {
111             throw new NullPointerException("Should not return null in getMetaData()");
112         }
113 
114         final Bundle bundle = metaData.build();
115         final String uriString = new Uri.Builder()
116                 .scheme(ContentResolver.SCHEME_CONTENT)
117                 .authority(mAuthority)
118                 .build()
119                 .toString();
120         bundle.putString(META_DATA_PREFERENCE_KEYHINT, getSwitchKey());
121         bundle.putString(META_DATA_PREFERENCE_SWITCH_URI, uriString);
122         if (this instanceof ProviderIcon) {
123             bundle.putString(META_DATA_PREFERENCE_ICON_URI, uriString);
124         }
125         if (this instanceof DynamicTitle) {
126             bundle.putString(META_DATA_PREFERENCE_TITLE_URI, uriString);
127         }
128         if (this instanceof DynamicSummary) {
129             bundle.putString(META_DATA_PREFERENCE_SUMMARY_URI, uriString);
130         }
131         return bundle;
132     }
133 
notifyChanged(Context context, String method)134     private void notifyChanged(Context context, String method) {
135         final Uri uri = TileUtils.buildUri(mAuthority, method, getSwitchKey());
136         context.getContentResolver().notifyChange(uri, null);
137     }
138 
139     /**
140      * Collects all meta data of the item.
141      */
142     protected static class MetaData {
143         private String mCategory;
144         private int mOrder;
145         @DrawableRes
146         private int mIcon;
147         private int mIconBackgroundHint;
148         private int mIconBackgroundArgb;
149         private Boolean mIconTintable;
150         @StringRes
151         private int mTitleId;
152         private String mTitle;
153         @StringRes
154         private int mSummaryId;
155         private String mSummary;
156 
157         /**
158          * @param category the category of the switch. This value must be from {@link CategoryKey}.
159          */
MetaData(@onNull String category)160         public MetaData(@NonNull String category) {
161             mCategory = category;
162         }
163 
164         /**
165          * Set the order of the item that should be displayed on screen. Bigger value items displays
166          * closer on top.
167          */
setOrder(int order)168         public MetaData setOrder(int order) {
169             mOrder = order;
170             return this;
171         }
172 
173         /** Set the icon that should be displayed for the item. */
setIcon(@rawableRes int icon)174         public MetaData setIcon(@DrawableRes int icon) {
175             mIcon = icon;
176             return this;
177         }
178 
179         /** Set the icon background color. The value may or may not be used by Settings app. */
setIconBackgoundHint(int hint)180         public MetaData setIconBackgoundHint(int hint) {
181             mIconBackgroundHint = hint;
182             return this;
183         }
184 
185         /** Set the icon background color as raw ARGB. */
setIconBackgoundArgb(int argb)186         public MetaData setIconBackgoundArgb(int argb) {
187             mIconBackgroundArgb = argb;
188             return this;
189         }
190 
191         /** Specify whether the icon is tintable. */
setIconTintable(boolean tintable)192         public MetaData setIconTintable(boolean tintable) {
193             mIconTintable = tintable;
194             return this;
195         }
196 
197         /** Set the title that should be displayed for the item. */
setTitle(@tringRes int id)198         public MetaData setTitle(@StringRes int id) {
199             mTitleId = id;
200             return this;
201         }
202 
203         /** Set the title that should be displayed for the item. */
setTitle(String title)204         public MetaData setTitle(String title) {
205             mTitle = title;
206             return this;
207         }
208 
209         /** Set the summary text that should be displayed for the item. */
setSummary(@tringRes int id)210         public MetaData setSummary(@StringRes int id) {
211             mSummaryId = id;
212             return this;
213         }
214 
215         /** Set the summary text that should be displayed for the item. */
setSummary(String summary)216         public MetaData setSummary(String summary) {
217             mSummary = summary;
218             return this;
219         }
220 
build()221         private Bundle build() {
222             final Bundle bundle = new Bundle();
223             bundle.putString(EXTRA_CATEGORY_KEY, mCategory);
224 
225             if (mOrder != 0) {
226                 bundle.putInt(META_DATA_KEY_ORDER, mOrder);
227             }
228 
229             if (mIcon != 0) {
230                 bundle.putInt(META_DATA_PREFERENCE_ICON, mIcon);
231             }
232             if (mIconBackgroundHint != 0) {
233                 bundle.putInt(META_DATA_PREFERENCE_ICON_BACKGROUND_HINT, mIconBackgroundHint);
234             }
235             if (mIconBackgroundArgb != 0) {
236                 bundle.putInt(META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB, mIconBackgroundArgb);
237             }
238             if (mIconTintable != null) {
239                 bundle.putBoolean(META_DATA_PREFERENCE_ICON_TINTABLE, mIconTintable);
240             }
241 
242             if (mTitleId != 0) {
243                 bundle.putInt(META_DATA_PREFERENCE_TITLE, mTitleId);
244             } else if (mTitle != null) {
245                 bundle.putString(META_DATA_PREFERENCE_TITLE, mTitle);
246             }
247 
248             if (mSummaryId != 0) {
249                 bundle.putInt(META_DATA_PREFERENCE_SUMMARY, mSummaryId);
250             } else if (mSummary != null) {
251                 bundle.putString(META_DATA_PREFERENCE_SUMMARY, mSummary);
252             }
253             return bundle;
254         }
255     }
256 }
257