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.settings.notification;
18 
19 import android.app.settings.SettingsEnums;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.pm.PackageItemInfo;
23 import android.content.pm.PackageManager;
24 import android.content.pm.ServiceInfo;
25 import android.graphics.drawable.Drawable;
26 import android.os.RemoteException;
27 import android.provider.SearchIndexableResource;
28 import android.provider.Settings;
29 import android.service.notification.NotificationAssistantService;
30 import android.text.TextUtils;
31 import android.util.Log;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.settings.R;
35 import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
36 import com.android.settings.search.BaseSearchIndexProvider;
37 import com.android.settings.search.Indexable;
38 import com.android.settingslib.applications.DefaultAppInfo;
39 import com.android.settingslib.applications.ServiceListing;
40 import com.android.settingslib.widget.CandidateInfo;
41 
42 import java.util.ArrayList;
43 import java.util.List;
44 
45 public class NotificationAssistantPicker extends DefaultAppPickerFragment implements
46         ServiceListing.Callback {
47 
48     private static final String TAG = "NotiAssistantPicker";
49 
50     @VisibleForTesting
51     protected NotificationBackend mNotificationBackend;
52     private List<CandidateInfo> mCandidateInfos = new ArrayList<>();
53     @VisibleForTesting
54     protected Context mContext;
55     private ServiceListing mServiceListing;
56 
57     @Override
onAttach(Context context)58     public void onAttach(Context context) {
59         super.onAttach(context);
60         mContext = context;
61         mNotificationBackend = new NotificationBackend();
62         mServiceListing = new ServiceListing.Builder(context)
63                 .setTag(TAG)
64                 .setSetting(Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT)
65                 .setIntentAction(NotificationAssistantService.SERVICE_INTERFACE)
66                 .setPermission(android.Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE)
67                 .setNoun("notification assistant")
68                 .build();
69         mServiceListing.addCallback(this);
70         mServiceListing.reload();
71     }
72 
73     @Override
onDetach()74     public void onDetach() {
75         super.onDetach();
76         mServiceListing.removeCallback(this);
77     }
78 
79     @Override
getPreferenceScreenResId()80     protected int getPreferenceScreenResId() {
81         return R.xml.notification_assistant_settings;
82     }
83 
84     @Override
getCandidates()85     protected List<? extends CandidateInfo> getCandidates() {
86         return mCandidateInfos;
87     }
88 
89     @Override
getDefaultKey()90     protected String getDefaultKey() {
91         ComponentName cn = mNotificationBackend.getAllowedNotificationAssistant();
92         return (cn != null) ? cn.flattenToString() : "";
93     }
94 
95     @Override
setDefaultKey(String key)96     protected boolean setDefaultKey(String key) {
97         return mNotificationBackend.setNotificationAssistantGranted(
98                 ComponentName.unflattenFromString(key));
99     }
100 
101     @Override
getMetricsCategory()102     public int getMetricsCategory() {
103         return SettingsEnums.DEFAULT_NOTIFICATION_ASSISTANT;
104     }
105 
106     @Override
getConfirmationMessage(CandidateInfo info)107     protected CharSequence getConfirmationMessage(CandidateInfo info) {
108         if (TextUtils.isEmpty(info.getKey())) {
109             return null;
110         }
111         return mContext.getString(R.string.notification_assistant_security_warning_summary,
112                 info.loadLabel());
113     }
114 
115     @Override
onServicesReloaded(List<ServiceInfo> services)116     public void onServicesReloaded(List<ServiceInfo> services) {
117         List<CandidateInfo> list = new ArrayList<>();
118         services.sort(new PackageItemInfo.DisplayNameComparator(mPm));
119         for (ServiceInfo service : services) {
120             if (mContext.getPackageManager().checkPermission(
121                     android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE,
122                     service.packageName) == PackageManager.PERMISSION_GRANTED) {
123                 final ComponentName cn = new ComponentName(service.packageName, service.name);
124                 list.add(new DefaultAppInfo(mContext, mPm, mUserId, cn));
125             }
126         }
127         list.add(new CandidateNone(mContext));
128         mCandidateInfos = list;
129     }
130 
131     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
132             new BaseSearchIndexProvider() {
133                 @Override
134                 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
135                         boolean enabled) {
136                     final List<SearchIndexableResource> result = new ArrayList<>();
137 
138                     final SearchIndexableResource sir = new SearchIndexableResource(context);
139                     sir.xmlResId = R.xml.notification_assistant_settings;
140                     result.add(sir);
141                     return result;
142                 }
143             };
144 
145     public static class CandidateNone extends CandidateInfo {
146 
147         public Context mContext;
148 
CandidateNone(Context context)149         public CandidateNone(Context context) {
150             super(true);
151             mContext = context;
152         }
153 
154         @Override
loadLabel()155         public CharSequence loadLabel() {
156             return mContext.getString(R.string.no_notification_assistant);
157         }
158 
159         @Override
loadIcon()160         public Drawable loadIcon() {
161             return null;
162         }
163 
164         @Override
getKey()165         public String getKey() {
166             return "";
167         }
168     }
169 }
170