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