1 /*
2  * Copyright (C) 2023 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.TileUtils.META_DATA_PREFERENCE_KEYHINT;
20 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
21 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
22 
23 import android.content.ContentProvider;
24 import android.content.ContentValues;
25 import android.content.Context;
26 import android.content.pm.ProviderInfo;
27 import android.database.Cursor;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.text.TextUtils;
31 import android.util.Log;
32 
33 import java.util.ArrayList;
34 import java.util.LinkedHashMap;
35 import java.util.List;
36 import java.util.Map;
37 
38 /**
39  * An abstract class for injecting entries to Settings.
40  */
41 public abstract class EntriesProvider extends ContentProvider {
42     private static final String TAG = "EntriesProvider";
43 
44     public static final String METHOD_GET_ENTRY_DATA = "getEntryData";
45     public static final String METHOD_GET_PROVIDER_ICON = "getProviderIcon";
46     public static final String METHOD_GET_DYNAMIC_TITLE = "getDynamicTitle";
47     public static final String METHOD_GET_DYNAMIC_SUMMARY = "getDynamicSummary";
48     public static final String METHOD_IS_CHECKED = "isChecked";
49     public static final String METHOD_ON_CHECKED_CHANGED = "onCheckedChanged";
50 
51     /**
52      * @deprecated use {@link #METHOD_GET_ENTRY_DATA} instead.
53      */
54     @Deprecated
55     public static final String METHOD_GET_SWITCH_DATA = "getSwitchData";
56 
57     public static final String EXTRA_ENTRY_DATA = "entry_data";
58     public static final String EXTRA_SWITCH_CHECKED_STATE = "checked_state";
59     public static final String EXTRA_SWITCH_SET_CHECKED_ERROR = "set_checked_error";
60     public static final String EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE = "set_checked_error_message";
61 
62     /**
63      * @deprecated use {@link #EXTRA_ENTRY_DATA} instead.
64      */
65     @Deprecated
66     public static final String EXTRA_SWITCH_DATA = "switch_data";
67 
68     private String mAuthority;
69     private final Map<String, EntryController> mControllerMap = new LinkedHashMap<>();
70     private final List<Bundle> mEntryDataList = new ArrayList<>();
71 
72     /**
73      * Get a list of {@link EntryController} for this provider.
74      */
createEntryControllers()75     protected abstract List<? extends EntryController> createEntryControllers();
76 
getController(String key)77     protected EntryController getController(String key) {
78         return mControllerMap.get(key);
79     }
80 
81     @Override
attachInfo(Context context, ProviderInfo info)82     public void attachInfo(Context context, ProviderInfo info) {
83         mAuthority = info.authority;
84         Log.i(TAG, mAuthority);
85         super.attachInfo(context, info);
86     }
87 
88     @Override
onCreate()89     public boolean onCreate() {
90         final List<? extends EntryController> controllers = createEntryControllers();
91         if (controllers == null || controllers.isEmpty()) {
92             throw new IllegalArgumentException();
93         }
94 
95         for (EntryController controller : controllers) {
96             final String key = controller.getKey();
97             if (TextUtils.isEmpty(key)) {
98                 throw new NullPointerException("Entry key cannot be null: "
99                         + controller.getClass().getSimpleName());
100             } else if (mControllerMap.containsKey(key)) {
101                 throw new IllegalArgumentException("Entry key " + key + " is duplicated by: "
102                         + controller.getClass().getSimpleName());
103             }
104 
105             controller.setAuthority(mAuthority);
106             mControllerMap.put(key, controller);
107             if (!(controller instanceof PrimarySwitchController)) {
108                 mEntryDataList.add(controller.getBundle());
109             }
110         }
111         return true;
112     }
113 
114     @Override
call(String method, String uriString, Bundle extras)115     public Bundle call(String method, String uriString, Bundle extras) {
116         final Bundle bundle = new Bundle();
117         final String key = extras != null
118                 ? extras.getString(META_DATA_PREFERENCE_KEYHINT)
119                 : null;
120         if (TextUtils.isEmpty(key)) {
121             switch (method) {
122                 case METHOD_GET_ENTRY_DATA:
123                     bundle.putParcelableList(EXTRA_ENTRY_DATA, mEntryDataList);
124                     return bundle;
125                 case METHOD_GET_SWITCH_DATA:
126                     bundle.putParcelableList(EXTRA_SWITCH_DATA, mEntryDataList);
127                     return bundle;
128                 default:
129                     return null;
130             }
131         }
132 
133         final EntryController controller = mControllerMap.get(key);
134         if (controller == null) {
135             return null;
136         }
137 
138         switch (method) {
139             case METHOD_GET_ENTRY_DATA:
140             case METHOD_GET_SWITCH_DATA:
141                 if (!(controller instanceof PrimarySwitchController)) {
142                     return controller.getBundle();
143                 }
144                 break;
145             case METHOD_GET_PROVIDER_ICON:
146                 if (controller instanceof ProviderIcon) {
147                     return ((ProviderIcon) controller).getProviderIcon();
148                 }
149                 break;
150             case METHOD_GET_DYNAMIC_TITLE:
151                 if (controller instanceof DynamicTitle) {
152                     bundle.putString(META_DATA_PREFERENCE_TITLE,
153                             ((DynamicTitle) controller).getDynamicTitle());
154                     return bundle;
155                 }
156                 break;
157             case METHOD_GET_DYNAMIC_SUMMARY:
158                 if (controller instanceof DynamicSummary) {
159                     bundle.putString(META_DATA_PREFERENCE_SUMMARY,
160                             ((DynamicSummary) controller).getDynamicSummary());
161                     return bundle;
162                 }
163                 break;
164             case METHOD_IS_CHECKED:
165                 if (controller instanceof ProviderSwitch) {
166                     bundle.putBoolean(EXTRA_SWITCH_CHECKED_STATE,
167                             ((ProviderSwitch) controller).isSwitchChecked());
168                     return bundle;
169                 }
170                 break;
171             case METHOD_ON_CHECKED_CHANGED:
172                 if (controller instanceof ProviderSwitch) {
173                     return onSwitchCheckedChanged(extras.getBoolean(EXTRA_SWITCH_CHECKED_STATE),
174                             (ProviderSwitch) controller);
175                 }
176                 break;
177         }
178         return null;
179     }
180 
onSwitchCheckedChanged(boolean checked, ProviderSwitch controller)181     private Bundle onSwitchCheckedChanged(boolean checked, ProviderSwitch controller) {
182         final boolean success = controller.onSwitchCheckedChanged(checked);
183         final Bundle bundle = new Bundle();
184         bundle.putBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR, !success);
185         if (success) {
186             if (controller instanceof DynamicSummary) {
187                 ((EntryController) controller).notifySummaryChanged(getContext());
188             }
189         } else {
190             bundle.putString(EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE,
191                     controller.getSwitchErrorMessage(checked));
192         }
193         return bundle;
194     }
195 
196     @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)197     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
198             String sortOrder) {
199         throw new UnsupportedOperationException();
200     }
201 
202     @Override
getType(Uri uri)203     public String getType(Uri uri) {
204         throw new UnsupportedOperationException();
205     }
206 
207     @Override
insert(Uri uri, ContentValues values)208     public Uri insert(Uri uri, ContentValues values) {
209         throw new UnsupportedOperationException();
210     }
211 
212     @Override
delete(Uri uri, String selection, String[] selectionArgs)213     public int delete(Uri uri, String selection, String[] selectionArgs) {
214         throw new UnsupportedOperationException();
215     }
216 
217     @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)218     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
219         throw new UnsupportedOperationException();
220     }
221 }
222 
223