blob: 071969ed7c6fb8f7dd8c15502b16da0de775f599 [file] [log] [blame]
/*
* 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);
}
}