Skip to content

Commit b68982c

Browse files
committed
Merge branch 'master' into innogames-feature/ShowInForeground-feature-for-Android
2 parents f0c3d80 + 2653cec commit b68982c

File tree

5 files changed

+109
-30
lines changed

5 files changed

+109
-30
lines changed

TestProjects/com.unity.mobile-notifications-sample/Assets/Scripts/AndroidTest.cs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,20 @@ public class AndroidTest : MonoBehaviour
2020
private Dictionary<string, OrderedDictionary> m_groups;
2121
private Logger m_LOGGER;
2222
private int _notificationExplicitID;
23-
private Button ButtonExplicitID;
23+
private Button ButtonModifyExplicitID;
24+
private Button ButtonCancelExplicitID;
25+
private Button ButtonCheckStatusExplicitID;
2426

2527
public int notificationExplicitID
2628
{
2729
get { return _notificationExplicitID; }
2830
set
2931
{
3032
_notificationExplicitID = value;
31-
if (_notificationExplicitID == 0)
32-
{
33-
ButtonExplicitID.interactable = false;
34-
}
35-
else
36-
{
37-
ButtonExplicitID.interactable = true;
38-
}
33+
bool buttonsEnabled = _notificationExplicitID != 0;
34+
ButtonModifyExplicitID.interactable = buttonsEnabled;
35+
ButtonCancelExplicitID.interactable = buttonsEnabled;
36+
ButtonCheckStatusExplicitID.interactable = buttonsEnabled;
3937
}
4038
}
4139

@@ -64,6 +62,7 @@ void OnNotificationReceivedHandler(AndroidNotificationIntentData notificationInt
6462
.Properties(notificationIntentData.Notification, 1);
6563
if (notificationIntentData.Id == notificationExplicitID)
6664
{
65+
AndroidNotificationCenter.CheckScheduledNotificationStatus(notificationExplicitID);
6766
notificationExplicitID = 0;
6867
}
6968
}
@@ -122,6 +121,9 @@ private void InstantiateAllTestButtons()
122121
m_groups["Modify"] = new OrderedDictionary();
123122
//m_groups["Modify"]["Create notification preset"] = new Action(() => { });
124123
m_groups["Modify"]["Modify pending Explicit notification"] = new Action(() => { ModifyExplicitNotification(); });
124+
m_groups["Modify"]["Cancel pending Explicit notification"] = new Action(() => { CancelExplicitNotification(); });
125+
m_groups["Modify"]["Check status of Explicit notification"] = new Action(() => { CheckStatusOfExplicitNotification (); });
126+
125127

126128
m_groups["Send"] = new OrderedDictionary();
127129
foreach (AndroidNotificationTemplate template in Resources.LoadAll("AndroidNotifications", typeof(AndroidNotificationTemplate)))
@@ -133,6 +135,7 @@ private void InstantiateAllTestButtons()
133135
{
134136
Title = template.Title,
135137
Text = template.Text,
138+
136139
SmallIcon = template.SmallIcon,
137140
LargeIcon = template.LargeIcon,
138141
Style = template.NotificationStyle,
@@ -236,8 +239,13 @@ private void InstantiateAllTestButtons()
236239
}
237240
buttonGameObject.gameObject.SetActive(false);
238241
}
239-
ButtonExplicitID = GameObject.Find("Modify/Modify pending Explicit notification").GetComponent<Button>();
240-
ButtonExplicitID.interactable = false;
242+
ButtonModifyExplicitID = GameObject.Find("Modify/Modify pending Explicit notification").GetComponent<Button>();
243+
ButtonModifyExplicitID.interactable = false;
244+
ButtonCancelExplicitID = GameObject.Find("Modify/Cancel pending Explicit notification").GetComponent<Button>();
245+
ButtonCancelExplicitID.interactable = false;
246+
ButtonCheckStatusExplicitID = GameObject.Find("Modify/Check status of Explicit notification").GetComponent<Button>();
247+
ButtonCheckStatusExplicitID.interactable = false;
248+
241249
m_gameObjectReferences.ButtonGroupTemplate.gameObject.SetActive(false);
242250
}
243251

@@ -255,6 +263,21 @@ public void ModifyExplicitNotification()
255263
.Properties(template, 1);
256264
}
257265

266+
public void CancelExplicitNotification()
267+
{
268+
AndroidNotificationCenter.CancelScheduledNotification(notificationExplicitID);
269+
notificationExplicitID = 0;
270+
m_LOGGER
271+
.Blue($"[{DateTime.Now.ToString("HH:mm:ss.ffffff")}] Call {MethodBase.GetCurrentMethod().Name}");
272+
}
273+
274+
public void CheckStatusOfExplicitNotification()
275+
{
276+
m_LOGGER
277+
.Blue($"[{DateTime.Now.ToString("HH:mm:ss.ffffff")}] Explicit notification (ID:{notificationExplicitID}) status: {AndroidNotificationCenter.CheckScheduledNotificationStatus(notificationExplicitID)}");
278+
279+
}
280+
258281
public void SendNotification(AndroidNotification notification, string channel = "default_channel", int notificationID = 0, bool log = true)
259282
{
260283
if (log)

com.unity.mobile.notifications/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
All notable changes to this package will be documented in this file.
44

5+
## [2.0.2] - 2022-05-13
6+
7+
### Changes & Improvements:
8+
- [Android] - AndroidNotificationCenter.CheckScheduledNotificationStatus now works on devices with all API levels
9+
10+
### Fixes:
11+
- [Android] [issue 186](https://github.com/Unity-Technologies/com.unity.mobile.notifications/issues/186) Mitigate OutOfMemory errors causing application crash
12+
- [Android] [issue 188](https://github.com/Unity-Technologies/com.unity.mobile.notifications/issues/188) Fix unguarded API usage from level 23
13+
514
## [2.0.1] - 2022-04-15
615

716
### Fixes:

com.unity.mobile.notifications/Runtime/Android/AndroidNotificationCenter.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,6 @@ public static void CancelAllDisplayedNotifications()
360360

361361
/// <summary>
362362
/// Return the status of a scheduled notification.
363-
/// Only available in API 23 and above.
364363
/// </summary>
365364
/// <param name="id">ID of the notification to check</param>
366365
/// <returns>The status of the notification</returns>

com.unity.mobile.notifications/Runtime/Android/Plugins/com/unity/androidnotifications/UnityNotificationManager.java

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class UnityNotificationManager extends BroadcastReceiver {
4141
protected static NotificationCallback mNotificationCallback;
4242
protected static UnityNotificationManager mUnityNotificationManager;
4343
private static HashMap<Integer, Notification> mScheduledNotifications = new HashMap();
44+
private static HashSet<Integer> mVisibleNotifications = new HashSet<>();
4445
private static int mSentSinceLastHousekeeping = 0;
4546
private static boolean mPerformingHousekeeping = false;
4647

@@ -61,6 +62,7 @@ public class UnityNotificationManager extends BroadcastReceiver {
6162
protected static final String KEY_SMALL_ICON = "smallIcon";
6263
protected static final String KEY_CHANNEL_ID = "channelID";
6364
protected static final String KEY_SHOW_IN_FOREGROUND = "com.unity.showInForeground";
65+
protected static final String KEY_NOTIFICATION_DISMISSED = "com.unity.NotificationDismissed";
6466

6567
protected static final String NOTIFICATION_CHANNELS_SHARED_PREFS = "UNITY_NOTIFICATIONS";
6668
protected static final String NOTIFICATION_CHANNELS_SHARED_PREFS_KEY = "ChannelIDs";
@@ -301,7 +303,7 @@ static Notification scheduleAlarmWithNotification(Context context, Class activit
301303
// fireTime not taken from notification, because we may have adjusted it
302304

303305
Notification notification = buildNotificationForSending(context, activityClass, notificationBuilder);
304-
mScheduledNotifications.put(Integer.valueOf(id), notification);
306+
putScheduledNotification(Integer.valueOf(id), notification);
305307
intent.putExtra(KEY_NOTIFICATION_ID, id);
306308

307309
PendingIntent broadcast = getBroadcastPendingIntent(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
@@ -330,6 +332,16 @@ protected static Notification buildNotificationForSending(Context context, Class
330332
openAppIntent.putExtra(KEY_NOTIFICATION_ID, id);
331333
PendingIntent pendingIntent = getActivityPendingIntent(context, id, openAppIntent, 0);
332334
builder.setContentIntent(pendingIntent);
335+
336+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
337+
// Can't check StatusBar notifications pre-M, so ask to be notified when dismissed
338+
Intent deleteIntent = new Intent(context, UnityNotificationManager.class);
339+
deleteIntent.setAction(KEY_NOTIFICATION_DISMISSED); // need action to distinguish intent from content one
340+
deleteIntent.putExtra(KEY_NOTIFICATION_DISMISSED, id);
341+
PendingIntent deletePending = getBroadcastPendingIntent(context, id, deleteIntent, 0);
342+
builder.setDeleteIntent(deletePending);
343+
}
344+
333345
finalizeNotificationForDisplay(context, builder);
334346
return builder.build();
335347
}
@@ -408,8 +420,10 @@ private static void performNotificationHousekeeping(Context context, Set<String>
408420
synchronized (UnityNotificationManager.class) {
409421
// list might have changed while we searched
410422
Set<String> currentIds = new HashSet<>(getScheduledNotificationIDs(context));
411-
for (String id : invalid)
423+
for (String id : invalid) {
412424
currentIds.remove(id);
425+
removeScheduledNotification(Integer.valueOf(id));
426+
}
413427
saveScheduledNotificationIDs(context, currentIds);
414428
mSentSinceLastHousekeeping = 0;
415429
}
@@ -431,11 +445,19 @@ private static Set<String> findInvalidNotificationIds(Context context, Set<Strin
431445
}
432446
}
433447

434-
StatusBarNotification[] active = getNotificationManager(context).getActiveNotifications();
435-
for (StatusBarNotification notification : active) {
436-
// any notifications in status bar are still valid
437-
String id = String.valueOf(notification.getId());
438-
invalid.remove(id);
448+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
449+
StatusBarNotification[] active = getNotificationManager(context).getActiveNotifications();
450+
for (StatusBarNotification notification : active) {
451+
// any notifications in status bar are still valid
452+
String id = String.valueOf(notification.getId());
453+
invalid.remove(id);
454+
}
455+
}
456+
else synchronized (UnityNotificationManager.class) {
457+
for (Integer visibleId : mVisibleNotifications) {
458+
String id = String.valueOf(visibleId);
459+
invalid.remove(id);
460+
}
439461
}
440462

441463
// if app is launched with notification, user still has access to it
@@ -548,18 +570,21 @@ protected static void scheduleNotificationIntentAlarm(Context context, long repe
548570
// Check the notification status by id.
549571
public int checkNotificationStatus(int id) {
550572
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
551-
// TODO: what if the notification has been dismissed by the user?
552573
for (StatusBarNotification n : getNotificationManager().getActiveNotifications()) {
553574
if (id == n.getId())
554575
return 2;
555576
}
577+
} else synchronized (UnityNotificationManager.class) {
578+
for (Integer notificationId : mVisibleNotifications) {
579+
if (notificationId.intValue() == id)
580+
return 2;
581+
}
582+
}
556583

557-
if (checkIfPendingNotificationIsRegistered(id))
558-
return 1;
584+
if (checkIfPendingNotificationIsRegistered(id))
585+
return 1;
559586

560-
return 0;
561-
}
562-
return -1;
587+
return 0;
563588
}
564589

565590
// Check if the pending notification with the given id has been registered.
@@ -583,6 +608,7 @@ public void cancelAllPendingNotificationIntents() {
583608
cancelPendingNotificationIntent(context, Integer.valueOf(id));
584609
deleteExpiredNotificationIntent(context, id);
585610
}
611+
triggerHousekeeping(context, null);
586612
}).start();
587613
}
588614
}
@@ -640,6 +666,15 @@ public void cancelAllNotifications() {
640666
@Override
641667
public void onReceive(Context context, Intent intent) {
642668
try {
669+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
670+
if (KEY_NOTIFICATION_DISMISSED.equals(intent.getAction())) {
671+
int removedId = intent.getIntExtra(KEY_NOTIFICATION_DISMISSED, -1);
672+
if (removedId > 0) synchronized (UnityNotificationManager.class) {
673+
mVisibleNotifications.remove(removedId);
674+
}
675+
return;
676+
}
677+
}
643678
Object notification = getNotificationOrBuilderForIntent(context, intent);
644679
if (notification != null) {
645680
Notification notif = null;
@@ -667,7 +702,7 @@ public void onReceive(Context context, Intent intent) {
667702
id = builder.getExtras().getInt(KEY_NOTIFICATION_ID, -1);
668703
notif = buildNotificationForSending(context, openActivity, builder);
669704
// if notification is not sendable, it wasn't cached
670-
mScheduledNotifications.put(Integer.valueOf(id), notif);
705+
putScheduledNotification(Integer.valueOf(id), notif);
671706
}
672707

673708
if (notif != null) {
@@ -684,6 +719,8 @@ protected static void notify(Context context, int id, Notification notification)
684719
boolean showInForeground = notification.extras.getBoolean(KEY_SHOW_IN_FOREGROUND, true);
685720
if (!isInForeground() || showInForeground) {
686721
getNotificationManager(context).notify(id, notification);
722+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) synchronized (UnityNotificationManager.class) {
723+
mVisibleNotifications.add(Integer.valueOf(id));
687724
}
688725

689726
try {
@@ -832,8 +869,7 @@ public static Object getNotificationOrBuilderForIntent(Context context, Intent i
832869
if (intent.hasExtra(KEY_NOTIFICATION_ID)) {
833870
int id = intent.getExtras().getInt(KEY_NOTIFICATION_ID);
834871
Integer notificationId = Integer.valueOf(id);
835-
if (mScheduledNotifications.containsKey(notificationId)) {
836-
notification = mScheduledNotifications.get(notificationId);
872+
if ((notification = getScheduledNotification(notificationId)) != null) {
837873
sendable = true;
838874
} else {
839875
// in case we don't have cached notification, deserialize from storage
@@ -881,4 +917,16 @@ public void showNotificationSettings(String channelId) {
881917
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
882918
mActivity.startActivity(settingsIntent);
883919
}
920+
921+
private static synchronized void putScheduledNotification(Integer id, Notification notification) {
922+
mScheduledNotifications.put(id, notification);
923+
}
924+
925+
private static synchronized Notification getScheduledNotification(Integer id) {
926+
return mScheduledNotifications.get(id);
927+
}
928+
929+
private static synchronized Notification removeScheduledNotification(Integer id) {
930+
return mScheduledNotifications.remove(id);
931+
}
884932
}

com.unity.mobile.notifications/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"name": "com.unity.mobile.notifications",
33
"displayName": "Mobile Notifications",
4-
"version": "2.0.1",
4+
"version": "2.0.2",
55
"unity": "2019.4",
6-
"description": "Mobile Notifications package adds support for scheduling local repeatable or one-time notifications on iOS and Android.\n\nRequires iOS 10 and Android 4.4 or above.",
6+
"description": "Mobile Notifications package adds support for scheduling local repeatable or one-time notifications on iOS and Android.\n\nRequires iOS 10 and Android 5.1 or above.",
77
"keywords": [
88
"Android",
99
"iOS",

0 commit comments

Comments
 (0)