1
0
mirror of https://github.com/nerzhul/ownCloud-SMS-App.git synced 2025-06-06 23:46:13 +00:00

Fix notifications not being shown on modern Androids (#221)

* Add notification channels support

* Update Travis CI config
This commit is contained in:
Dmitriy Bogdanov 2025-01-23 18:47:17 +01:00 committed by GitHub
parent 5ea03be8d6
commit 7d677a9fe2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 134 additions and 42 deletions

View File

@ -12,15 +12,15 @@ jdk:
- oraclejdk8 - oraclejdk8
before_install: before_install:
- yes | sdkmanager "platforms;android-27" - yes | sdkmanager "platforms;android-28"
android: android:
components: components:
- tools - tools
- platform-tools - platform-tools
- extra - extra
- build-tools-27.0.3 - build-tools-28.0.3
- android-27 - android-28
licenses: licenses:
- 'android-sdk-license-.+' - 'android-sdk-license-.+'
- 'google-gdk-license-.+' - 'google-gdk-license-.+'

View File

@ -93,12 +93,16 @@ public interface ASyncSMSSync {
if (prefs.showSyncNotifications()) { if (prefs.showSyncNotifications()) {
OCSMSNotificationUI.notify(_context, _context.getString(R.string.sync_title), OCSMSNotificationUI.notify(_context, _context.getString(R.string.sync_title),
_context.getString(R.string.sync_inprogress), OCSMSNotificationType.SYNC.ordinal()); _context.getString(R.string.sync_inprogress), OCSMSNotificationType.SYNC);
} }
syncStartupDate = smsBuffer.getLastMessageDate(); try {
performSync(smsBuffer); syncStartupDate = smsBuffer.getLastMessageDate();
hasSyncSomething = true; performSync(smsBuffer);
hasSyncSomething = true;
} finally {
OCSMSNotificationUI.cancel(_context, OCSMSNotificationType.SYNC);
}
} }
} }
@ -114,17 +118,16 @@ public interface ASyncSMSSync {
// Fetch API version first to do some early verifications // Fetch API version first to do some early verifications
Log.i(ASyncSMSSync.TAG, "Server API version: " + _client.getServerAPIVersion()); Log.i(ASyncSMSSync.TAG, "Server API version: " + _client.getServerAPIVersion());
_client.doPushRequest(smsBuffer); _client.doPushRequest(smsBuffer);
OCSMSNotificationUI.cancel(_context); OCSMSNotificationUI.cancel(_context, OCSMSNotificationType.SYNC_FAILED);
} catch (IllegalStateException e) { // Fail to read account data } catch (IllegalStateException e) { // Fail to read account data
OCSMSNotificationUI.notify(_context, _context.getString(R.string.fatal_error), OCSMSNotificationUI.notify(_context, _context.getString(R.string.fatal_error),
e.getMessage(), OCSMSNotificationType.SYNC_FAILED.ordinal()); e.getMessage(), OCSMSNotificationType.SYNC_FAILED);
} catch (OCSyncException e) { } catch (OCSyncException e) {
Log.e(ASyncSMSSync.TAG, _context.getString(e.getErrorId())); Log.e(ASyncSMSSync.TAG, _context.getString(e.getErrorId()));
OCSMSNotificationUI.notify(_context, _context.getString(R.string.fatal_error), OCSMSNotificationUI.notify(_context, _context.getString(R.string.fatal_error),
e.getMessage(), OCSMSNotificationType.SYNC_FAILED.ordinal()); e.getMessage(), OCSMSNotificationType.SYNC_FAILED);
} }
} }
OCSMSNotificationUI.cancel(_context);
smsBuffer.clear(); smsBuffer.clear();
} }

View File

@ -0,0 +1,48 @@
package fr.unix_experience.owncloud_sms.enums;
import android.app.NotificationManager;
import android.os.Build;
import android.support.annotation.StringRes;
import fr.unix_experience.owncloud_sms.R;
public enum OCSMSNotificationChannel {
DEFAULT("OCSMS_DEFAULT", R.string.notification_channel_name_default, null),
SYNC("OCSMS_SYNC", R.string.notification_channel_name_sync, null);
static {
// well, that's a bit of a hack :/
// can be inlined in the future
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
DEFAULT.importance = NotificationManager.IMPORTANCE_DEFAULT;
SYNC.importance = NotificationManager.IMPORTANCE_LOW;
}
}
private final String channelId;
private final int nameResId;
private final Integer descResId;
private int importance;
OCSMSNotificationChannel(String channelId, @StringRes int nameResId, @StringRes Integer descResId) {
this.channelId = channelId;
this.nameResId = nameResId;
this.descResId = descResId;
}
public String getChannelId() {
return channelId;
}
public int getNameResId() {
return nameResId;
}
public Integer getDescResId() {
return descResId;
}
public int getImportance() {
return importance;
}
}

View File

@ -18,8 +18,23 @@ package fr.unix_experience.owncloud_sms.enums;
*/ */
public enum OCSMSNotificationType { public enum OCSMSNotificationType {
SYNC, SYNC(OCSMSNotificationChannel.SYNC, 0),
SYNC_FAILED, SYNC_FAILED(OCSMSNotificationChannel.DEFAULT, 1),
DEBUG, PERMISSION(OCSMSNotificationChannel.DEFAULT, 2);
PERMISSION,
private final OCSMSNotificationChannel channel;
private final int notificationId;
OCSMSNotificationType(OCSMSNotificationChannel channel, int notificationId) {
this.channel = channel;
this.notificationId = notificationId;
}
public OCSMSNotificationChannel getChannel() {
return channel;
}
public int getNotificationId() {
return notificationId;
}
} }

View File

@ -17,17 +17,17 @@ package fr.unix_experience.owncloud_sms.notifications;
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import android.annotation.TargetApi;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build; import android.os.Build;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import fr.unix_experience.owncloud_sms.R; import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.enums.OCSMSNotificationChannel;
import fr.unix_experience.owncloud_sms.enums.OCSMSNotificationType;
/** /**
* Helper class for showing and canceling ui * Helper class for showing and canceling ui
@ -42,25 +42,30 @@ public class OCSMSNotificationUI {
*/ */
private static final String NOTIFICATION_TAG = "OCSMS_NOTIFICATION"; private static final String NOTIFICATION_TAG = "OCSMS_NOTIFICATION";
public static void notify(Context context, String titleString,
String contentString, OCSMSNotificationType type) {
notify(context, titleString, contentString,
type.getChannel().getChannelId(), type.getNotificationId());
}
/** /**
* Shows the notification, or updates a previously shown notification of * Shows the notification, or updates a previously shown notification of
* this type, with the given parameters. * this type, with the given parameters.
* *
* @see #cancel(Context) * @see #cancel(Context, OCSMSNotificationType)
*/ */
public static void notify(Context context, String titleString, public static void notify(Context context, String titleString, String contentString,
String contentString, int number) { String channelId, int notificationId) {
Resources res = context.getResources(); Resources res = context.getResources();
// This image is used as the notification's large icon (thumbnail). // This image is used as the notification's large icon (thumbnail).
// TODO: Remove this if your notification has no relevant thumbnail. // TODO: Remove this if your notification has no relevant thumbnail.
Bitmap picture = BitmapFactory.decodeResource(res, R.mipmap.ic_launcher); // Bitmap picture = BitmapFactory.decodeResource(res, R.mipmap.ic_launcher);
// String ticker = (titleString.length() > 20) ? titleString.substring(0, 20) : titleString;
String ticker = (titleString.length() > 20) ? titleString.substring(0, 20) : titleString;
String title = res.getString(R.string.ui_notification_title_template, titleString); String title = res.getString(R.string.ui_notification_title_template, titleString);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context) NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
// Set appropriate defaults for the notification light, sound, // Set appropriate defaults for the notification light, sound,
// and vibration. // and vibration.
@ -77,9 +82,6 @@ public class OCSMSNotificationUI {
// Set ticker text (preview) information for this notification. // Set ticker text (preview) information for this notification.
//.setTicker(ticker) //.setTicker(ticker)
// Show a number. This is useful when stacking notifications of
// a single type.
.setNumber(number)
.setStyle(new NotificationCompat.BigTextStyle() .setStyle(new NotificationCompat.BigTextStyle()
.bigText(contentString) .bigText(contentString)
.setBigContentTitle(title) .setBigContentTitle(title)
@ -87,24 +89,45 @@ public class OCSMSNotificationUI {
.setAutoCancel(true) .setAutoCancel(true)
.setColor(context.getResources().getColor(R.color.oc_primary)); .setColor(context.getResources().getColor(R.color.oc_primary));
OCSMSNotificationUI.notify(context, builder.build()); notify(context, builder.build(), notificationId);
} }
@TargetApi(Build.VERSION_CODES.ECLAIR) private static void notify(Context context, Notification notification, int notificationId) {
private static void notify(Context context, Notification notification) {
NotificationManager nm = (NotificationManager) context NotificationManager nm = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE); .getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(OCSMSNotificationUI.NOTIFICATION_TAG, 0, notification); createNotificationChannels(context, nm);
nm.notify(OCSMSNotificationUI.NOTIFICATION_TAG, notificationId, notification);
} }
/** /**
* Cancels any notifications of this type previously shown using * Cancels any notifications of this type previously shown using
* {@link #notify(Context, String, String, int)}. * {@link #notify(Context, String, String, OCSMSNotificationType)}.
*/ */
@TargetApi(Build.VERSION_CODES.ECLAIR) public static void cancel(Context context, OCSMSNotificationType type) {
public static void cancel(Context context) { cancel(context, type.getNotificationId());
}
public static void cancel(Context context, int notificationId) {
NotificationManager nm = (NotificationManager) context NotificationManager nm = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE); .getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel(OCSMSNotificationUI.NOTIFICATION_TAG, 0); nm.cancel(OCSMSNotificationUI.NOTIFICATION_TAG, notificationId);
} }
private static void createNotificationChannels(Context context, NotificationManager nm) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
for (OCSMSNotificationChannel ocsmsChannel : OCSMSNotificationChannel.values()) {
NotificationChannel channel = new NotificationChannel(
ocsmsChannel.getChannelId(),
context.getString(ocsmsChannel.getNameResId()),
ocsmsChannel.getImportance());
if (ocsmsChannel.getDescResId() != null) {
channel.setDescription(context.getString(ocsmsChannel.getDescResId()));
}
nm.createNotificationChannel(channel);
}
}
}
} }

View File

@ -67,7 +67,7 @@ public class PermissionChecker {
// For context only show a notification // For context only show a notification
OCSMSNotificationUI.notify(context, context.getString(R.string.notif_permission_required), OCSMSNotificationUI.notify(context, context.getString(R.string.notif_permission_required),
context.getString(R.string.notif_permission_required_content), context.getString(R.string.notif_permission_required_content),
OCSMSNotificationType.PERMISSION.ordinal()); OCSMSNotificationType.PERMISSION);
return false; return false;
} }

View File

@ -45,7 +45,7 @@ class SmsSyncAdapter extends AbstractThreadedSyncAdapter {
if (new OCSMSSharedPrefs(getContext()).showSyncNotifications()) { if (new OCSMSSharedPrefs(getContext()).showSyncNotifications()) {
OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.sync_title), OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.sync_title),
getContext().getString(R.string.sync_inprogress), OCSMSNotificationType.SYNC.ordinal()); getContext().getString(R.string.sync_inprogress), OCSMSNotificationType.SYNC);
} }
try { try {
@ -56,14 +56,13 @@ class SmsSyncAdapter extends AbstractThreadedSyncAdapter {
// and push datas // and push datas
_client.doPushRequest(null); _client.doPushRequest(null);
OCSMSNotificationUI.cancel(getContext()); OCSMSNotificationUI.cancel(getContext(), OCSMSNotificationType.SYNC_FAILED);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error), OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error),
e.getMessage(), OCSMSNotificationType.SYNC_FAILED.ordinal()); e.getMessage(), OCSMSNotificationType.SYNC_FAILED);
} catch (OCSyncException e) { } catch (OCSyncException e) {
OCSMSNotificationUI.cancel(getContext());
OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error), OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error),
getContext().getString(e.getErrorId()), OCSMSNotificationType.SYNC_FAILED.ordinal()); getContext().getString(e.getErrorId()), OCSMSNotificationType.SYNC_FAILED);
if (e.getErrorType() == OCSyncErrorType.IO) { if (e.getErrorType() == OCSyncErrorType.IO) {
syncResult.stats.numIoExceptions++; syncResult.stats.numIoExceptions++;
} }
@ -76,6 +75,8 @@ class SmsSyncAdapter extends AbstractThreadedSyncAdapter {
else { else {
Log.w(SmsSyncAdapter.TAG, "onPerformSync: unhandled response"); Log.w(SmsSyncAdapter.TAG, "onPerformSync: unhandled response");
} }
} finally {
OCSMSNotificationUI.cancel(getContext(), OCSMSNotificationType.SYNC);
} }
} }

View File

@ -206,6 +206,8 @@
<string name="sync_title">Sync process</string> <string name="sync_title">Sync process</string>
<string name="sync_inprogress">Sync in progress …</string> <string name="sync_inprogress">Sync in progress …</string>
<string name="fatal_error">Fatal error ! </string> <string name="fatal_error">Fatal error ! </string>
<string name="notification_channel_name_default">Default</string>
<string name="notification_channel_name_sync">Sync</string>
<!-- Errors --> <!-- Errors -->
<string name="err_sync_get_smslist">Error #1: Invalid data received from server when getting previous messages</string> <string name="err_sync_get_smslist">Error #1: Invalid data received from server when getting previous messages</string>