blob: 2f9853e11b38f4712a76a542065ab9b432ecbb79 [file] [log] [blame]
Chris Wrenf715fd92014-05-07 17:44:21 -04001/*
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;
Christoph Studer13900282014-06-06 11:18:52 +020028import android.service.notification.NotificationListenerService.Ranking;
29import android.service.notification.NotificationListenerService.RankingMap;
Chris Wrenf715fd92014-05-07 17:44:21 -040030import android.service.notification.StatusBarNotification;
31import android.support.v4.content.LocalBroadcastManager;
32import android.text.TextUtils;
33import android.util.Log;
34
35import java.util.ArrayList;
Chris Wrenf715fd92014-05-07 17:44:21 -040036import java.util.Collections;
Chris Wrena02d4fd2014-05-07 17:44:21 -040037import java.util.Comparator;
Chris Wrenf715fd92014-05-07 17:44:21 -040038import java.util.List;
39
40public class Listener extends NotificationListenerService {
41 private static final String TAG = "SampleListener";
42
43 // Message tags
44 private static final int MSG_NOTIFY = 1;
45 private static final int MSG_CANCEL = 2;
46 private static final int MSG_STARTUP = 3;
47 private static final int MSG_ORDER = 4;
48 private static final int MSG_DISMISS = 5;
49 private static final int MSG_LAUNCH = 6;
50 private static final int PAGE = 10;
51
52 static final String ACTION_DISMISS = "com.android.example.notificationlistener.DISMISS";
53 static final String ACTION_LAUNCH = "com.android.example.notificationlistener.LAUNCH";
54 static final String ACTION_REFRESH = "com.android.example.notificationlistener.REFRESH";
55 static final String EXTRA_KEY = "key";
56
57 private static ArrayList<StatusBarNotification> sNotifications;
58
59 public static List<StatusBarNotification> getNotifications() {
60 return sNotifications;
61 }
62
Chris Wrenf715fd92014-05-07 17:44:21 -040063 private class Delta {
64 final StatusBarNotification mSbn;
Christoph Studer13900282014-06-06 11:18:52 +020065 final RankingMap mRankingMap;
Chris Wrenf715fd92014-05-07 17:44:21 -040066
Christoph Studer13900282014-06-06 11:18:52 +020067 public Delta(StatusBarNotification sbn, RankingMap rankingMap) {
Chris Wrenf715fd92014-05-07 17:44:21 -040068 mSbn = sbn;
Christoph Studer13900282014-06-06 11:18:52 +020069 mRankingMap = rankingMap;
Chris Wrenf715fd92014-05-07 17:44:21 -040070 }
71 }
72
Chris Wrena02d4fd2014-05-07 17:44:21 -040073 private final Comparator<StatusBarNotification> mRankingComparator =
74 new Comparator<StatusBarNotification>() {
75 @Override
76 public int compare(StatusBarNotification lhs, StatusBarNotification rhs) {
Christoph Studer13900282014-06-06 11:18:52 +020077 Ranking lhsRanking = mRankingMap.getRanking(lhs.getKey());
78 Ranking rhsRanking = mRankingMap.getRanking(rhs.getKey());
79 return Integer.compare(lhsRanking.getRank(), rhsRanking.getRank());
Chris Wrena02d4fd2014-05-07 17:44:21 -040080 }
81 };
82
Chris Wrenf715fd92014-05-07 17:44:21 -040083 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
84 @Override
85 public void onReceive(Context context, Intent intent) {
86 String key = intent.getStringExtra(EXTRA_KEY);
87 int what = MSG_DISMISS;
88 if (ACTION_LAUNCH.equals(intent.getAction())) {
89 what = MSG_LAUNCH;
90 }
91 Log.d(TAG, "received an action broadcast " + intent.getAction());
92 if (!TextUtils.isEmpty(key)) {
93 Log.d(TAG, " on " + key);
94 Message.obtain(mHandler, what, key).sendToTarget();
95 }
96 }
97 };
98
Chris Wrena02d4fd2014-05-07 17:44:21 -040099 private final Handler mHandler = new Handler() {
Chris Wrenf715fd92014-05-07 17:44:21 -0400100 @Override
101 public void handleMessage(Message msg) {
102 Delta delta = null;
103 if (msg.obj instanceof Delta) {
104 delta = (Delta) msg.obj;
105 }
106 switch (msg.what) {
107 case MSG_NOTIFY:
108 Log.i(TAG, "notify: " + delta.mSbn.getKey());
109 synchronized (sNotifications) {
Christoph Studer13900282014-06-06 11:18:52 +0200110 Ranking ranking = mRankingMap.getRanking(delta.mSbn.getKey());
111 if (ranking == null) {
Chris Wrenf715fd92014-05-07 17:44:21 -0400112 sNotifications.add(delta.mSbn);
113 } else {
Christoph Studer13900282014-06-06 11:18:52 +0200114 int position = ranking.getRank();
Chris Wrenf715fd92014-05-07 17:44:21 -0400115 sNotifications.set(position, delta.mSbn);
116 }
Christoph Studer13900282014-06-06 11:18:52 +0200117 mRankingMap = delta.mRankingMap;
Chris Wrena02d4fd2014-05-07 17:44:21 -0400118 Collections.sort(sNotifications, mRankingComparator);
Chris Wrenf715fd92014-05-07 17:44:21 -0400119 Log.i(TAG, "finish with: " + sNotifications.size());
120 }
121 LocalBroadcastManager.getInstance(Listener.this)
122 .sendBroadcast(new Intent(ACTION_REFRESH)
123 .putExtra(EXTRA_KEY, delta.mSbn.getKey()));
124 break;
125
126 case MSG_CANCEL:
127 Log.i(TAG, "remove: " + delta.mSbn.getKey());
128 synchronized (sNotifications) {
Christoph Studer13900282014-06-06 11:18:52 +0200129 Ranking ranking = mRankingMap.getRanking(delta.mSbn.getKey());
130 int position = ranking.getRank();
Chris Wrenf715fd92014-05-07 17:44:21 -0400131 if (position != -1) {
132 sNotifications.remove(position);
133 }
Christoph Studer13900282014-06-06 11:18:52 +0200134 mRankingMap = delta.mRankingMap;
Chris Wrena02d4fd2014-05-07 17:44:21 -0400135 Collections.sort(sNotifications, mRankingComparator);
Chris Wrenf715fd92014-05-07 17:44:21 -0400136 }
137 LocalBroadcastManager.getInstance(Listener.this)
138 .sendBroadcast(new Intent(ACTION_REFRESH));
139 break;
140
141 case MSG_ORDER:
142 Log.i(TAG, "reorder");
143 synchronized (sNotifications) {
Christoph Studer13900282014-06-06 11:18:52 +0200144 mRankingMap = delta.mRankingMap;
Chris Wrena02d4fd2014-05-07 17:44:21 -0400145 Collections.sort(sNotifications, mRankingComparator);
Chris Wrenf715fd92014-05-07 17:44:21 -0400146 }
147 LocalBroadcastManager.getInstance(Listener.this)
148 .sendBroadcast(new Intent(ACTION_REFRESH));
149 break;
150
151 case MSG_STARTUP:
152 fetchActive();
153 Log.i(TAG, "start with: " + sNotifications.size() + " notifications.");
154 LocalBroadcastManager.getInstance(Listener.this)
155 .sendBroadcast(new Intent(ACTION_REFRESH));
156 break;
157
158 case MSG_DISMISS:
159 if (msg.obj instanceof String) {
160 final String key = (String) msg.obj;
Christoph Studer13900282014-06-06 11:18:52 +0200161 Ranking ranking = mRankingMap.getRanking(key);
162 StatusBarNotification sbn = sNotifications.get(ranking.getRank());
Chris Wrenf715fd92014-05-07 17:44:21 -0400163 if ((sbn.getNotification().flags & Notification.FLAG_AUTO_CANCEL) != 0 &&
164 sbn.getNotification().contentIntent != null) {
165 try {
166 sbn.getNotification().contentIntent.send();
167 } catch (PendingIntent.CanceledException e) {
168 Log.d(TAG, "failed to send intent for " + sbn.getKey(), e);
169 }
170 }
171 cancelNotification(key);
172 }
173 break;
174
175 case MSG_LAUNCH:
176 if (msg.obj instanceof String) {
177 final String key = (String) msg.obj;
Christoph Studer13900282014-06-06 11:18:52 +0200178 Ranking ranking = mRankingMap.getRanking(delta.mSbn.getKey());
179 int position = ranking.getRank();
180 StatusBarNotification sbn = sNotifications.get(position);
Chris Wrenf715fd92014-05-07 17:44:21 -0400181 if (sbn.getNotification().contentIntent != null) {
182 try {
183 sbn.getNotification().contentIntent.send();
184 } catch (PendingIntent.CanceledException e) {
185 Log.d(TAG, "failed to send intent for " + sbn.getKey(), e);
186 }
187 }
188 if ((sbn.getNotification().flags & Notification.FLAG_AUTO_CANCEL) != 0) {
189 cancelNotification(key);
190 }
191 }
192 break;
193 }
194 }
195 };
196
Christoph Studer13900282014-06-06 11:18:52 +0200197 private RankingMap mRankingMap;
Chris Wrena02d4fd2014-05-07 17:44:21 -0400198
Chris Wrenf715fd92014-05-07 17:44:21 -0400199 @Override
200 public void onCreate() {
201 super.onCreate();
202 Log.d(TAG, "registering broadcast listener");
203 final IntentFilter intentFilter = new IntentFilter();
204 intentFilter.addAction(ACTION_DISMISS);
205 intentFilter.addAction(ACTION_LAUNCH);
206 LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, intentFilter);
207 }
208
209 @Override
210 public void onDestroy() {
211 LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
212 super.onDestroy();
213 }
214
215 @Override
Christoph Studer2b5b44a2014-05-21 21:23:45 +0200216 public void onListenerConnected() {
Chris Wrenf715fd92014-05-07 17:44:21 -0400217 Message.obtain(mHandler, MSG_STARTUP).sendToTarget();
218 }
219
220 @Override
Christoph Studer13900282014-06-06 11:18:52 +0200221 public void onNotificationRankingUpdate(RankingMap rankingMap) {
Chris Wrenf715fd92014-05-07 17:44:21 -0400222 Message.obtain(mHandler, MSG_ORDER,
Christoph Studer13900282014-06-06 11:18:52 +0200223 new Delta(null, rankingMap)).sendToTarget();
Chris Wrenf715fd92014-05-07 17:44:21 -0400224 }
225
226 @Override
Christoph Studer13900282014-06-06 11:18:52 +0200227 public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
Chris Wrenf715fd92014-05-07 17:44:21 -0400228 Message.obtain(mHandler, MSG_NOTIFY,
Christoph Studer13900282014-06-06 11:18:52 +0200229 new Delta(sbn, rankingMap)).sendToTarget();
Chris Wrenf715fd92014-05-07 17:44:21 -0400230 }
231
232 @Override
Christoph Studer13900282014-06-06 11:18:52 +0200233 public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
Chris Wrenf715fd92014-05-07 17:44:21 -0400234 Message.obtain(mHandler, MSG_CANCEL,
Christoph Studer13900282014-06-06 11:18:52 +0200235 new Delta(sbn, rankingMap)).sendToTarget();
Chris Wrenf715fd92014-05-07 17:44:21 -0400236 }
237
238 private void fetchActive() {
Christoph Studer13900282014-06-06 11:18:52 +0200239 mRankingMap = getCurrentRanking();
Chris Wrenf715fd92014-05-07 17:44:21 -0400240 sNotifications = new ArrayList<StatusBarNotification>();
Christoph Studer2b5b44a2014-05-21 21:23:45 +0200241 for (StatusBarNotification sbn : getActiveNotifications()) {
242 sNotifications.add(sbn);
Chris Wrenf715fd92014-05-07 17:44:21 -0400243 }
Chris Wrena02d4fd2014-05-07 17:44:21 -0400244 Collections.sort(sNotifications, mRankingComparator);
Chris Wrenf715fd92014-05-07 17:44:21 -0400245 }
246}