RankingHelper.java revision cf7ed583080b6c958f5a02817110505bae2a17df
1/** 2 * Copyright (c) 2014, 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 */ 16package com.android.server.notification; 17 18import android.app.Notification; 19import android.content.Context; 20import android.os.Handler; 21import android.os.Message; 22import android.os.UserHandle; 23import android.text.TextUtils; 24import android.util.ArrayMap; 25import android.util.Log; 26import android.util.Slog; 27import android.util.SparseIntArray; 28import org.xmlpull.v1.XmlPullParser; 29import org.xmlpull.v1.XmlPullParserException; 30import org.xmlpull.v1.XmlSerializer; 31 32import java.io.IOException; 33import java.io.PrintWriter; 34import java.util.ArrayList; 35import java.util.Collections; 36import java.util.concurrent.TimeUnit; 37 38public class RankingHelper implements RankingConfig { 39 private static final String TAG = "RankingHelper"; 40 private static final boolean DEBUG = false; 41 42 private static final int XML_VERSION = 1; 43 44 private static final String TAG_RANKING = "ranking"; 45 private static final String TAG_PACKAGE = "package"; 46 private static final String ATT_VERSION = "version"; 47 48 private static final String ATT_NAME = "name"; 49 private static final String ATT_UID = "uid"; 50 private static final String ATT_PRIORITY = "priority"; 51 52 private static final String VALUE_HIGH = "high"; 53 54 private final NotificationSignalExtractor[] mSignalExtractors; 55 private final NotificationComparator mRankingComparator = new NotificationComparator(); 56 57 // Package name to uid, to priority. Would be better as Table<String, Int, Int> 58 private final ArrayMap<String, SparseIntArray> mPackagePriorities; 59 60 private final Context mContext; 61 private final Handler mRankingHandler; 62 63 public RankingHelper(Context context, Handler rankingHandler, String[] extractorNames) { 64 mContext = context; 65 mRankingHandler = rankingHandler; 66 mPackagePriorities = new ArrayMap<String, SparseIntArray>(); 67 68 final int N = extractorNames.length; 69 mSignalExtractors = new NotificationSignalExtractor[N]; 70 for (int i = 0; i < N; i++) { 71 try { 72 Class<?> extractorClass = mContext.getClassLoader().loadClass(extractorNames[i]); 73 NotificationSignalExtractor extractor = 74 (NotificationSignalExtractor) extractorClass.newInstance(); 75 extractor.initialize(mContext); 76 extractor.setConfig(this); 77 mSignalExtractors[i] = extractor; 78 } catch (ClassNotFoundException e) { 79 Slog.w(TAG, "Couldn't find extractor " + extractorNames[i] + ".", e); 80 } catch (InstantiationException e) { 81 Slog.w(TAG, "Couldn't instantiate extractor " + extractorNames[i] + ".", e); 82 } catch (IllegalAccessException e) { 83 Slog.w(TAG, "Problem accessing extractor " + extractorNames[i] + ".", e); 84 } 85 } 86 } 87 88 public void extractSignals(NotificationRecord r) { 89 final int N = mSignalExtractors.length; 90 for (int i = 0; i < N; i++) { 91 NotificationSignalExtractor extractor = mSignalExtractors[i]; 92 try { 93 RankingReconsideration recon = extractor.process(r); 94 if (recon != null) { 95 Message m = Message.obtain(mRankingHandler, 96 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 97 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 98 mRankingHandler.sendMessageDelayed(m, delay); 99 } 100 } catch (Throwable t) { 101 Slog.w(TAG, "NotificationSignalExtractor failed.", t); 102 } 103 } 104 } 105 106 public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException { 107 int type = parser.getEventType(); 108 if (type != XmlPullParser.START_TAG) return; 109 String tag = parser.getName(); 110 if (!TAG_RANKING.equals(tag)) return; 111 mPackagePriorities.clear(); 112 final int version = safeInt(parser, ATT_VERSION, XML_VERSION); 113 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 114 tag = parser.getName(); 115 if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) { 116 return; 117 } 118 if (type == XmlPullParser.START_TAG) { 119 if (TAG_PACKAGE.equals(tag)) { 120 int uid = safeInt(parser, ATT_UID, UserHandle.USER_ALL); 121 int priority = safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT); 122 String name = parser.getAttributeValue(null, ATT_NAME); 123 124 if (!TextUtils.isEmpty(name) && priority != Notification.PRIORITY_DEFAULT) { 125 SparseIntArray priorityByUid = mPackagePriorities.get(name); 126 if (priorityByUid == null) { 127 priorityByUid = new SparseIntArray(); 128 mPackagePriorities.put(name, priorityByUid); 129 } 130 priorityByUid.put(uid, priority); 131 } 132 } 133 } 134 } 135 throw new IllegalStateException("Failed to reach END_DOCUMENT"); 136 } 137 138 public void writeXml(XmlSerializer out) throws IOException { 139 out.startTag(null, TAG_RANKING); 140 out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION)); 141 142 final int N = mPackagePriorities.size(); 143 for (int i = 0; i < N; i ++) { 144 String name = mPackagePriorities.keyAt(i); 145 SparseIntArray priorityByUid = mPackagePriorities.get(name); 146 final int M = priorityByUid.size(); 147 for (int j = 0; j < M; j++) { 148 int uid = priorityByUid.keyAt(j); 149 int priority = priorityByUid.get(uid); 150 out.startTag(null, TAG_PACKAGE); 151 out.attribute(null, ATT_NAME, name); 152 out.attribute(null, ATT_UID, Integer.toString(uid)); 153 out.attribute(null, ATT_PRIORITY, Integer.toString(priority)); 154 out.endTag(null, TAG_PACKAGE); 155 } 156 } 157 out.endTag(null, TAG_RANKING); 158 } 159 160 private void updateConfig() { 161 final int N = mSignalExtractors.length; 162 for (int i = 0; i < N; i++) { 163 mSignalExtractors[i].setConfig(this); 164 } 165 mRankingHandler.sendEmptyMessage(NotificationManagerService.MESSAGE_RANKING_CONFIG_CHANGE); 166 } 167 168 public void sort(ArrayList<NotificationRecord> notificationList) { 169 Collections.sort(notificationList, mRankingComparator); 170 } 171 172 public int indexOf(ArrayList<NotificationRecord> notificationList, NotificationRecord target) { 173 return Collections.binarySearch(notificationList, target, mRankingComparator); 174 } 175 176 private static int safeInt(XmlPullParser parser, String att, int defValue) { 177 final String val = parser.getAttributeValue(null, att); 178 return tryParseInt(val, defValue); 179 } 180 181 private static int tryParseInt(String value, int defValue) { 182 if (TextUtils.isEmpty(value)) return defValue; 183 try { 184 return Integer.valueOf(value); 185 } catch (NumberFormatException e) { 186 return defValue; 187 } 188 } 189 190 @Override 191 public int getPackagePriority(String packageName, int uid) { 192 int priority = Notification.PRIORITY_DEFAULT; 193 SparseIntArray priorityByUid = mPackagePriorities.get(packageName); 194 if (priorityByUid != null) { 195 priority = priorityByUid.get(uid, Notification.PRIORITY_DEFAULT); 196 } 197 return priority; 198 } 199 200 @Override 201 public void setPackagePriority(String packageName, int uid, int priority) { 202 if (priority == getPackagePriority(packageName, uid)) { 203 return; 204 } 205 SparseIntArray priorityByUid = mPackagePriorities.get(packageName); 206 if (priorityByUid == null) { 207 priorityByUid = new SparseIntArray(); 208 mPackagePriorities.put(packageName, priorityByUid); 209 } 210 priorityByUid.put(uid, priority); 211 updateConfig(); 212 } 213 214 public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) { 215 if (filter == null) { 216 final int N = mSignalExtractors.length; 217 pw.print(prefix); 218 pw.print("mSignalExtractors.length = "); 219 pw.println(N); 220 for (int i = 0; i < N; i++) { 221 pw.print(prefix); 222 pw.print(" "); 223 pw.println(mSignalExtractors[i]); 224 } 225 } 226 final int N = mPackagePriorities.size(); 227 if (filter == null) { 228 pw.print(prefix); 229 pw.println("package priorities:"); 230 } 231 for (int i = 0; i < N; i++) { 232 String name = mPackagePriorities.keyAt(i); 233 if (filter == null || filter.matches(name)) { 234 SparseIntArray priorityByUid = mPackagePriorities.get(name); 235 final int M = priorityByUid.size(); 236 for (int j = 0; j < M; j++) { 237 int uid = priorityByUid.keyAt(j); 238 int priority = priorityByUid.get(uid); 239 pw.print(prefix); 240 pw.print(" "); 241 pw.print(name); 242 pw.print(" ("); 243 pw.print(uid); 244 pw.print(") has priority: "); 245 pw.println(priority); 246 } 247 } 248 } 249 } 250} 251