Listener.java revision 70bed82c9cf579dccbe4581859d4d3b9720ddbb2
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.NotificationListenerService.Ranking;
29import android.service.notification.NotificationListenerService.RankingMap;
30import android.service.notification.StatusBarNotification;
31import android.support.v4.content.LocalBroadcastManager;
32import android.text.TextUtils;
33import android.util.Log;
34
35import java.util.ArrayList;
36import java.util.Collections;
37import java.util.Comparator;
38import 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
63    private final Ranking mTmpRanking = new Ranking();
64
65    private class Delta {
66        final StatusBarNotification mSbn;
67        final RankingMap mRankingMap;
68
69        public Delta(StatusBarNotification sbn, RankingMap rankingMap) {
70            mSbn = sbn;
71            mRankingMap = rankingMap;
72        }
73    }
74
75    private final Comparator<StatusBarNotification> mRankingComparator =
76            new Comparator<StatusBarNotification>() {
77
78                private final Ranking mLhsRanking = new Ranking();
79                private final Ranking mRhsRanking = new Ranking();
80
81                @Override
82                public int compare(StatusBarNotification lhs, StatusBarNotification rhs) {
83                    mRankingMap.getRanking(lhs.getKey(), mLhsRanking);
84                    mRankingMap.getRanking(rhs.getKey(), mRhsRanking);
85                    return Integer.compare(mLhsRanking.getRank(), mRhsRanking.getRank());
86                }
87            };
88
89    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
90        @Override
91        public void onReceive(Context context, Intent intent) {
92            String key = intent.getStringExtra(EXTRA_KEY);
93            int what = MSG_DISMISS;
94            if (ACTION_LAUNCH.equals(intent.getAction())) {
95                what = MSG_LAUNCH;
96            }
97            Log.d(TAG, "received an action broadcast " + intent.getAction());
98            if (!TextUtils.isEmpty(key)) {
99                Log.d(TAG, "  on " + key);
100                Message.obtain(mHandler, what, key).sendToTarget();
101            }
102        }
103    };
104
105    private final Handler mHandler = new Handler() {
106        @Override
107        public void handleMessage(Message msg) {
108            Delta delta = null;
109            if (msg.obj instanceof Delta) {
110                delta = (Delta) msg.obj;
111            }
112
113            switch (msg.what) {
114                case MSG_NOTIFY:
115                    Log.i(TAG, "notify: " + delta.mSbn.getKey());
116                    synchronized (sNotifications) {
117                        boolean exists = mRankingMap.getRanking(delta.mSbn.getKey(), mTmpRanking);
118                        if (!exists) {
119                            sNotifications.add(delta.mSbn);
120                        } else {
121                            int position = mTmpRanking.getRank();
122                            sNotifications.set(position, delta.mSbn);
123                        }
124                        mRankingMap = delta.mRankingMap;
125                        Collections.sort(sNotifications, mRankingComparator);
126                        Log.i(TAG, "finish with: " + sNotifications.size());
127                    }
128                    LocalBroadcastManager.getInstance(Listener.this)
129                            .sendBroadcast(new Intent(ACTION_REFRESH)
130                            .putExtra(EXTRA_KEY, delta.mSbn.getKey()));
131                    break;
132
133                case MSG_CANCEL:
134                    Log.i(TAG, "remove: " + delta.mSbn.getKey());
135                    synchronized (sNotifications) {
136                        boolean exists = mRankingMap.getRanking(delta.mSbn.getKey(), mTmpRanking);
137                        if (exists) {
138                            sNotifications.remove(mTmpRanking.getRank());
139                        }
140                        mRankingMap = delta.mRankingMap;
141                        Collections.sort(sNotifications, mRankingComparator);
142                    }
143                    LocalBroadcastManager.getInstance(Listener.this)
144                            .sendBroadcast(new Intent(ACTION_REFRESH));
145                    break;
146
147                case MSG_ORDER:
148                    Log.i(TAG, "reorder");
149                    synchronized (sNotifications) {
150                        mRankingMap = delta.mRankingMap;
151                        Collections.sort(sNotifications, mRankingComparator);
152                    }
153                    LocalBroadcastManager.getInstance(Listener.this)
154                            .sendBroadcast(new Intent(ACTION_REFRESH));
155                    break;
156
157                case MSG_STARTUP:
158                    fetchActive();
159                    Log.i(TAG, "start with: " + sNotifications.size() + " notifications.");
160                    LocalBroadcastManager.getInstance(Listener.this)
161                            .sendBroadcast(new Intent(ACTION_REFRESH));
162                    break;
163
164                case MSG_DISMISS:
165                    if (msg.obj instanceof String) {
166                        final String key = (String) msg.obj;
167                        mRankingMap.getRanking(key, mTmpRanking);
168                        StatusBarNotification sbn = sNotifications.get(mTmpRanking.getRank());
169                        if ((sbn.getNotification().flags & Notification.FLAG_AUTO_CANCEL) != 0 &&
170                                sbn.getNotification().contentIntent != null) {
171                            try {
172                                sbn.getNotification().contentIntent.send();
173                            } catch (PendingIntent.CanceledException e) {
174                                Log.d(TAG, "failed to send intent for " + sbn.getKey(), e);
175                            }
176                        }
177                        cancelNotification(key);
178                    }
179                    break;
180
181                case MSG_LAUNCH:
182                    if (msg.obj instanceof String) {
183                        final String key = (String) msg.obj;
184                        mRankingMap.getRanking(key, mTmpRanking);
185                        StatusBarNotification sbn = sNotifications.get(mTmpRanking.getRank());
186                        if (sbn.getNotification().contentIntent != null) {
187                            try {
188                                sbn.getNotification().contentIntent.send();
189                            } catch (PendingIntent.CanceledException e) {
190                                Log.d(TAG, "failed to send intent for " + sbn.getKey(), e);
191                            }
192                        }
193                        if ((sbn.getNotification().flags & Notification.FLAG_AUTO_CANCEL) != 0) {
194                            cancelNotification(key);
195                        }
196                    }
197                    break;
198            }
199        }
200    };
201
202    private RankingMap mRankingMap;
203
204    @Override
205    public void onCreate() {
206        super.onCreate();
207        Log.d(TAG, "registering broadcast listener");
208        final IntentFilter intentFilter = new IntentFilter();
209        intentFilter.addAction(ACTION_DISMISS);
210        intentFilter.addAction(ACTION_LAUNCH);
211        LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, intentFilter);
212    }
213
214    @Override
215    public void onDestroy() {
216        LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
217        super.onDestroy();
218    }
219
220    @Override
221    public void onListenerConnected() {
222        Message.obtain(mHandler, MSG_STARTUP).sendToTarget();
223    }
224
225    @Override
226    public void onNotificationRankingUpdate(RankingMap rankingMap) {
227        Message.obtain(mHandler, MSG_ORDER,
228                new Delta(null, rankingMap)).sendToTarget();
229    }
230
231    @Override
232    public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
233        Message.obtain(mHandler, MSG_NOTIFY,
234                new Delta(sbn, rankingMap)).sendToTarget();
235    }
236
237    @Override
238    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
239        Message.obtain(mHandler, MSG_CANCEL,
240                new Delta(sbn, rankingMap)).sendToTarget();
241    }
242
243    private void fetchActive() {
244        mRankingMap = getCurrentRanking();
245        sNotifications = new ArrayList<StatusBarNotification>();
246        for (StatusBarNotification sbn : getActiveNotifications()) {
247            sNotifications.add(sbn);
248        }
249        Collections.sort(sNotifications, mRankingComparator);
250    }
251}
252