From 0b59b8d0ac19e7b69ee166c933e156677d8f97bc Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Mon, 12 Feb 2018 22:03:08 +0100 Subject: [PATCH] notification improvements (#522) * correctly filter notifications on Api >= 26, other fixes and refactoring * use correct areNotificationsEnabled method in MainActivity * change notification led color --- .../com/keylesspalace/tusky/BaseActivity.java | 2 +- .../com/keylesspalace/tusky/MainActivity.java | 18 ++--- .../tusky/NotificationPullJobCreator.java | 6 +- .../keylesspalace/tusky/SplashActivity.java | 4 +- .../keylesspalace/tusky/db/AccountManager.kt | 20 ++--- .../NotificationClearBroadcastReceiver.kt | 4 +- ...onManager.java => NotificationHelper.java} | 79 +++++++++++++------ 7 files changed, 78 insertions(+), 55 deletions(-) rename app/src/main/java/com/keylesspalace/tusky/util/{NotificationManager.java => NotificationHelper.java} (80%) diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java index 4b203f897..af93a464e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java @@ -201,11 +201,11 @@ public abstract class BaseActivity extends AppCompatActivity { } protected void setPullNotificationCheckInterval(long minutes) { - JobManager.instance().cancelAllForTag(NotificationPullJobCreator.NOTIFICATIONS_JOB_TAG); long checkInterval = 1000 * 60 * minutes; new JobRequest.Builder(NotificationPullJobCreator.NOTIFICATIONS_JOB_TAG) .setPeriodic(checkInterval) + .setUpdateCurrent(true) .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) .build() .schedule(); diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java index 7b69ba569..1a3f70130 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java @@ -42,7 +42,7 @@ import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.interfaces.ActionButtonActivity; import com.keylesspalace.tusky.pager.TimelinePagerAdapter; import com.keylesspalace.tusky.receiver.TimelineReceiver; -import com.keylesspalace.tusky.util.NotificationManager; +import com.keylesspalace.tusky.util.NotificationHelper; import com.keylesspalace.tusky.util.ThemeUtils; import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.materialdrawer.AccountHeader; @@ -96,9 +96,9 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity { Intent intent = getIntent(); int tabPosition = 0; - + if (intent != null) { - long accountId = intent.getLongExtra(NotificationManager.ACCOUNT_ID, -1); + long accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1); if(accountId != -1) { // user clicked a notification, show notification tab and switch user if necessary @@ -181,7 +181,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity { tintTab(tab, true); if(tab.getPosition() == 1) { - NotificationManager.clearNotificationsForActiveAccount(MainActivity.this); + NotificationHelper.clearNotificationsForActiveAccount(MainActivity.this); } } @@ -199,7 +199,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity { } // Setup push notifications - if (TuskyApplication.getAccountManager().notificationsEnabled()) { + if (NotificationHelper.areNotificationsEnabled(this)) { enablePushNotifications(); } else { disablePushNotifications(); @@ -212,7 +212,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity { protected void onResume() { super.onResume(); - NotificationManager.clearNotificationsForActiveAccount(this); + NotificationHelper.clearNotificationsForActiveAccount(this); /* After editing a profile, the profile header in the navigation drawer needs to be * refreshed */ @@ -437,11 +437,11 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity { AccountManager accountManager = TuskyApplication.getAccountManager(); - NotificationManager.deleteNotificationChannelsForAccount(accountManager.getActiveAccount(), MainActivity.this); + NotificationHelper.deleteNotificationChannelsForAccount(accountManager.getActiveAccount(), MainActivity.this); AccountEntity newAccount = accountManager.logActiveAccountOut(); - if (!accountManager.notificationsEnabled()) disablePushNotifications(); + if (!NotificationHelper.areNotificationsEnabled(MainActivity.this)) disablePushNotifications(); Intent intent; if (newAccount == null) { @@ -490,7 +490,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity { am.updateActiveAccount(me); - NotificationManager.createNotificationChannelsForAccount(am.getActiveAccount(), this); + NotificationHelper.createNotificationChannelsForAccount(am.getActiveAccount(), this); List allAccounts = am.getAllAccountsOrderedByActive(); diff --git a/app/src/main/java/com/keylesspalace/tusky/NotificationPullJobCreator.java b/app/src/main/java/com/keylesspalace/tusky/NotificationPullJobCreator.java index b1b775cb9..0561fda12 100644 --- a/app/src/main/java/com/keylesspalace/tusky/NotificationPullJobCreator.java +++ b/app/src/main/java/com/keylesspalace/tusky/NotificationPullJobCreator.java @@ -30,7 +30,7 @@ import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.entity.Notification; import com.keylesspalace.tusky.json.SpannedTypeAdapter; import com.keylesspalace.tusky.network.MastodonApi; -import com.keylesspalace.tusky.util.NotificationManager; +import com.keylesspalace.tusky.util.NotificationHelper; import com.keylesspalace.tusky.util.OkHttpUtils; import java.io.IOException; @@ -98,7 +98,7 @@ public final class NotificationPullJobCreator implements JobCreator { @NonNull @Override - protected Result onRunJob(Params params) { + protected Result onRunJob(@NonNull Params params) { List accountList = new ArrayList<>(TuskyApplication.getAccountManager().getAllAccountsOrderedByActive()); @@ -144,7 +144,7 @@ public final class NotificationPullJobCreator implements JobCreator { if (isBiggerThan(currentId, newId)) { account.setLastNotificationId(notification.id); - NotificationManager.make(context, notification, account); + NotificationHelper.make(context, notification, account); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/SplashActivity.java b/app/src/main/java/com/keylesspalace/tusky/SplashActivity.java index 2445111ec..c2390b876 100644 --- a/app/src/main/java/com/keylesspalace/tusky/SplashActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/SplashActivity.java @@ -20,7 +20,7 @@ import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import com.keylesspalace.tusky.db.AccountEntity; -import com.keylesspalace.tusky.util.NotificationManager; +import com.keylesspalace.tusky.util.NotificationHelper; public class SplashActivity extends AppCompatActivity { @Override @@ -30,7 +30,7 @@ public class SplashActivity extends AppCompatActivity { /* Determine whether the user is currently logged in, and if so go ahead and load the * timeline. Otherwise, start the activity_login screen. */ - NotificationManager.deleteLegacyNotificationChannels(this); + NotificationHelper.deleteLegacyNotificationChannels(this); AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt index b28c01371..e0f09b652 100644 --- a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt +++ b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt @@ -24,6 +24,8 @@ import com.keylesspalace.tusky.entity.Account * @author ConnyDuck */ +private const val TAG = "AccountManager" + class AccountManager { @Volatile var activeAccount: AccountEntity? = null @@ -50,7 +52,7 @@ class AccountManager { activeAccount?.let{ it.isActive = false - Log.d("AccountManager", "saving account with id "+it.id) + Log.d(TAG, "addAccount: saving account with id "+it.id) accountDao.insertOrReplace(it) } @@ -66,13 +68,7 @@ class AccountManager { */ fun saveAccount(account: AccountEntity) { if(account.id != 0L) { - Log.d("AccountManager", "saving account with id "+account.id) - val index = accounts.indexOf(account) - if (index != -1) { - accounts.removeAt(index) - accounts.add(account) - } - + Log.d(TAG, "saveAccount: saving account with id "+account.id) accountDao.insertOrReplace(account) } @@ -93,6 +89,7 @@ class AccountManager { if(accounts.size > 0) { accounts[0].isActive = true activeAccount = accounts[0] + Log.d(TAG, "logActiveAccountOut: saving account with id "+accounts[0].id) accountDao.insertOrReplace(accounts[0]) } else { activeAccount = null @@ -115,10 +112,8 @@ class AccountManager { it.displayName = account.getDisplayName() it.profilePictureUrl = account.avatar - Log.d("AccountManager", "id before save "+it.id) + Log.d(TAG, "updateActiveAccount: saving account with id "+it.id) it.id = accountDao.insertOrReplace(it) - Log.d("AccountManager", "id after save "+it.id) - val accountIndex = accounts.indexOf(it) @@ -140,6 +135,7 @@ class AccountManager { fun setActiveAccount(accountId: Long) { activeAccount?.let{ + Log.d(TAG, "setActiveAccount: saving account with id "+it.id) it.isActive = false accountDao.insertOrReplace(it) } @@ -172,7 +168,7 @@ class AccountManager { /** * @return true if at least one account has notifications enabled */ - fun notificationsEnabled(): Boolean { + fun areNotificationsEnabled(): Boolean { return accounts.any { it.notificationsEnabled } } diff --git a/app/src/main/java/com/keylesspalace/tusky/receiver/NotificationClearBroadcastReceiver.kt b/app/src/main/java/com/keylesspalace/tusky/receiver/NotificationClearBroadcastReceiver.kt index be8f84b26..bb47ce654 100644 --- a/app/src/main/java/com/keylesspalace/tusky/receiver/NotificationClearBroadcastReceiver.kt +++ b/app/src/main/java/com/keylesspalace/tusky/receiver/NotificationClearBroadcastReceiver.kt @@ -20,12 +20,12 @@ import android.content.Context import android.content.Intent import com.keylesspalace.tusky.TuskyApplication -import com.keylesspalace.tusky.util.NotificationManager +import com.keylesspalace.tusky.util.NotificationHelper class NotificationClearBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { - val accountId = intent.getLongExtra(NotificationManager.ACCOUNT_ID, -1) + val accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1) val accountManager = TuskyApplication.getAccountManager() val account = accountManager.getAccountById(accountId) diff --git a/app/src/main/java/com/keylesspalace/tusky/util/NotificationManager.java b/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java similarity index 80% rename from app/src/main/java/com/keylesspalace/tusky/util/NotificationManager.java rename to app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java index 05dc5fd32..ef0cda87f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/NotificationManager.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java @@ -17,6 +17,7 @@ package com.keylesspalace.tusky.util; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -47,12 +48,12 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -public class NotificationManager { +public class NotificationHelper { /** constants used in Intents */ public static final String ACCOUNT_ID = "account_id"; - private static final String TAG = "NotificationManager"; + private static final String TAG = "NotificationHelper"; /** notification channels used on Android O+ **/ private static final String CHANNEL_MENTION = "CHANNEL_MENTION"; @@ -71,7 +72,7 @@ public class NotificationManager { public static void make(final Context context, Notification body, AccountEntity account) { - if (!filterNotification(account, body)) { + if (!filterNotification(account, body, context)) { return; } @@ -166,8 +167,7 @@ public class NotificationManager { builder.setVisibility(NotificationCompat.VISIBILITY_PRIVATE); builder.setCategory(NotificationCompat.CATEGORY_SOCIAL); - android.app.NotificationManager notificationManager = (android.app.NotificationManager) - context.getSystemService(Context.NOTIFICATION_SERVICE); + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); //noinspection ConstantConditions notificationManager.notify((int)account.getId(), builder.build()); @@ -176,8 +176,7 @@ public class NotificationManager { public static void createNotificationChannelsForAccount(AccountEntity account, Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - android.app.NotificationManager mNotificationManager = - (android.app.NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); String[] channelIds = new String[]{ CHANNEL_MENTION+account.getIdentifier(), @@ -202,17 +201,18 @@ public class NotificationManager { NotificationChannelGroup channelGroup = new NotificationChannelGroup(account.getIdentifier(), account.getFullName()); //noinspection ConstantConditions - mNotificationManager.createNotificationChannelGroup(channelGroup); + notificationManager.createNotificationChannelGroup(channelGroup); for (int i = 0; i < channelIds.length; i++) { String id = channelIds[i]; String name = context.getString(channelNames[i]); String description = context.getString(channelDescriptions[i]); - int importance = android.app.NotificationManager.IMPORTANCE_DEFAULT; + int importance = NotificationManager.IMPORTANCE_DEFAULT; NotificationChannel channel = new NotificationChannel(id, name, importance); channel.setDescription(description); channel.enableLights(true); + channel.setLightColor(0xFF2B90D9); channel.enableVibration(true); channel.setShowBadge(true); channel.setGroup(account.getIdentifier()); @@ -220,7 +220,7 @@ public class NotificationManager { } //noinspection ConstantConditions - mNotificationManager.createNotificationChannels(channels); + notificationManager.createNotificationChannels(channels); } } @@ -228,11 +228,10 @@ public class NotificationManager { public static void deleteNotificationChannelsForAccount(AccountEntity account, Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - android.app.NotificationManager mNotificationManager = - (android.app.NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); //noinspection ConstantConditions - mNotificationManager.deleteNotificationChannelGroup(account.getIdentifier()); + notificationManager.deleteNotificationChannelGroup(account.getIdentifier()); } } @@ -241,17 +240,42 @@ public class NotificationManager { // delete the notification channels that where used before the multi account mode was introduced to avoid confusion if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - android.app.NotificationManager mNotificationManager = - (android.app.NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); //noinspection ConstantConditions - mNotificationManager.deleteNotificationChannel(CHANNEL_MENTION); - mNotificationManager.deleteNotificationChannel(CHANNEL_FAVOURITE); - mNotificationManager.deleteNotificationChannel(CHANNEL_BOOST); - mNotificationManager.deleteNotificationChannel(CHANNEL_FOLLOW); + notificationManager.deleteNotificationChannel(CHANNEL_MENTION); + notificationManager.deleteNotificationChannel(CHANNEL_FAVOURITE); + notificationManager.deleteNotificationChannel(CHANNEL_BOOST); + notificationManager.deleteNotificationChannel(CHANNEL_FOLLOW); } } + public static boolean areNotificationsEnabled(Context context) { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + + // on Android >= O, notifications are enabled, if at least one channel is enabled + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + //noinspection ConstantConditions + if(notificationManager.areNotificationsEnabled()) { + for(NotificationChannel channel: notificationManager.getNotificationChannels()) { + if(channel.getImportance() > NotificationManager.IMPORTANCE_NONE) { + Log.d(TAG, "NotificationsEnabled"); + return true; + } + } + } + Log.d(TAG, "NotificationsDisabled"); + + return false; + + } else { + // on Android < O, notifications are enabled, if at least one account has notification enabled + return TuskyApplication.getAccountManager().areNotificationsEnabled(); + } + + } + public static void clearNotificationsForActiveAccount(Context context) { AccountManager accountManager = TuskyApplication.getAccountManager(); AccountEntity account = accountManager.getActiveAccount(); @@ -259,18 +283,21 @@ public class NotificationManager { account.setActiveNotifications("[]"); accountManager.saveAccount(account); - android.app.NotificationManager manager = (android.app.NotificationManager) - context.getSystemService(Context.NOTIFICATION_SERVICE); + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); //noinspection ConstantConditions - manager.cancel((int)account.getId()); + notificationManager.cancel((int)account.getId()); } } - private static boolean filterNotification(AccountEntity account, - Notification notification) { + private static boolean filterNotification(AccountEntity account, Notification notification, + Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - return true; //do not filter on Android O or newer, the system does it for us + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + //noinspection ConstantConditions + NotificationChannel channel = notificationManager.getNotificationChannel(getChannelId(account, notification)); + return channel.getImportance() > NotificationManager.IMPORTANCE_NONE; } switch (notification.type) { @@ -317,7 +344,7 @@ public class NotificationManager { } if (account.getNotificationLight()) { - builder.setLights(0xFF00FF8F, 300, 1000); + builder.setLights(0xFF2B90D9, 300, 1000); } }