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