/* * Copyright (C) 2007-2008 Esmertec AG. * Copyright (C) 2007-2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.im.service; import java.util.HashMap; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; import android.text.TextUtils; import android.util.Log; import com.android.im.R; import com.android.im.app.ContactListActivity; import com.android.im.app.NewChatActivity; import com.android.im.provider.Imps; public class StatusBarNotifier { private static final boolean DBG = false; private static final long SUPPRESS_SOUND_INTERVAL_MS = 3000L; static final long[] VIBRATE_PATTERN = new long[] {0, 250, 250, 250}; private Context mContext; private NotificationManager mNotificationManager; private HashMap<Long, Imps.ProviderSettings.QueryMap> mSettings; private Handler mHandler; private HashMap<Long, NotificationInfo> mNotificationInfos; private long mLastSoundPlayedMs; public StatusBarNotifier(Context context) { mContext = context; mNotificationManager = (NotificationManager) context.getSystemService( Context.NOTIFICATION_SERVICE); mSettings = new HashMap<Long, Imps.ProviderSettings.QueryMap>(); mHandler = new Handler(); mNotificationInfos = new HashMap<Long, NotificationInfo>(); } public void onServiceStop() { for(Imps.ProviderSettings.QueryMap queryMap : mSettings.values()) { queryMap.close(); } } public void notifyChat(long providerId, long accountId, long chatId, String username, String nickname, String msg, boolean lightWeightNotify) { if (!isNotificationEnabled(providerId)) { if (DBG) log("notification for chat " + username + " is not enabled"); return; } String title = nickname; String snippet = nickname + ": " + msg; Intent intent = new Intent(Intent.ACTION_VIEW, ContentUris.withAppendedId(Imps.Chats.CONTENT_URI, chatId)); intent.addCategory(com.android.im.app.ImApp.IMPS_CATEGORY); notify(username, title, snippet, msg, providerId, accountId, intent, lightWeightNotify); } public void notifySubscriptionRequest(long providerId, long accountId, long contactId, String username, String nickname) { if (!isNotificationEnabled(providerId)) { if (DBG) log("notification for subscription request " + username + " is not enabled"); return; } String title = nickname; String message = mContext.getString(R.string.subscription_notify_text, nickname); Intent intent = new Intent(ImServiceConstants.ACTION_MANAGE_SUBSCRIPTION, ContentUris.withAppendedId(Imps.Contacts.CONTENT_URI, contactId)); intent.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, providerId); intent.putExtra(ImServiceConstants.EXTRA_INTENT_FROM_ADDRESS, username); notify(username, title, message, message, providerId, accountId, intent, false); } public void notifyGroupInvitation(long providerId, long accountId, long invitationId, String username) { Intent intent = new Intent(Intent.ACTION_VIEW, ContentUris.withAppendedId(Imps.Invitation.CONTENT_URI, invitationId)); String title = mContext.getString(R.string.notify_groupchat_label); String message = mContext.getString( R.string.group_chat_invite_notify_text, username); notify(username, title, message, message, providerId, accountId, intent, false); } public void dismissNotifications(long providerId) { synchronized (mNotificationInfos) { NotificationInfo info = mNotificationInfos.get(providerId); if (info != null) { mNotificationManager.cancel(info.computeNotificationId()); mNotificationInfos.remove(providerId); } } } public void dismissChatNotification(long providerId, String username) { NotificationInfo info; boolean removed; synchronized (mNotificationInfos) { info = mNotificationInfos.get(providerId); if (info == null) { return; } removed = info.removeItem(username); } if (removed) { if (info.getMessage() == null) { if (DBG) log("dismissChatNotification: removed notification for " + providerId); mNotificationManager.cancel(info.computeNotificationId()); } else { if (DBG) { log("cancelNotify: new notification" + " mTitle=" + info.getTitle() + " mMessage=" + info.getMessage() + " mIntent=" + info.getIntent()); } mNotificationManager.notify(info.computeNotificationId(), info.createNotification("", true)); } } } private Imps.ProviderSettings.QueryMap getProviderSettings(long providerId) { Imps.ProviderSettings.QueryMap res = mSettings.get(providerId); if (res == null) { res = new Imps.ProviderSettings.QueryMap(mContext.getContentResolver(), providerId, true, mHandler); mSettings.put(providerId, res); } return res; } private boolean isNotificationEnabled(long providerId) { Imps.ProviderSettings.QueryMap settings = getProviderSettings(providerId); return settings.getEnableNotification(); } private void notify(String sender, String title, String tickerText, String message, long providerId, long accountId, Intent intent, boolean lightWeightNotify) { NotificationInfo info; synchronized (mNotificationInfos) { info = mNotificationInfos.get(providerId); if (info == null) { info = new NotificationInfo(providerId, accountId); mNotificationInfos.put(providerId, info); } info.addItem(sender, title, message, intent); } mNotificationManager.notify(info.computeNotificationId(), info.createNotification(tickerText, lightWeightNotify)); } private void setRinger(long providerId, Notification notification) { Imps.ProviderSettings.QueryMap settings = getProviderSettings(providerId); String ringtoneUri = settings.getRingtoneURI(); boolean vibrate = settings.getVibrate(); notification.sound = TextUtils.isEmpty(ringtoneUri) ? null : Uri.parse(ringtoneUri); if (notification.sound != null) { mLastSoundPlayedMs = SystemClock.elapsedRealtime(); } if (DBG) log("setRinger: notification.sound = " + notification.sound); if (vibrate) { notification.defaults |= Notification.DEFAULT_VIBRATE; if (DBG) log("setRinger: defaults |= vibrate"); } } class NotificationInfo { class Item { String mTitle; String mMessage; Intent mIntent; public Item(String title, String message, Intent intent) { mTitle = title; mMessage = message; mIntent = intent; } } private HashMap<String, Item> mItems; private long mProviderId; private long mAccountId; public NotificationInfo(long providerId, long accountId) { mProviderId = providerId; mAccountId = accountId; mItems = new HashMap<String, Item>(); } public int computeNotificationId() { return (int)mProviderId; } public synchronized void addItem(String sender, String title, String message, Intent intent) { Item item = mItems.get(sender); if (item == null) { item = new Item(title, message, intent); mItems.put(sender, item); } else { item.mTitle = title; item.mMessage = message; item.mIntent = intent; } } public synchronized boolean removeItem(String sender) { Item item = mItems.remove(sender); if (item != null) { return true; } return false; } public Notification createNotification(String tickerText, boolean lightWeightNotify) { Notification notification = new Notification( android.R.drawable.stat_notify_chat, lightWeightNotify ? null : tickerText, System.currentTimeMillis()); Intent intent = getIntent(); notification.setLatestEventInfo(mContext, getTitle(), getMessage(), PendingIntent.getActivity(mContext, 0, intent, 0)); notification.flags |= Notification.FLAG_AUTO_CANCEL; if (!(lightWeightNotify || shouldSuppressSoundNotification())) { setRinger(mProviderId, notification); } return notification; } private Intent getDefaultIntent() { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setType(Imps.Contacts.CONTENT_TYPE); intent.setClass(mContext, ContactListActivity.class); intent.putExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, mAccountId); return intent; } private Intent getMultipleNotificationIntent() { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setClass(mContext, NewChatActivity.class); intent.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, mProviderId); intent.putExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, mAccountId); intent.putExtra(ImServiceConstants.EXTRA_INTENT_SHOW_MULTIPLE, true); return intent; } public String getTitle() { int count = mItems.size(); if (count == 0) { return null; } else if (count == 1) { Item item = mItems.values().iterator().next(); return item.mTitle; } else { return mContext.getString(R.string.newMessages_label, Imps.Provider.getProviderNameForId(mContext.getContentResolver(), mProviderId)); } } public String getMessage() { int count = mItems.size(); if (count == 0) { return null; } else if (count == 1) { Item item = mItems.values().iterator().next(); return item.mMessage; } else { return mContext.getString(R.string.num_unread_chats, count); } } public Intent getIntent() { int count = mItems.size(); if (count == 0) { return getDefaultIntent(); } else if (count == 1) { Item item = mItems.values().iterator().next(); return item.mIntent; } else { return getMultipleNotificationIntent(); } } } private static void log(String msg) { Log.d(RemoteImService.TAG, "[StatusBarNotify] " + msg); } private boolean shouldSuppressSoundNotification() { return (SystemClock.elapsedRealtime() - mLastSoundPlayedMs < SUPPRESS_SOUND_INTERVAL_MS); } }