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