Listener.java revision 2989ef25fd6c380bec0f35c509dc2341691d7f5f
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.example.notificationlistener; 17 18 19import android.app.Notification; 20import android.app.PendingIntent; 21import android.content.BroadcastReceiver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.os.Handler; 26import android.os.Message; 27import android.service.notification.NotificationListenerService; 28import android.service.notification.StatusBarNotification; 29import android.support.v4.content.LocalBroadcastManager; 30import android.text.TextUtils; 31import android.util.Log; 32 33import java.util.ArrayList; 34import java.util.Arrays; 35import java.util.Collections; 36import java.util.Comparator; 37import java.util.List; 38 39public class Listener extends NotificationListenerService { 40 private static final String TAG = "SampleListener"; 41 42 // Message tags 43 private static final int MSG_NOTIFY = 1; 44 private static final int MSG_CANCEL = 2; 45 private static final int MSG_STARTUP = 3; 46 private static final int MSG_ORDER = 4; 47 private static final int MSG_DISMISS = 5; 48 private static final int MSG_LAUNCH = 6; 49 private static final int PAGE = 10; 50 51 static final String ACTION_DISMISS = "com.android.example.notificationlistener.DISMISS"; 52 static final String ACTION_LAUNCH = "com.android.example.notificationlistener.LAUNCH"; 53 static final String ACTION_REFRESH = "com.android.example.notificationlistener.REFRESH"; 54 static final String EXTRA_KEY = "key"; 55 56 private static ArrayList<StatusBarNotification> sNotifications; 57 58 public static List<StatusBarNotification> getNotifications() { 59 return sNotifications; 60 } 61 62 private class Delta { 63 final StatusBarNotification mSbn; 64 final Ranking mRanking; 65 66 public Delta(StatusBarNotification sbn, Ranking update) { 67 mSbn = sbn; 68 mRanking = update; 69 } 70 } 71 72 private final Comparator<StatusBarNotification> mRankingComparator = 73 new Comparator<StatusBarNotification>() { 74 @Override 75 public int compare(StatusBarNotification lhs, StatusBarNotification rhs) { 76 return Integer.compare(mRanking.getIndexOfKey(lhs.getKey()), 77 mRanking.getIndexOfKey(rhs.getKey())); 78 } 79 }; 80 81 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 82 @Override 83 public void onReceive(Context context, Intent intent) { 84 String key = intent.getStringExtra(EXTRA_KEY); 85 int what = MSG_DISMISS; 86 if (ACTION_LAUNCH.equals(intent.getAction())) { 87 what = MSG_LAUNCH; 88 } 89 Log.d(TAG, "received an action broadcast " + intent.getAction()); 90 if (!TextUtils.isEmpty(key)) { 91 Log.d(TAG, " on " + key); 92 Message.obtain(mHandler, what, key).sendToTarget(); 93 } 94 } 95 }; 96 97 private final Handler mHandler = new Handler() { 98 @Override 99 public void handleMessage(Message msg) { 100 Delta delta = null; 101 if (msg.obj instanceof Delta) { 102 delta = (Delta) msg.obj; 103 } 104 switch (msg.what) { 105 case MSG_NOTIFY: 106 Log.i(TAG, "notify: " + delta.mSbn.getKey()); 107 synchronized (sNotifications) { 108 int position = mRanking.getIndexOfKey(delta.mSbn.getKey()); 109 if (position == -1) { 110 sNotifications.add(delta.mSbn); 111 } else { 112 sNotifications.set(position, delta.mSbn); 113 } 114 mRanking = delta.mRanking; 115 Collections.sort(sNotifications, mRankingComparator); 116 Log.i(TAG, "finish with: " + sNotifications.size()); 117 } 118 LocalBroadcastManager.getInstance(Listener.this) 119 .sendBroadcast(new Intent(ACTION_REFRESH) 120 .putExtra(EXTRA_KEY, delta.mSbn.getKey())); 121 break; 122 123 case MSG_CANCEL: 124 Log.i(TAG, "remove: " + delta.mSbn.getKey()); 125 synchronized (sNotifications) { 126 int position = mRanking.getIndexOfKey(delta.mSbn.getKey()); 127 if (position != -1) { 128 sNotifications.remove(position); 129 } 130 mRanking = delta.mRanking; 131 Collections.sort(sNotifications, mRankingComparator); 132 } 133 LocalBroadcastManager.getInstance(Listener.this) 134 .sendBroadcast(new Intent(ACTION_REFRESH)); 135 break; 136 137 case MSG_ORDER: 138 Log.i(TAG, "reorder"); 139 synchronized (sNotifications) { 140 mRanking = delta.mRanking; 141 Collections.sort(sNotifications, mRankingComparator); 142 } 143 LocalBroadcastManager.getInstance(Listener.this) 144 .sendBroadcast(new Intent(ACTION_REFRESH)); 145 break; 146 147 case MSG_STARTUP: 148 fetchActive(); 149 Log.i(TAG, "start with: " + sNotifications.size() + " notifications."); 150 LocalBroadcastManager.getInstance(Listener.this) 151 .sendBroadcast(new Intent(ACTION_REFRESH)); 152 break; 153 154 case MSG_DISMISS: 155 if (msg.obj instanceof String) { 156 final String key = (String) msg.obj; 157 StatusBarNotification sbn = sNotifications.get(mRanking.getIndexOfKey(key)); 158 if ((sbn.getNotification().flags & Notification.FLAG_AUTO_CANCEL) != 0 && 159 sbn.getNotification().contentIntent != null) { 160 try { 161 sbn.getNotification().contentIntent.send(); 162 } catch (PendingIntent.CanceledException e) { 163 Log.d(TAG, "failed to send intent for " + sbn.getKey(), e); 164 } 165 } 166 cancelNotification(key); 167 } 168 break; 169 170 case MSG_LAUNCH: 171 if (msg.obj instanceof String) { 172 final String key = (String) msg.obj; 173 StatusBarNotification sbn = sNotifications.get(mRanking.getIndexOfKey(key)); 174 if (sbn.getNotification().contentIntent != null) { 175 try { 176 sbn.getNotification().contentIntent.send(); 177 } catch (PendingIntent.CanceledException e) { 178 Log.d(TAG, "failed to send intent for " + sbn.getKey(), e); 179 } 180 } 181 if ((sbn.getNotification().flags & Notification.FLAG_AUTO_CANCEL) != 0) { 182 cancelNotification(key); 183 } 184 } 185 break; 186 } 187 } 188 }; 189 190 private Ranking mRanking; 191 192 @Override 193 public void onCreate() { 194 super.onCreate(); 195 Log.d(TAG, "registering broadcast listener"); 196 final IntentFilter intentFilter = new IntentFilter(); 197 intentFilter.addAction(ACTION_DISMISS); 198 intentFilter.addAction(ACTION_LAUNCH); 199 LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, intentFilter); 200 } 201 202 @Override 203 public void onDestroy() { 204 LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); 205 super.onDestroy(); 206 } 207 208 @Override 209 public void onListenerConnected(String[] notificationKeys) { 210 Message.obtain(mHandler, MSG_STARTUP).sendToTarget(); 211 } 212 213 @Override 214 public void onNotificationRankingUpdate() { 215 Message.obtain(mHandler, MSG_ORDER, 216 new Delta(null, getCurrentRanking())).sendToTarget(); 217 } 218 219 @Override 220 public void onNotificationPosted(StatusBarNotification sbn) { 221 Message.obtain(mHandler, MSG_NOTIFY, 222 new Delta(sbn, getCurrentRanking())).sendToTarget(); 223 } 224 225 @Override 226 public void onNotificationRemoved(StatusBarNotification sbn) { 227 Message.obtain(mHandler, MSG_CANCEL, 228 new Delta(sbn, getCurrentRanking())).sendToTarget(); 229 } 230 231 private void fetchActive() { 232 mRanking = getCurrentRanking(); 233 String[] keys = mRanking.getOrderedKeys(); 234 sNotifications = new ArrayList<StatusBarNotification>(); 235 sNotifications.clear(); 236 for (int i = 0; i < keys.length; i += PAGE) { 237 final int j = (i + PAGE < keys.length ? i + PAGE : keys.length); 238 String[] fetchKeys = Arrays.copyOfRange(keys, i, j); 239 StatusBarNotification[] sbns = getActiveNotifications(fetchKeys); 240 for(int s = 0; s < sbns.length; s++) { 241 // unfortunately cloneLight() is hidden 242 sNotifications.add(sbns[s]); 243 } 244 } 245 Collections.sort(sNotifications, mRankingComparator); 246 } 247} 248