From 994511b3c9d0e439de64c462ef859191c7efdf85 Mon Sep 17 00:00:00 2001 From: Lukas Barth Date: Wed, 12 Mar 2014 19:41:11 +0100 Subject: [PATCH 1/3] Adding widget with notification count Remove bad positioned label --- AndroidManifest.xml | 8 ++ res/drawable/circle_badge.xml | 16 +++ res/layout/textsecure_appwidget.xml | 35 ++++++ res/xml/textsecure_appwidget_info.xml | 11 ++ .../notifications/MessageNotifier.java | 7 +- .../TextSecureAppWidgetProvider.java | 105 ++++++++++++++++++ 6 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 res/drawable/circle_badge.xml create mode 100644 res/layout/textsecure_appwidget.xml create mode 100644 res/xml/textsecure_appwidget_info.xml create mode 100644 src/org/thoughtcrime/securesms/providers/TextSecureAppWidgetProvider.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c74ddf472d7..26e88062a96 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -245,6 +245,14 @@ + + + + + + + + + + + + + + diff --git a/res/layout/textsecure_appwidget.xml b/res/layout/textsecure_appwidget.xml new file mode 100644 index 00000000000..e482706451f --- /dev/null +++ b/res/layout/textsecure_appwidget.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/xml/textsecure_appwidget_info.xml b/res/xml/textsecure_appwidget_info.xml new file mode 100644 index 00000000000..3480f9cece8 --- /dev/null +++ b/res/xml/textsecure_appwidget_info.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java index db3c0c08627..0eed57a9eb3 100644 --- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java @@ -19,6 +19,8 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.database.Cursor; @@ -41,6 +43,7 @@ import org.thoughtcrime.securesms.RoutingActivity; import org.thoughtcrime.securesms.contacts.ContactPhotoFactory; import org.thoughtcrime.securesms.database.PushDatabase; +import org.thoughtcrime.securesms.providers.TextSecureAppWidgetProvider; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.whispersystems.textsecure.crypto.MasterSecret; @@ -98,7 +101,6 @@ public static void notifyMessageDeliveryFailed(Context context, Recipients recip } } - public static void updateNotification(Context context, MasterSecret masterSecret) { if (!TextSecurePreferences.isNotificationsEnabled(context)) { return; @@ -120,10 +122,13 @@ public static void updateNotification(Context context, MasterSecret masterSecret } } + private static void updateNotification(Context context, MasterSecret masterSecret, boolean signal) { Cursor telcoCursor = null; Cursor pushCursor = null; + TextSecureAppWidgetProvider.triggerUpdate(context); + try { telcoCursor = DatabaseFactory.getMmsSmsDatabase(context).getUnread(); pushCursor = DatabaseFactory.getPushDatabase(context).getPending(); diff --git a/src/org/thoughtcrime/securesms/providers/TextSecureAppWidgetProvider.java b/src/org/thoughtcrime/securesms/providers/TextSecureAppWidgetProvider.java new file mode 100644 index 00000000000..f7d50266c7c --- /dev/null +++ b/src/org/thoughtcrime/securesms/providers/TextSecureAppWidgetProvider.java @@ -0,0 +1,105 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.thoughtcrime.securesms.providers; + +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.view.View; +import android.widget.RemoteViews; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.RoutingActivity; +import org.thoughtcrime.securesms.database.DatabaseFactory; + +/** + * The provider for the TextSecure AppWidget + * + * @author Lukas Barth + */ +public class TextSecureAppWidgetProvider extends AppWidgetProvider { + + public static void triggerUpdate(Context context) { + AppWidgetManager widgetManager = AppWidgetManager.getInstance(context); + ComponentName widgetComponent = new ComponentName(context, TextSecureAppWidgetProvider.class); + int[] widgetIds = widgetManager.getAppWidgetIds(widgetComponent); + + Intent updateIntent = new Intent(); + updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds); + updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); + updateIntent.setClass(context, TextSecureAppWidgetProvider.class); + context.sendBroadcast(updateIntent); + } + + private int getUnreadCount(Context context) { + Cursor telcoCursor = null; + Cursor pushCursor = null; + int unread = 0; + + try { + telcoCursor = DatabaseFactory.getMmsSmsDatabase(context).getUnread(); + pushCursor = DatabaseFactory.getPushDatabase(context).getPending(); + + if (telcoCursor != null) { + unread += telcoCursor.getCount(); + } + + if (pushCursor != null) { + unread += pushCursor.getCount(); + } + + } finally { + if (telcoCursor != null) telcoCursor.close(); + if (pushCursor != null) pushCursor.close(); + } + + return unread; + } + + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + final int n = appWidgetIds.length; + + for (int i = 0; i < n; i++) { + int appWidgetId = appWidgetIds[i]; + + Intent intent = new Intent(context, RoutingActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); + + RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.textsecure_appwidget); + views.setOnClickPendingIntent(R.id.icon_view, pendingIntent); + + int unread = getUnreadCount(context); + if (unread > 0) { + if (unread > 99) { + unread = 99; + } + + views.setTextViewText(R.id.unread_count_text, Integer.toString(unread)); + views.setViewVisibility(R.id.unread_count_text, View.VISIBLE); + } else { + views.setViewVisibility(R.id.unread_count_text, View.INVISIBLE); + } + + appWidgetManager.updateAppWidget(appWidgetId, views); + } + } +} From b62d749918913581f49412a88b39f0647f5e6cb5 Mon Sep 17 00:00:00 2001 From: Lukas Barth Date: Sun, 18 May 2014 18:50:07 +0200 Subject: [PATCH 2/3] Fix wrong layout --- res/layout/textsecure_appwidget.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/res/layout/textsecure_appwidget.xml b/res/layout/textsecure_appwidget.xml index e482706451f..b12f568ca1e 100644 --- a/res/layout/textsecure_appwidget.xml +++ b/res/layout/textsecure_appwidget.xml @@ -28,8 +28,7 @@ android:background="@drawable/circle_badge" android:gravity="center_vertical|center_horizontal" android:layout_alignParentEnd="false" - android:layout_gravity="left" - android:layout_marginLeft="25dip"/> + android:layout_gravity="right" /> \ No newline at end of file From 16e37e741e283b529a64ce90135173c4c5db069a Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Mon, 18 Aug 2014 23:19:52 +0200 Subject: [PATCH 3/3] Moved message counting to MessageNotifier --- .../notifications/MessageNotifier.java | 5 +- .../TextSecureAppWidgetProvider.java | 121 +++++++++++------- 2 files changed, 79 insertions(+), 47 deletions(-) diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java index 0eed57a9eb3..bdcaf1d5373 100644 --- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java @@ -127,8 +127,6 @@ private static void updateNotification(Context context, MasterSecret masterSecre Cursor telcoCursor = null; Cursor pushCursor = null; - TextSecureAppWidgetProvider.triggerUpdate(context); - try { telcoCursor = DatabaseFactory.getMmsSmsDatabase(context).getUnread(); pushCursor = DatabaseFactory.getPushDatabase(context).getPending(); @@ -138,6 +136,7 @@ private static void updateNotification(Context context, MasterSecret masterSecre { ((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE)) .cancel(NOTIFICATION_ID); + TextSecureAppWidgetProvider.triggerUpdate(context, 0); return; } @@ -145,6 +144,8 @@ private static void updateNotification(Context context, MasterSecret masterSecre appendPushNotificationState(context, masterSecret, notificationState, pushCursor); + TextSecureAppWidgetProvider.triggerUpdate(context, notificationState.getMessageCount()); + if (notificationState.hasMultipleThreads()) { sendMultipleThreadNotification(context, masterSecret, notificationState, signal); } else { diff --git a/src/org/thoughtcrime/securesms/providers/TextSecureAppWidgetProvider.java b/src/org/thoughtcrime/securesms/providers/TextSecureAppWidgetProvider.java index f7d50266c7c..f5fbdd68948 100644 --- a/src/org/thoughtcrime/securesms/providers/TextSecureAppWidgetProvider.java +++ b/src/org/thoughtcrime/securesms/providers/TextSecureAppWidgetProvider.java @@ -23,7 +23,10 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.database.Cursor; +import android.os.Bundle; import android.view.View; import android.widget.RemoteViews; @@ -31,6 +34,8 @@ import org.thoughtcrime.securesms.RoutingActivity; import org.thoughtcrime.securesms.database.DatabaseFactory; +import java.util.List; + /** * The provider for the TextSecure AppWidget * @@ -38,68 +43,94 @@ */ public class TextSecureAppWidgetProvider extends AppWidgetProvider { - public static void triggerUpdate(Context context) { + final static String UNREAD_COUNT = "unreadCount"; + + public static void triggerUpdate(Context context, int unread) { AppWidgetManager widgetManager = AppWidgetManager.getInstance(context); ComponentName widgetComponent = new ComponentName(context, TextSecureAppWidgetProvider.class); int[] widgetIds = widgetManager.getAppWidgetIds(widgetComponent); - + // widget notification Intent updateIntent = new Intent(); + updateIntent.putExtra(UNREAD_COUNT, unread); updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds); updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); updateIntent.setClass(context, TextSecureAppWidgetProvider.class); context.sendBroadcast(updateIntent); + // Samsung TouchWiz notification + String launcherClassName = getLauncherClassName(context); + if (launcherClassName != null) { + Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE"); + intent.putExtra("badge_count", unread); + intent.putExtra("badge_count_package_name", context.getPackageName()); + intent.putExtra("badge_count_class_name", launcherClassName); + context.sendBroadcast(intent); + } + // Sony BadgeReceiver notification + Intent intent = new Intent(); + intent.setAction("com.sonyericsson.home.action.UPDATE_BADGE"); + intent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", RoutingActivity.class.getCanonicalName()); + intent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", "org.thoughtcrime.securesms"); + intent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", Integer.toString(unread)); + if(unread>0) + intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", true); + else + intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", false); + context.sendBroadcast(intent); } - private int getUnreadCount(Context context) { - Cursor telcoCursor = null; - Cursor pushCursor = null; - int unread = 0; + private static String getLauncherClassName(Context context) { + PackageManager pm = context.getPackageManager(); - try { - telcoCursor = DatabaseFactory.getMmsSmsDatabase(context).getUnread(); - pushCursor = DatabaseFactory.getPushDatabase(context).getPending(); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); - if (telcoCursor != null) { - unread += telcoCursor.getCount(); + List resolveInfos = pm.queryIntentActivities(intent, 0); + for (ResolveInfo resolveInfo : resolveInfos) { + String pkgName = resolveInfo.activityInfo.applicationInfo.packageName; + if (pkgName.equalsIgnoreCase(context.getPackageName())) { + String className = resolveInfo.activityInfo.name; + return className; } - - if (pushCursor != null) { - unread += pushCursor.getCount(); - } - - } finally { - if (telcoCursor != null) telcoCursor.close(); - if (pushCursor != null) pushCursor.close(); } - - return unread; + return null; } - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - final int n = appWidgetIds.length; - - for (int i = 0; i < n; i++) { - int appWidgetId = appWidgetIds[i]; - - Intent intent = new Intent(context, RoutingActivity.class); - PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); - - RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.textsecure_appwidget); - views.setOnClickPendingIntent(R.id.icon_view, pendingIntent); - - int unread = getUnreadCount(context); - if (unread > 0) { - if (unread > 99) { - unread = 99; + public void onReceive(Context context, Intent intent) { + // Protect against rogue update broadcasts (not really a security issue, + // just filter bad broacasts out so subclasses are less likely to crash). + String action = intent.getAction(); + if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) { + Bundle extras = intent.getExtras(); + if (extras != null) { + int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); + int unread = extras.getInt(UNREAD_COUNT); + if (appWidgetIds != null && appWidgetIds.length > 0) { + final int n = appWidgetIds.length; + + for (int i = 0; i < n; i++) { + int appWidgetId = appWidgetIds[i]; + + Intent clickIntent = new Intent(context, RoutingActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, clickIntent, 0); + + RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.textsecure_appwidget); + views.setOnClickPendingIntent(R.id.icon_view, pendingIntent); + + if (unread > 0) { + if (unread > 9) + views.setTextViewText(R.id.unread_count_text, "9+"); + else + views.setTextViewText(R.id.unread_count_text, Integer.toString(unread)); + views.setViewVisibility(R.id.unread_count_text, View.VISIBLE); + } else { + views.setViewVisibility(R.id.unread_count_text, View.INVISIBLE); + } + + AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, views); + } } - - views.setTextViewText(R.id.unread_count_text, Integer.toString(unread)); - views.setViewVisibility(R.id.unread_count_text, View.VISIBLE); - } else { - views.setViewVisibility(R.id.unread_count_text, View.INVISIBLE); } - - appWidgetManager.updateAppWidget(appWidgetId, views); - } + } else + super.onReceive(context, intent); } }