1 /* 2 * Copyright (C) 2015 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 package com.android.settings.notification; 17 18 import static android.app.NotificationManager.IMPORTANCE_NONE; 19 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; 20 21 import android.app.INotificationManager; 22 import android.app.NotificationChannel; 23 import android.app.NotificationChannelGroup; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageInfo; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ParceledListSlice; 30 import android.graphics.drawable.Drawable; 31 import android.os.ServiceManager; 32 import android.os.UserHandle; 33 import android.service.notification.NotifyingApp; 34 import android.util.IconDrawableFactory; 35 import android.util.Log; 36 37 import com.android.internal.annotations.VisibleForTesting; 38 import com.android.settingslib.Utils; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 43 public class NotificationBackend { 44 private static final String TAG = "NotificationBackend"; 45 46 static INotificationManager sINM = INotificationManager.Stub.asInterface( 47 ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 48 49 public AppRow loadAppRow(Context context, PackageManager pm, ApplicationInfo app) { 50 final AppRow row = new AppRow(); 51 row.pkg = app.packageName; 52 row.uid = app.uid; 53 try { 54 row.label = app.loadLabel(pm); 55 } catch (Throwable t) { 56 Log.e(TAG, "Error loading application label for " + row.pkg, t); 57 row.label = row.pkg; 58 } 59 row.icon = IconDrawableFactory.newInstance(context).getBadgedIcon(app); 60 row.banned = getNotificationsBanned(row.pkg, row.uid); 61 row.showBadge = canShowBadge(row.pkg, row.uid); 62 row.userId = UserHandle.getUserId(row.uid); 63 row.blockedChannelCount = getBlockedChannelCount(row.pkg, row.uid); 64 row.channelCount = getChannelCount(row.pkg, row.uid); 65 return row; 66 } 67 68 public AppRow loadAppRow(Context context, PackageManager pm, PackageInfo app) { 69 final AppRow row = loadAppRow(context, pm, app.applicationInfo); 70 recordCanBeBlocked(context, pm, app, row); 71 return row; 72 } 73 74 void recordCanBeBlocked(Context context, PackageManager pm, PackageInfo app, AppRow row) { 75 row.systemApp = Utils.isSystemPackage(context.getResources(), pm, app); 76 final String[] nonBlockablePkgs = context.getResources().getStringArray( 77 com.android.internal.R.array.config_nonBlockableNotificationPackages); 78 markAppRowWithBlockables(nonBlockablePkgs, row, app.packageName); 79 } 80 81 @VisibleForTesting static void markAppRowWithBlockables(String[] nonBlockablePkgs, AppRow row, 82 String packageName) { 83 if (nonBlockablePkgs != null) { 84 int N = nonBlockablePkgs.length; 85 for (int i = 0; i < N; i++) { 86 String pkg = nonBlockablePkgs[i]; 87 if (pkg == null) { 88 continue; 89 } else if (pkg.contains(":")) { 90 // Interpret as channel; lock only this channel for this app. 91 if (packageName.equals(pkg.split(":", 2)[0])) { 92 row.lockedChannelId = pkg.split(":", 2 )[1]; 93 } 94 } else if (packageName.equals(nonBlockablePkgs[i])) { 95 row.systemApp = row.lockedImportance = true; 96 } 97 } 98 } 99 } 100 101 public boolean isSystemApp(Context context, ApplicationInfo app) { 102 try { 103 PackageInfo info = context.getPackageManager().getPackageInfo( 104 app.packageName, PackageManager.GET_SIGNATURES); 105 final AppRow row = new AppRow(); 106 recordCanBeBlocked(context, context.getPackageManager(), info, row); 107 return row.systemApp; 108 } catch (PackageManager.NameNotFoundException e) { 109 e.printStackTrace(); 110 } 111 return false; 112 } 113 114 public boolean getNotificationsBanned(String pkg, int uid) { 115 try { 116 final boolean enabled = sINM.areNotificationsEnabledForPackage(pkg, uid); 117 return !enabled; 118 } catch (Exception e) { 119 Log.w(TAG, "Error calling NoMan", e); 120 return false; 121 } 122 } 123 124 public boolean setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 125 try { 126 if (onlyHasDefaultChannel(pkg, uid)) { 127 NotificationChannel defaultChannel = 128 getChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID); 129 defaultChannel.setImportance(enabled ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_NONE); 130 updateChannel(pkg, uid, defaultChannel); 131 } 132 sINM.setNotificationsEnabledForPackage(pkg, uid, enabled); 133 return true; 134 } catch (Exception e) { 135 Log.w(TAG, "Error calling NoMan", e); 136 return false; 137 } 138 } 139 140 public boolean canShowBadge(String pkg, int uid) { 141 try { 142 return sINM.canShowBadge(pkg, uid); 143 } catch (Exception e) { 144 Log.w(TAG, "Error calling NoMan", e); 145 return false; 146 } 147 } 148 149 public boolean setShowBadge(String pkg, int uid, boolean showBadge) { 150 try { 151 sINM.setShowBadge(pkg, uid, showBadge); 152 return true; 153 } catch (Exception e) { 154 Log.w(TAG, "Error calling NoMan", e); 155 return false; 156 } 157 } 158 159 public NotificationChannel getChannel(String pkg, int uid, String channelId) { 160 if (channelId == null) { 161 return null; 162 } 163 try { 164 return sINM.getNotificationChannelForPackage(pkg, uid, channelId, true); 165 } catch (Exception e) { 166 Log.w(TAG, "Error calling NoMan", e); 167 return null; 168 } 169 } 170 171 public NotificationChannelGroup getGroup(String pkg, int uid, String groupId) { 172 if (groupId == null) { 173 return null; 174 } 175 try { 176 return sINM.getNotificationChannelGroupForPackage(groupId, pkg, uid); 177 } catch (Exception e) { 178 Log.w(TAG, "Error calling NoMan", e); 179 return null; 180 } 181 } 182 183 public ParceledListSlice<NotificationChannelGroup> getGroups(String pkg, int uid) { 184 try { 185 return sINM.getNotificationChannelGroupsForPackage(pkg, uid, false); 186 } catch (Exception e) { 187 Log.w(TAG, "Error calling NoMan", e); 188 return ParceledListSlice.emptyList(); 189 } 190 } 191 192 public void updateChannel(String pkg, int uid, NotificationChannel channel) { 193 try { 194 sINM.updateNotificationChannelForPackage(pkg, uid, channel); 195 } catch (Exception e) { 196 Log.w(TAG, "Error calling NoMan", e); 197 } 198 } 199 200 public void updateChannelGroup(String pkg, int uid, NotificationChannelGroup group) { 201 try { 202 sINM.updateNotificationChannelGroupForPackage(pkg, uid, group); 203 } catch (Exception e) { 204 Log.w(TAG, "Error calling NoMan", e); 205 } 206 } 207 208 public int getDeletedChannelCount(String pkg, int uid) { 209 try { 210 return sINM.getDeletedChannelCount(pkg, uid); 211 } catch (Exception e) { 212 Log.w(TAG, "Error calling NoMan", e); 213 return 0; 214 } 215 } 216 217 public int getBlockedChannelCount(String pkg, int uid) { 218 try { 219 return sINM.getBlockedChannelCount(pkg, uid); 220 } catch (Exception e) { 221 Log.w(TAG, "Error calling NoMan", e); 222 return 0; 223 } 224 } 225 226 public boolean onlyHasDefaultChannel(String pkg, int uid) { 227 try { 228 return sINM.onlyHasDefaultChannel(pkg, uid); 229 } catch (Exception e) { 230 Log.w(TAG, "Error calling NoMan", e); 231 return false; 232 } 233 } 234 235 public int getChannelCount(String pkg, int uid) { 236 try { 237 return sINM.getNumNotificationChannelsForPackage(pkg, uid, false); 238 } catch (Exception e) { 239 Log.w(TAG, "Error calling NoMan", e); 240 return 0; 241 } 242 } 243 244 public List<NotifyingApp> getRecentApps() { 245 try { 246 return sINM.getRecentNotifyingAppsForUser(UserHandle.myUserId()).getList(); 247 } catch (Exception e) { 248 Log.w(TAG, "Error calling NoMan", e); 249 return new ArrayList<>(); 250 } 251 } 252 253 public int getBlockedAppCount() { 254 try { 255 return sINM.getBlockedAppCount(UserHandle.myUserId()); 256 } catch (Exception e) { 257 Log.w(TAG, "Error calling NoMan", e); 258 return 0; 259 } 260 } 261 262 static class Row { 263 public String section; 264 } 265 266 public static class AppRow extends Row { 267 public String pkg; 268 public int uid; 269 public Drawable icon; 270 public CharSequence label; 271 public Intent settingsIntent; 272 public boolean banned; 273 public boolean first; // first app in section 274 public boolean systemApp; 275 public boolean lockedImportance; 276 public String lockedChannelId; 277 public boolean showBadge; 278 public int userId; 279 public int blockedChannelCount; 280 public int channelCount; 281 } 282 } 283