Home | History | Annotate | Download | only in service
      1 /*
      2  * Copyright (C) 2007-2008 Esmertec AG.
      3  * Copyright (C) 2007-2008 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.im.service;
     19 
     20 import java.util.HashMap;
     21 
     22 import android.app.Notification;
     23 import android.app.NotificationManager;
     24 import android.app.PendingIntent;
     25 import android.content.ContentUris;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.net.Uri;
     29 import android.os.Handler;
     30 import android.os.SystemClock;
     31 import android.text.TextUtils;
     32 import android.util.Log;
     33 
     34 import com.android.im.R;
     35 import com.android.im.app.ContactListActivity;
     36 import com.android.im.app.NewChatActivity;
     37 import com.android.im.provider.Imps;
     38 
     39 public class StatusBarNotifier {
     40     private static final boolean DBG = false;
     41 
     42     private static final long SUPPRESS_SOUND_INTERVAL_MS = 3000L;
     43 
     44     static final long[] VIBRATE_PATTERN = new long[] {0, 250, 250, 250};
     45 
     46     private Context mContext;
     47     private NotificationManager mNotificationManager;
     48 
     49     private HashMap<Long, Imps.ProviderSettings.QueryMap> mSettings;
     50     private Handler mHandler;
     51     private HashMap<Long, NotificationInfo> mNotificationInfos;
     52     private long mLastSoundPlayedMs;
     53 
     54     public StatusBarNotifier(Context context) {
     55         mContext = context;
     56         mNotificationManager = (NotificationManager) context.getSystemService(
     57                 Context.NOTIFICATION_SERVICE);
     58         mSettings = new HashMap<Long, Imps.ProviderSettings.QueryMap>();
     59         mHandler = new Handler();
     60         mNotificationInfos = new HashMap<Long, NotificationInfo>();
     61     }
     62 
     63     public void onServiceStop() {
     64         for(Imps.ProviderSettings.QueryMap queryMap : mSettings.values()) {
     65             queryMap.close();
     66         }
     67     }
     68 
     69     public void notifyChat(long providerId, long accountId, long chatId,
     70             String username, String nickname, String msg, boolean lightWeightNotify) {
     71         if (!isNotificationEnabled(providerId)) {
     72             if (DBG) log("notification for chat " + username + " is not enabled");
     73             return;
     74         }
     75 
     76         String title = nickname;
     77         String snippet = nickname + ": " + msg;
     78         Intent intent = new Intent(Intent.ACTION_VIEW,
     79                 ContentUris.withAppendedId(Imps.Chats.CONTENT_URI, chatId));
     80         intent.addCategory(com.android.im.app.ImApp.IMPS_CATEGORY);
     81         notify(username, title, snippet, msg, providerId, accountId, intent, lightWeightNotify);
     82     }
     83 
     84     public void notifySubscriptionRequest(long providerId, long accountId,
     85             long contactId, String username, String nickname) {
     86         if (!isNotificationEnabled(providerId)) {
     87             if (DBG) log("notification for subscription request " + username + " is not enabled");
     88             return;
     89         }
     90         String title = nickname;
     91         String message = mContext.getString(R.string.subscription_notify_text, nickname);
     92         Intent intent = new Intent(ImServiceConstants.ACTION_MANAGE_SUBSCRIPTION,
     93                 ContentUris.withAppendedId(Imps.Contacts.CONTENT_URI, contactId));
     94         intent.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, providerId);
     95         intent.putExtra(ImServiceConstants.EXTRA_INTENT_FROM_ADDRESS, username);
     96         notify(username, title, message, message, providerId, accountId, intent, false);
     97     }
     98 
     99     public void notifyGroupInvitation(long providerId, long accountId,
    100             long invitationId, String username) {
    101 
    102         Intent intent = new Intent(Intent.ACTION_VIEW,
    103                 ContentUris.withAppendedId(Imps.Invitation.CONTENT_URI, invitationId));
    104 
    105         String title = mContext.getString(R.string.notify_groupchat_label);
    106         String message = mContext.getString(
    107                 R.string.group_chat_invite_notify_text, username);
    108         notify(username, title, message, message, providerId, accountId, intent, false);
    109     }
    110 
    111     public void dismissNotifications(long providerId) {
    112         synchronized (mNotificationInfos) {
    113             NotificationInfo info = mNotificationInfos.get(providerId);
    114             if (info != null) {
    115                 mNotificationManager.cancel(info.computeNotificationId());
    116                 mNotificationInfos.remove(providerId);
    117             }
    118         }
    119     }
    120 
    121     public void dismissChatNotification(long providerId, String username) {
    122         NotificationInfo info;
    123         boolean removed;
    124         synchronized (mNotificationInfos) {
    125             info = mNotificationInfos.get(providerId);
    126             if (info == null) {
    127                 return;
    128             }
    129             removed = info.removeItem(username);
    130         }
    131 
    132         if (removed) {
    133             if (info.getMessage() == null) {
    134                 if (DBG) log("dismissChatNotification: removed notification for " + providerId);
    135                 mNotificationManager.cancel(info.computeNotificationId());
    136             } else {
    137                 if (DBG) {
    138                     log("cancelNotify: new notification" +
    139                             " mTitle=" + info.getTitle() +
    140                             " mMessage=" + info.getMessage() +
    141                             " mIntent=" + info.getIntent());
    142                 }
    143                 mNotificationManager.notify(info.computeNotificationId(),
    144                         info.createNotification("", true));
    145             }
    146         }
    147     }
    148 
    149     private Imps.ProviderSettings.QueryMap getProviderSettings(long providerId) {
    150         Imps.ProviderSettings.QueryMap res = mSettings.get(providerId);
    151         if (res == null) {
    152             res = new Imps.ProviderSettings.QueryMap(mContext.getContentResolver(),
    153                     providerId, true, mHandler);
    154             mSettings.put(providerId, res);
    155         }
    156         return res;
    157     }
    158 
    159     private boolean isNotificationEnabled(long providerId) {
    160         Imps.ProviderSettings.QueryMap settings = getProviderSettings(providerId);
    161         return settings.getEnableNotification();
    162     }
    163 
    164     private void notify(String sender, String title, String tickerText, String message,
    165             long providerId, long accountId, Intent intent, boolean lightWeightNotify) {
    166         NotificationInfo info;
    167         synchronized (mNotificationInfos) {
    168             info = mNotificationInfos.get(providerId);
    169             if (info == null) {
    170                 info = new NotificationInfo(providerId, accountId);
    171                 mNotificationInfos.put(providerId, info);
    172             }
    173             info.addItem(sender, title, message, intent);
    174         }
    175 
    176         mNotificationManager.notify(info.computeNotificationId(),
    177                 info.createNotification(tickerText, lightWeightNotify));
    178     }
    179 
    180     private void setRinger(long providerId, Notification notification) {
    181         Imps.ProviderSettings.QueryMap settings = getProviderSettings(providerId);
    182         String ringtoneUri = settings.getRingtoneURI();
    183         boolean vibrate = settings.getVibrate();
    184 
    185         notification.sound = TextUtils.isEmpty(ringtoneUri) ? null : Uri.parse(ringtoneUri);
    186         if (notification.sound != null) {
    187             mLastSoundPlayedMs = SystemClock.elapsedRealtime();
    188         }
    189 
    190         if (DBG) log("setRinger: notification.sound = " + notification.sound);
    191 
    192         if (vibrate) {
    193             notification.defaults |= Notification.DEFAULT_VIBRATE;
    194             if (DBG) log("setRinger: defaults |= vibrate");
    195         }
    196     }
    197 
    198     class NotificationInfo {
    199         class Item {
    200             String mTitle;
    201             String mMessage;
    202             Intent mIntent;
    203 
    204             public Item(String title, String message, Intent intent) {
    205                 mTitle = title;
    206                 mMessage = message;
    207                 mIntent = intent;
    208             }
    209         }
    210 
    211         private HashMap<String, Item> mItems;
    212 
    213         private long mProviderId;
    214         private long mAccountId;
    215 
    216         public NotificationInfo(long providerId, long accountId) {
    217             mProviderId = providerId;
    218             mAccountId = accountId;
    219             mItems = new HashMap<String, Item>();
    220         }
    221 
    222         public int computeNotificationId() {
    223             return (int)mProviderId;
    224         }
    225 
    226         public synchronized void addItem(String sender, String title, String message, Intent intent) {
    227             Item item = mItems.get(sender);
    228             if (item == null) {
    229                 item = new Item(title, message, intent);
    230                 mItems.put(sender, item);
    231             } else {
    232                 item.mTitle = title;
    233                 item.mMessage = message;
    234                 item.mIntent = intent;
    235             }
    236         }
    237 
    238         public synchronized boolean removeItem(String sender) {
    239             Item item =  mItems.remove(sender);
    240             if (item != null) {
    241                 return true;
    242             }
    243             return false;
    244         }
    245 
    246         public Notification createNotification(String tickerText, boolean lightWeightNotify) {
    247             Notification notification = new Notification(
    248                     android.R.drawable.stat_notify_chat,
    249                     lightWeightNotify ? null : tickerText,
    250                     System.currentTimeMillis());
    251 
    252             Intent intent = getIntent();
    253 
    254             notification.setLatestEventInfo(mContext, getTitle(), getMessage(),
    255                     PendingIntent.getActivity(mContext, 0, intent, 0));
    256             notification.flags |= Notification.FLAG_AUTO_CANCEL;
    257             if (!(lightWeightNotify || shouldSuppressSoundNotification())) {
    258                 setRinger(mProviderId, notification);
    259             }
    260             return notification;
    261         }
    262 
    263         private Intent getDefaultIntent() {
    264             Intent intent = new Intent(Intent.ACTION_VIEW);
    265             intent.setType(Imps.Contacts.CONTENT_TYPE);
    266             intent.setClass(mContext, ContactListActivity.class);
    267             intent.putExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, mAccountId);
    268 
    269             return intent;
    270         }
    271 
    272         private Intent getMultipleNotificationIntent() {
    273             Intent intent = new Intent(Intent.ACTION_VIEW);
    274             intent.setClass(mContext, NewChatActivity.class);
    275             intent.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, mProviderId);
    276             intent.putExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, mAccountId);
    277             intent.putExtra(ImServiceConstants.EXTRA_INTENT_SHOW_MULTIPLE, true);
    278             return intent;
    279         }
    280 
    281         public String getTitle() {
    282             int count = mItems.size();
    283             if (count == 0) {
    284                 return null;
    285             } else if (count == 1) {
    286                 Item item = mItems.values().iterator().next();
    287                 return item.mTitle;
    288             } else {
    289                 return mContext.getString(R.string.newMessages_label,
    290                         Imps.Provider.getProviderNameForId(mContext.getContentResolver(), mProviderId));
    291             }
    292         }
    293 
    294         public String getMessage() {
    295             int count = mItems.size();
    296             if (count == 0) {
    297                 return null;
    298             } else if (count == 1) {
    299                 Item item = mItems.values().iterator().next();
    300                 return item.mMessage;
    301             } else {
    302                 return mContext.getString(R.string.num_unread_chats, count);
    303             }
    304         }
    305 
    306         public Intent getIntent() {
    307             int count = mItems.size();
    308             if (count == 0) {
    309                 return getDefaultIntent();
    310             } else if (count == 1) {
    311                 Item item = mItems.values().iterator().next();
    312                 return item.mIntent;
    313             } else {
    314                 return getMultipleNotificationIntent();
    315             }
    316         }
    317     }
    318 
    319     private static void log(String msg) {
    320         Log.d(RemoteImService.TAG, "[StatusBarNotify] " + msg);
    321     }
    322 
    323     private boolean shouldSuppressSoundNotification() {
    324         return (SystemClock.elapsedRealtime() - mLastSoundPlayedMs < SUPPRESS_SOUND_INTERVAL_MS);
    325     }
    326 }
    327