From d65d63b82bc80b2bdf1265fbf8b5cddcd605400a Mon Sep 17 00:00:00 2001 From: Conny Duck Date: Wed, 18 Oct 2017 22:18:07 +0200 Subject: [PATCH] implement notification channels, use system notification settings on android Oreo --- .../tusky/PreferencesActivity.java | 2 + .../tusky/adapter/StatusBaseViewHolder.java | 2 +- .../tusky/fragment/PreferencesFragment.java | 26 ++++ .../service/PullNotificationService.java | 4 + .../tusky/util/NotificationMaker.java | 90 ++++++++++++- app/src/main/res/values/strings.xml | 10 ++ app/src/main/res/xml/preferences.xml | 126 +++++++++--------- 7 files changed, 192 insertions(+), 68 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.java b/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.java index 716747ee..fe6de818 100644 --- a/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.java @@ -46,6 +46,8 @@ public class PreferencesActivity extends BaseActivity getFragmentManager().beginTransaction() .replace(android.R.id.content, new PreferencesFragment()) .commit(); + + } private void saveInstanceState(Bundle outState) { diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java index 7962a506..9675d9d2 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -229,7 +229,7 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder { } } SharedPreferences pm = PreferenceManager.getDefaultSharedPreferences(context); - Boolean isAlwayShowSensitive = pm.getBoolean("alwayShowSensitiveMedia",false); + Boolean isAlwayShowSensitive = pm.getBoolean("alwayShowSensitiveMedia", false); if (sensitive && (!isAlwayShowSensitive)) { sensitiveMediaWarning.setVisibility(showingSensitive ? View.GONE : View.VISIBLE); sensitiveMediaShow.setVisibility(showingSensitive ? View.VISIBLE : View.GONE); diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java index 280098a7..7b2bbe39 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java @@ -15,9 +15,14 @@ package com.keylesspalace.tusky.fragment; +import android.content.Intent; +import android.os.Build; import android.os.Bundle; +import android.preference.Preference; import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; +import com.keylesspalace.tusky.BuildConfig; import com.keylesspalace.tusky.R; public class PreferencesFragment extends PreferenceFragment { @@ -25,5 +30,26 @@ public class PreferencesFragment extends PreferenceFragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); + + + //on Android O and newer, launch the system notification settings instead of the app settings + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + PreferenceScreen notificationPreferences = (PreferenceScreen) findPreference("notificationSettings"); + notificationPreferences.removeAll(); + notificationPreferences.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(); + intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); + + intent.putExtra("android.provider.extra.APP_PACKAGE", BuildConfig.APPLICATION_ID); + + startActivity(intent); + return true; + } + }); + + + } } } diff --git a/app/src/main/java/com/keylesspalace/tusky/service/PullNotificationService.java b/app/src/main/java/com/keylesspalace/tusky/service/PullNotificationService.java index fa4a18c0..237826ba 100644 --- a/app/src/main/java/com/keylesspalace/tusky/service/PullNotificationService.java +++ b/app/src/main/java/com/keylesspalace/tusky/service/PullNotificationService.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.text.Spanned; +import android.util.Log; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -58,6 +59,9 @@ public class PullNotificationService extends IntentService { @Override protected void onHandleIntent(Intent intent) { + + Log.d("PullNotifications", "pulling for notification"); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences( getApplicationContext()); boolean enabled = preferences.getBoolean("notificationsEnabled", true); diff --git a/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java b/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java index 04f27e62..97555013 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.util; +import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; @@ -28,6 +29,7 @@ import android.provider.Settings; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; +import android.support.v4.content.ContextCompat; import android.util.Log; import com.keylesspalace.tusky.MainActivity; @@ -41,9 +43,18 @@ import com.squareup.picasso.Target; import org.json.JSONArray; import org.json.JSONException; +import java.util.ArrayList; +import java.util.List; + public class NotificationMaker { public static final String TAG = "NotificationMaker"; + /** notification channels used on Android O+ **/ + private static final String CHANNEL_MENTION = "CHANNEL_MENTION"; + private static final String CHANNEL_FOLLOW = "CHANNEL_FOLLOW"; + private static final String CHANNEL_BOOST = "CHANNEL_BOOST"; + private static final String CHANNEL_FAVOURITE =" CHANNEL_FAVOURITE"; + /** * Takes a given Mastodon notification and either creates a new Android notification or updates * the state of the existing notification to reflect the new interaction. @@ -62,6 +73,8 @@ public class NotificationMaker { return; } + createNotificationChannels(context); + String rawCurrentNotifications = notificationPreferences.getString("current", "[]"); JSONArray currentNotifications; @@ -103,12 +116,15 @@ public class NotificationMaker { PendingIntent deletePendingIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT); - final NotificationCompat.Builder builder = new NotificationCompat.Builder(context) + final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getChannelId(body)) .setSmallIcon(R.drawable.ic_notify) .setContentIntent(resultPendingIntent) .setDeleteIntent(deletePendingIntent) + .setColor(ContextCompat.getColor(context, (R.color.primary))) .setDefaults(0); // So it doesn't ring twice, notify only in Target callback + setupPreferences(preferences, builder); + if (currentNotifications.length() == 1) { builder.setContentTitle(titleForType(context, body)) .setContentText(truncateWithEllipses(bodyForType(body), 40)); @@ -118,8 +134,6 @@ public class NotificationMaker { public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { builder.setLargeIcon(bitmap); - setupPreferences(preferences, builder); - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(notifyId, builder.build()); @@ -138,7 +152,6 @@ public class NotificationMaker { .transform(new RoundedTransformation(7, 0)) .into(target); } else { - setupPreferences(preferences, builder); try { String format = context.getString(R.string.notification_title_summary); String title = String.format(format, currentNotifications.length()); @@ -160,9 +173,55 @@ public class NotificationMaker { notificationManager.notify(notifyId, builder.build()); } + private static void createNotificationChannels(Context context) { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + + NotificationManager mNotificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + String[] channelIds = new String[]{CHANNEL_MENTION, CHANNEL_FOLLOW, CHANNEL_BOOST, CHANNEL_FAVOURITE}; + int[] channelNames = { + R.string.notification_channel_mention_name, + R.string.notification_channel_follow_name, + R.string.notification_channel_boost_name, + R.string.notification_channel_favourite_name + }; + int[] channelDescriptions = { + R.string.notification_channel_mention_descriptions, + R.string.notification_channel_follow_description, + R.string.notification_channel_boost_description, + R.string.notification_channel_favourite_description + }; + + List channels = new ArrayList<>(4); + + for(int i=0; i= Build.VERSION_CODES.O) { + return true; //do not filter on Android O or newer, the system does it for us + } + + switch (notification.type) { default: case MENTION: return preferences.getBoolean("notificationFilterMentions", true); @@ -175,6 +234,21 @@ public class NotificationMaker { } } + private static String getChannelId(Notification notification) { + switch (notification.type) { + default: + case MENTION: + return CHANNEL_MENTION; + case FOLLOW: + return CHANNEL_FOLLOW; + case REBLOG: + return CHANNEL_BOOST; + case FAVOURITE: + return CHANNEL_FAVOURITE; + } + + } + private static String truncateWithEllipses(String string, int limit) { if (string.length() < limit) { return string; @@ -185,6 +259,11 @@ public class NotificationMaker { private static void setupPreferences(SharedPreferences preferences, NotificationCompat.Builder builder) { + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return; //do nothing on Android O or newer, the system uses the channel settings anyway + } + if (preferences.getBoolean("notificationAlertSound", true)) { builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI); } @@ -245,4 +324,5 @@ public class NotificationMaker { } return null; } + } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c58869c8..0d760b64 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -173,6 +173,16 @@ Show replies Show media previews + New Mentions + Notifications about new mentions + New Followers + Notifications about new followers + Boosts + Notifications when your toots get boosted + Favourites + Notifications when your toots get mark as favourite + + %s mentioned you %1$s, %2$s, %3$s and %4$d others %1$s, %2$s, and %3$s diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index ab655157..bfec7274 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -5,114 +5,116 @@ + android:title="@string/pref_title_light_theme" /> + android:title="@string/pref_title_hide_follow_button" /> + android:title="@string/pref_title_show_media_preview" /> + android:title="@string/pref_title_alway_show_sensitive_media" /> + android:title="@string/pref_title_custom_tabs" /> - + + android:title="@string/pref_title_show_boosts" /> + android:title="@string/pref_title_show_replies" /> - - - - + android:title="@string/pref_title_pull_notification_check_interval" /> - + + android:defaultValue="true" + android:key="notificationsEnabled" + android:title="@string/pref_title_notifications_enabled" /> - + - + - + + + - + - + - + - + - + + + - + - +