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