Listener.java revision 2b5b44a436d80fa89db4ddc55e429902943dc2c4
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.getRank(lhs.getKey()),
77                            mRanking.getRank(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.getRank(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.getRank(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.getRank(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.getRank(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() {
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        sNotifications = new ArrayList<StatusBarNotification>();
234        for (StatusBarNotification sbn : getActiveNotifications()) {
235            sNotifications.add(sbn);
236        }
237        Collections.sort(sNotifications, mRankingComparator);
238    }
239}
240