1 /*
2  * Copyright (C) 2021 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.car.settings.qc;
18 
19 import android.content.Context;
20 import android.net.Uri;
21 import android.util.ArrayMap;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.VisibleForTesting;
25 
26 import com.android.car.qc.QCItem;
27 import com.android.car.qc.provider.BaseQCProvider;
28 import com.android.car.settings.R;
29 import com.android.settingslib.utils.ThreadUtils;
30 
31 import java.util.Map;
32 import java.util.Set;
33 
34 /**
35  * Remote Quick Control provider for CarSettings.
36  */
37 public class SettingsQCProvider extends BaseQCProvider {
38     private final Map<Uri, SettingsQCItem> mSubscribedItems = new ArrayMap<>();
39     @VisibleForTesting
40     final Map<Uri, SettingsQCBackgroundWorker> mSubscribedWorkers = new ArrayMap<>();
41 
42     private Set<String> mAllowListedPackages;
43 
44     @Override
onCreate()45     public boolean onCreate() {
46         boolean returnVal = super.onCreate();
47         mAllowListedPackages = Set.of(getContext().getResources().getStringArray(
48                 R.array.settings_qc_provider_package_allowlist));
49         return returnVal;
50     }
51 
52     @Override
onBind(Uri uri)53     public QCItem onBind(Uri uri) {
54         if (SettingsQCRegistry.isValidUri(uri)) {
55             Context context = getContext();
56             return getQCItemFromUri(context, uri).getQCItem();
57         }
58         throw new IllegalArgumentException("Unrecognized uri: " + uri);
59     }
60 
61     @Override
onSubscribed(Uri uri)62     public void onSubscribed(Uri uri) {
63         if (SettingsQCRegistry.isValidUri(uri)) {
64             Context context = getContext();
65             SettingsQCItem qcItem = getQCItemFromUri(context, uri);
66             ThreadUtils.postOnMainThread(() -> startBackgroundWorker(qcItem, uri));
67         }
68     }
69 
70     @Override
onUnsubscribed(Uri uri)71     public void onUnsubscribed(Uri uri) {
72         ThreadUtils.postOnMainThread(() -> stopBackgroundWorker(uri));
73     }
74 
75     @Override
onDestroy(Uri uri)76     public void onDestroy(Uri uri) {
77         ThreadUtils.postOnMainThread(() -> SettingsQCBackgroundWorker.shutdown(uri));
78     }
79 
80     @Override
shutdown()81     public void shutdown() {
82         ThreadUtils.postOnMainThread(SettingsQCBackgroundWorker::shutdown);
83     }
84 
getQCItemFromUri(Context context, Uri uri)85     private SettingsQCItem getQCItemFromUri(Context context, Uri uri) {
86         if (mSubscribedItems.containsKey(uri)) {
87             return mSubscribedItems.get(uri);
88         }
89         Uri newUri = SettingsQCRegistry.removeParameterFromUri(uri);
90         Class clazz = SettingsQCRegistry.getQCClassByUri(newUri);
91         if (clazz == null) {
92             throw new IllegalArgumentException("No QCItem found for uri: " + uri);
93         }
94 
95         return SettingsQCItem.createInstance(context, clazz);
96     }
97 
startBackgroundWorker(SettingsQCItem qcItem, Uri uri)98     private void startBackgroundWorker(SettingsQCItem qcItem, Uri uri) {
99         Class workerClass = qcItem.getBackgroundWorkerClass();
100         if (workerClass == null) {
101             return;
102         }
103 
104         if (mSubscribedWorkers.containsKey(uri)) {
105             return;
106         }
107 
108         SettingsQCBackgroundWorker worker = SettingsQCBackgroundWorker.getInstance(
109                 getContext(), qcItem, uri);
110         mSubscribedWorkers.put(uri, worker);
111         worker.subscribe();
112         mSubscribedItems.put(uri, qcItem);
113     }
114 
stopBackgroundWorker(Uri uri)115     private void stopBackgroundWorker(Uri uri) {
116         SettingsQCBackgroundWorker worker = mSubscribedWorkers.get(uri);
117         if (worker != null) {
118             worker.unsubscribe();
119             mSubscribedWorkers.remove(uri);
120             mSubscribedItems.remove(uri);
121         }
122     }
123 
124     @NonNull
125     @Override
getAllowlistedPackages()126     protected Set<String> getAllowlistedPackages() {
127         return mAllowListedPackages;
128     }
129 }
130