/* * 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 info.guardianproject.otr.app.im.service; import info.guardianproject.otr.app.im.R; import info.guardianproject.otr.app.im.app.NewChatActivity; import info.guardianproject.otr.app.im.app.WelcomeActivity; import info.guardianproject.otr.app.im.provider.Imps; import info.guardianproject.util.SystemServices; import java.util.HashMap; import org.jsoup.Jsoup; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; 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 Imps.ProviderSettings.QueryMap mGlobalSettings; private Handler mHandler; private HashMap<String, NotificationInfo> mNotificationInfos; private long mLastSoundPlayedMs; public StatusBarNotifier(Context context) { mContext = context; mNotificationManager = (NotificationManager) context .getSystemService(Context.NOTIFICATION_SERVICE); mHandler = new Handler(); mNotificationInfos = new HashMap<String, NotificationInfo>(); } public void onServiceStop() { if (mGlobalSettings != null) mGlobalSettings.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; } msg = html2text(msg); // strip tags for html client inbound msgs String title = nickname; String snippet = mContext.getString(R.string.new_messages_notify) + ' ' + nickname;// + ": " + msg; Intent intent = new Intent(Intent.ACTION_VIEW, ContentUris.withAppendedId( Imps.Chats.CONTENT_URI, chatId)); intent.addCategory(info.guardianproject.otr.app.im.app.ImApp.IMPS_CATEGORY); notify(username, title, snippet, msg, providerId, accountId, intent, lightWeightNotify, R.drawable.ic_stat_status); } public void notifyError(String username, String error) { Intent intent = new Intent(mContext, NewChatActivity.class); notify(username, error, error, error, -1, -1, intent, true, R.drawable.ic_stat_status); } 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, R.drawable.ic_stat_status); } 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, R.drawable.ic_stat_status); } public void notifyLoggedIn(long providerId, long accountId) { Intent intent = new Intent(mContext, NewChatActivity.class); ; String title = mContext.getString(R.string.app_name); String message = mContext.getString(R.string.presence_available); notify(message, title, message, message, providerId, accountId, intent, false, R.drawable.ic_stat_status); } public void notifyLocked() { Intent intent = new Intent(mContext, WelcomeActivity.class); String title = mContext.getString(R.string.app_name); String message = mContext.getString(R.string.account_setup_pers_now_title); notify(message, title, message, message, -1, -1, intent, true, R.drawable.notify_chatsecure); } public void notifyDisconnected(long providerId, long accountId) { Intent intent = new Intent(mContext, NewChatActivity.class); ; String title = mContext.getString(R.string.app_name); String message = mContext.getString(R.string.presence_offline); notify(message, title, message, message, providerId, accountId, intent, false, R.drawable.ic_stat_status); } public void notifyFile(long providerId, long accountId, long id, String username, String nickname, String path, Uri uri, String type, boolean b) { String title = nickname; String message = mContext.getString(R.string.file_notify_text, path); Intent intent = SystemServices.Viewer.getViewIntent(uri, type); notify(message, title, message, message, providerId, accountId, intent, false, R.drawable.ic_stat_status); } 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(username); 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.cancel(info.computeNotificationId()); } } } private Imps.ProviderSettings.QueryMap getGlobalSettings() { if (mGlobalSettings == null) { ContentResolver contentResolver = mContext.getContentResolver(); Cursor cursor = contentResolver.query(Imps.ProviderSettings.CONTENT_URI,new String[] {Imps.ProviderSettings.NAME, Imps.ProviderSettings.VALUE},Imps.ProviderSettings.PROVIDER + "=?",new String[] { Long.toString(Imps.ProviderSettings.PROVIDER_ID_FOR_GLOBAL_SETTINGS)},null); if (cursor == null) return null; mGlobalSettings = new Imps.ProviderSettings.QueryMap(cursor, contentResolver, Imps.ProviderSettings.PROVIDER_ID_FOR_GLOBAL_SETTINGS, true, mHandler); } return mGlobalSettings; } private boolean isNotificationEnabled(long providerId) { return getGlobalSettings().getEnableNotification(); } private void notify(String sender, String title, String tickerText, String message, long providerId, long accountId, Intent intent, boolean lightWeightNotify, int icon) { // intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); NotificationInfo info; synchronized (mNotificationInfos) { info = mNotificationInfos.get(sender); if (info == null) { info = new NotificationInfo(providerId, accountId); mNotificationInfos.put(sender, info); } info.addItem(sender, title, message, intent); } mNotificationManager.notify(info.computeNotificationId(), info.createNotification(tickerText, lightWeightNotify, icon)); } private void setRinger(long providerId, NotificationCompat.Builder builder) { String ringtoneUri = getGlobalSettings().getRingtoneURI(); boolean vibrate = getGlobalSettings().getVibrate(); Uri sound = TextUtils.isEmpty(ringtoneUri) ? null : Uri.parse(ringtoneUri); builder.setSound(sound); if (sound != null) { mLastSoundPlayedMs = SystemClock.elapsedRealtime(); } if (DBG) log("setRinger: notification.sound = " + sound); if (vibrate) { builder.setDefaults(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 Item lastItem; private long mProviderId; private long mAccountId; public NotificationInfo(long providerId, long accountId) { mProviderId = providerId; mAccountId = accountId; // mItems = new HashMap<String, Item>(); } public int computeNotificationId() { if (lastItem == null) return (int)mProviderId; return lastItem.mTitle.hashCode(); } 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; }*/ lastItem = new Item(title, message, intent); } public synchronized boolean removeItem(String sender) { /* Item item = mItems.remove(sender); if (item != null) { return true; }*/ return true; } public Notification createNotification(String tickerText, boolean lightWeightNotify, int icon) { NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext); Intent intent = getIntent(); builder .setSmallIcon(icon) .setTicker(lightWeightNotify ? null : tickerText) .setWhen(System.currentTimeMillis()) .setLights(0xff00ff00, 300, 1000) .setContentTitle(getTitle()) .setContentText(getMessage()) .setContentIntent(PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)) .setAutoCancel(true); if (!(lightWeightNotify || shouldSuppressSoundNotification())) { setRinger(mProviderId, builder); } return builder.build(); } private Intent getDefaultIntent() { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setType(Imps.Contacts.CONTENT_TYPE); intent.setClass(mContext, NewChatActivity.class); intent.putExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, mAccountId); // intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 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); // intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 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)); }*/ return lastItem.mTitle; } 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); }*/ return lastItem.mMessage; } 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(); }*/ return lastItem.mIntent; } } private static void log(String msg) { RemoteImService.debug("[StatusBarNotify] " + msg); } private boolean shouldSuppressSoundNotification() { return (SystemClock.elapsedRealtime() - mLastSoundPlayedMs < SUPPRESS_SOUND_INTERVAL_MS); } public static String html2text(String html) { return Jsoup.parse(html).text(); } }