Home | History | Annotate | Download | only in notificationlistener
      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  */
     16 package com.android.example.notificationlistener;
     17 
     18 
     19 import android.app.Notification;
     20 import android.app.PendingIntent;
     21 import android.content.BroadcastReceiver;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.IntentFilter;
     25 import android.os.Handler;
     26 import android.os.Message;
     27 import android.service.notification.NotificationListenerService;
     28 import android.service.notification.NotificationListenerService.Ranking;
     29 import android.service.notification.NotificationListenerService.RankingMap;
     30 import android.service.notification.StatusBarNotification;
     31 import android.support.v4.content.LocalBroadcastManager;
     32 import android.text.TextUtils;
     33 import android.util.Log;
     34 
     35 import java.util.ArrayList;
     36 import java.util.Collections;
     37 import java.util.Comparator;
     38 import java.util.List;
     39 
     40 public 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