Home | History | Annotate | Download | only in notification
      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