fix:1、更换sdk

This commit is contained in:
2026-07-14 09:49:24 +08:00
parent 4187297e82
commit 8435b6e676
667 changed files with 36728 additions and 23022 deletions
@@ -0,0 +1,512 @@
using System;
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;
using Unity.Notifications.Android;
class AndroidNotificationSendingTests
{
const string kDefaultTestChannel = "default_test_channel";
class NotificationReceivedHandler
{
public int receivedNotificationCount = 0;
public AndroidNotificationIntentData lastNotification;
public void OnReceiveNotification(AndroidNotificationIntentData data)
{
++receivedNotificationCount;
lastNotification = data;
}
}
NotificationReceivedHandler currentHandler;
[OneTimeSetUp]
public void BeforeAllTests()
{
#if !UNITY_EDITOR
var c = new AndroidNotificationChannel();
c.Id = kDefaultTestChannel;
c.Name = "Default Channel 5";
c.Description = "test_channel 5";
c.Importance = Importance.High;
AndroidNotificationCenter.RegisterNotificationChannel(c);
#endif
}
[OneTimeTearDown]
public void AfterAllTests()
{
AndroidNotificationCenter.CancelAllNotifications();
}
[SetUp]
public void BeforeEachTest()
{
#if !UNITY_EDITOR
AndroidNotificationCenter.CancelAllNotifications();
currentHandler = new NotificationReceivedHandler();
AndroidNotificationCenter.OnNotificationReceived += currentHandler.OnReceiveNotification;
#endif
}
[TearDown]
public void AfterEachTest()
{
#if !UNITY_EDITOR
AndroidNotificationCenter.OnNotificationReceived -= currentHandler.OnReceiveNotification;
currentHandler = null;
#endif
}
IEnumerator WaitForNotification(float timeout)
{
float passed = 0.0f;
int notificationCount = currentHandler.receivedNotificationCount;
while (notificationCount == currentHandler.receivedNotificationCount && passed < timeout)
{
yield return null;
passed += Time.deltaTime;
}
if (passed > timeout)
Debug.LogWarning("Timeout waiting for notification");
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator SendNotificationExplicitID_NotificationIsReceived()
{
int originalId = 456;
var n = new AndroidNotification();
n.Title = "SendNotificationExplicitID_NotificationIsReceived : " + originalId.ToString();
n.Text = "SendNotificationExplicitID_NotificationIsReceived Text";
n.FireTime = System.DateTime.Now;
n.Group = "test.dummy.group";
Debug.LogWarning("SendNotificationExplicitID_NotificationIsReceived sends notification with ID " + originalId);
AndroidNotificationCenter.SendNotificationWithExplicitID(n, kDefaultTestChannel, originalId);
yield return WaitForNotification(8.0f);
Debug.LogWarning("SendNotificationExplicitID_NotificationIsReceived completed. Received notifications: " + currentHandler.receivedNotificationCount);
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
Assert.AreEqual(originalId, currentHandler.lastNotification.Id);
Assert.AreEqual(n.Group, currentHandler.lastNotification.Notification.Group);
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator SendNotification_NotificationIsReceived()
{
var n = new AndroidNotification();
n.Title = "SendNotification_NotificationIsReceived";
n.Text = "SendNotification_NotificationIsReceived Text";
n.FireTime = System.DateTime.Now;
Debug.LogWarning("SendNotification_NotificationIsReceived sends notification");
int originalId = AndroidNotificationCenter.SendNotification(n, kDefaultTestChannel);
yield return WaitForNotification(8.0f);
Debug.LogWarning("SendNotification_NotificationIsReceived completed. Received notifications: " + currentHandler.receivedNotificationCount);
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
Assert.AreEqual(originalId, currentHandler.lastNotification.Id);
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator SendNotificationAndCancelNotification_NotificationIsNotReceived()
{
var n = new AndroidNotification();
n.Title = "SendNotificationAndCancelNotification_NotificationIsNotReceived";
n.Text = "SendNotificationAndCancelNotification_NotificationIsNotReceived Text";
n.FireTime = System.DateTime.Now.AddSeconds(2.0f);
Debug.LogWarning("SendNotificationAndCancelNotification_NotificationIsNotReceived sends notification");
int originalId = AndroidNotificationCenter.SendNotification(n, kDefaultTestChannel);
yield return null;
AndroidNotificationCenter.CancelScheduledNotification(originalId);
yield return WaitForNotification(8.0f);
Debug.LogWarning("SendNotificationAndCancelNotification_NotificationIsNotReceived completed.");
Assert.AreEqual(0, currentHandler.receivedNotificationCount);
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator ScheduleRepeatableNotification_NotificationsAreReceived()
{
var n = new AndroidNotification();
n.Title = "Repeating Notification Title";
n.Text = "Repeating Notification Text";
n.FireTime = System.DateTime.Now.AddSeconds(2);
n.RepeatInterval = new System.TimeSpan(0, 0, 5); // interval needs to be quite big for test to be reliable
Debug.LogWarning("ScheduleRepeatableNotification_NotificationsAreReceived sends notification");
int originalId = AndroidNotificationCenter.SendNotification(n, kDefaultTestChannel);
// we use inexact scheduling, so repeated notification may take a while to appear
// inexact also can group, so for test purposes we only check that it repeats at least once
yield return WaitForNotification(120.0f);
yield return WaitForNotification(120.0f);
AndroidNotificationCenter.CancelScheduledNotification(originalId);
Debug.LogWarning("ScheduleRepeatableNotification_NotificationsAreReceived completed");
Assert.GreaterOrEqual(currentHandler.receivedNotificationCount, 2);
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator NotificationIsScheduled_NotificationStatusIsCorrectlyReported()
{
var n = new AndroidNotification();
n.Title = "NotificationStatusIsCorrectlyReported";
n.Text = "NotificationStatusIsCorrectlyReported";
n.FireTime = System.DateTime.Now.AddSeconds(2f);
Debug.LogWarning("NotificationIsScheduled_NotificationStatusIsCorrectlyReported sends notification");
int originalId = AndroidNotificationCenter.SendNotification(n, kDefaultTestChannel);
yield return null;
var status = AndroidNotificationCenter.CheckScheduledNotificationStatus(originalId);
Assert.AreEqual(NotificationStatus.Scheduled, status);
yield return WaitForNotification(120.0f);
yield return new WaitForSeconds(1.0f); // give some time for Status Bar to update
status = AndroidNotificationCenter.CheckScheduledNotificationStatus(originalId);
Assert.AreEqual(NotificationStatus.Delivered, status);
AndroidNotificationCenter.CancelNotification(originalId);
yield return new WaitForSeconds(1.5f);
status = AndroidNotificationCenter.CheckScheduledNotificationStatus(originalId);
Assert.AreEqual(NotificationStatus.Unknown, status);
Debug.LogWarning("NotificationIsScheduled_NotificationStatusIsCorrectlyReported completed");
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator ArrivedAndUserDismissedNotification_DoesNotReportStatusAsScheduled()
{
var n = new AndroidNotification("ArrivedNotificationAndDissmissed", "ArrivedNotificationAndDissmissed", System.DateTime.Now);
yield return DismissedNotification_DoesNotReportStatusAsScheduled(n);
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator ArrivedAndUserDismissedScheduledNotification_DoesNotReportStatusAsScheduled()
{
var n = new AndroidNotification("ArrivedNotificationAndDissmissedScheduled", "ArrivedNotificationAndDissmissedScheduled", System.DateTime.Now.AddSeconds(2));
yield return DismissedNotification_DoesNotReportStatusAsScheduled(n);
}
public IEnumerator DismissedNotification_DoesNotReportStatusAsScheduled(AndroidNotification n)
{
int originalId = AndroidNotificationCenter.SendNotification(n, kDefaultTestChannel);
yield return WaitForNotification(8.0f);
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
AndroidNotificationCenter.CancelDisplayedNotification(originalId);
yield return new WaitForSeconds(2.0f); // cancel is async
var status = AndroidNotificationCenter.CheckScheduledNotificationStatus(originalId);
Assert.AreEqual(NotificationStatus.Unknown, status);
// now simulate app kill and restart, where notifications are loaded from persistent storage
using var managerClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationManager");
using var manager = managerClass.GetStatic<AndroidJavaObject>("mUnityNotificationManager");
using var backgroundThread = manager.Get<AndroidJavaObject>("mBackgroundThread");
using var scheduledNotifications = manager.Get<AndroidJavaObject>("mScheduledNotifications");
scheduledNotifications.Call("clear");
backgroundThread.Call("loadNotifications");
status = AndroidNotificationCenter.CheckScheduledNotificationStatus(originalId);
Assert.AreEqual(NotificationStatus.Unknown, status);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void CreateNotificationChannelWithInitializedSettings_ChannelSettingsAreSaved()
{
var chOrig = new AndroidNotificationChannel();
chOrig.Id = "test_channel_settings_are_saved_0";
chOrig.Name = "spam Channel";
chOrig.Description = "Generic spam";
chOrig.Importance = Importance.High;
chOrig.CanBypassDnd = true;
chOrig.CanShowBadge = true;
chOrig.EnableLights = true;
chOrig.EnableVibration = false;
// this opne should be read-only, it reports the system setting, but can't be set
// chOrig.LockScreenVisibility = LockScreenVisibility.Private;
AndroidNotificationCenter.RegisterNotificationChannel(chOrig);
var ch = AndroidNotificationCenter.GetNotificationChannel(chOrig.Id);
Assert.AreEqual(chOrig.Id, ch.Id);
Assert.AreEqual(chOrig.Name, ch.Name);
Assert.AreEqual(chOrig.Description, ch.Description);
Assert.AreEqual(chOrig.Importance, ch.Importance);
Assert.AreEqual(chOrig.EnableLights, ch.EnableLights);
Assert.AreEqual(chOrig.EnableVibration, ch.EnableVibration);
//Assert.AreEqual(chOrig.LockScreenVisibility, ch.LockScreenVisibility);
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator SendNotification_NotificationIsReceived_CallMainThread()
{
var gameObjects = new GameObject[1];
AndroidNotificationCenter.NotificationReceivedCallback receivedNotificationHandler =
delegate (AndroidNotificationIntentData data)
{
gameObjects[0] = new GameObject();
gameObjects[0].name = "Hello_World";
Assert.AreEqual("Hello_World", gameObjects[0].name);
};
var n = new AndroidNotification();
n.Title = "SendNotification_NotificationIsReceived";
n.Text = "SendNotification_NotificationIsReceived Text";
n.FireTime = System.DateTime.Now;
Debug.LogWarning("SendNotification_NotificationIsReceived_CallMainThread sends notification");
int originalId = AndroidNotificationCenter.SendNotification(n, kDefaultTestChannel);
AndroidNotificationCenter.OnNotificationReceived += receivedNotificationHandler;
yield return WaitForNotification(8.0f);
Debug.LogWarning("SendNotification_NotificationIsReceived_CallMainThread completed");
AndroidNotificationCenter.OnNotificationReceived -= receivedNotificationHandler;
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
Assert.AreEqual(originalId, currentHandler.lastNotification.Id);
Assert.IsNotNull(gameObjects[0]);
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator SendNotification_CanAccessNativeBuilder()
{
var n = new AndroidNotification();
n.Title = "SendNotification_CanAccessNativeBuilder";
n.Text = "SendNotification_CanAccessNativeBuilder Text";
n.FireTime = System.DateTime.Now;
Debug.LogWarning("SendNotification_CanAccessNativeBuilder sends notification");
using (var builder = AndroidNotificationCenter.CreateNotificationBuilder(n, kDefaultTestChannel))
{
using (var extras = builder.Call<AndroidJavaObject>("getExtras"))
{
extras.Call("putString", "notification.test.string", "TheTest");
}
AndroidNotificationCenter.SendNotification(builder);
}
yield return WaitForNotification(8.0f);
Debug.LogWarning("SendNotification_CanAccessNativeBuilder completed");
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
using (var extras = currentHandler.lastNotification.NativeNotification.Get<AndroidJavaObject>("extras"))
{
Assert.AreEqual("TheTest", extras.Call<string>("getString", "notification.test.string"));
}
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator SendNotification_CanReschedule()
{
var managerClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationManager");
var rebootClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationRestartReceiver");
AndroidJavaObject context;
using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
context = activity.Call<AndroidJavaObject>("getApplicationContext");
}
var n = new AndroidNotification();
n.Title = "SendNotification_CanReschedule";
n.Text = "SendNotification_CanReschedule Text";
n.FireTime = System.DateTime.Now.AddSeconds(5);
Debug.LogWarning("SendNotification_CanReschedule sends notification");
int id = AndroidNotificationCenter.SendNotification(n, kDefaultTestChannel);
yield return new WaitForSeconds(0.2f);
var manager = managerClass.GetStatic<AndroidJavaObject>("mUnityNotificationManager");
// clear cached notifications to not mess up future tests
manager.Get<AndroidJavaObject>("mScheduledNotifications").Call("clear");
// simulate reboot by directly cancelling scheduled alarms preserving saves
manager.Call("cancelPendingNotificationIntent", id);
// temporary null the manager, cause that's what we have in reality
managerClass.SetStatic<AndroidJavaObject>("mUnityNotificationManager", null);
yield return new WaitForSeconds(0.2f);
// simulate reboot by calling reschedule method, that is called after reboot
rebootClass.CallStatic("rescheduleSavedNotifications", context);
var newManager = managerClass.GetStatic<AndroidJavaObject>("mUnityNotificationManager");
// new manager was supposed to be created, assign callback from original one to get notifications
newManager.Set("mNotificationCallback", manager.Get<AndroidJavaObject>("mNotificationCallback"));
yield return WaitForNotification(120.0f);
Debug.LogWarning("SendNotification_CanReschedule completed");
// restore manager (to not ruin other tests)
managerClass.SetStatic("mUnityNotificationManager", manager);
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
}
bool RescheduleNotification(AndroidNotification notification)
{
AndroidJavaObject manager, currentTime;
using (var managerClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationManager"))
manager = managerClass.GetStatic<AndroidJavaObject>("mUnityNotificationManager");
var rebootClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationRestartReceiver");
using (var calendarClass = new AndroidJavaClass("java.util.Calendar"))
{
using (var calendar = calendarClass.CallStatic<AndroidJavaObject>("getInstance"))
currentTime = calendar.Call<AndroidJavaObject>("getTime");
}
using var builder = AndroidNotificationCenter.CreateNotificationBuilder(789, notification, kDefaultTestChannel);
var result = rebootClass.CallStatic<bool>("rescheduleNotification", manager, currentTime, builder);
manager.Dispose();
currentTime.Dispose();
return result;
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator RescheduleNotification_ExpiredMomentAgo_SendsNotification()
{
var n = new AndroidNotification();
n.Title = "JustExpired";
n.Text = "Should be sent";
n.FireTime = System.DateTime.Now.AddMinutes(-1);
var result = RescheduleNotification(n);
Assert.IsTrue(result);
yield return WaitForNotification(5.0f);
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
var received = currentHandler.lastNotification.Notification;
Assert.AreEqual("JustExpired", received.Title);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void RescheduleNotification_ExpiredNotification_DoesNotReschedule()
{
var n = new AndroidNotification();
n.Title = "LongExpired";
n.Text = "Should NOT be sent";
n.FireTime = System.DateTime.Now.AddHours(-1);
var result = RescheduleNotification(n);
Assert.IsFalse(result);
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator SendNotificationNotShownInForeground_IsDeliveredButNotShown()
{
var n = new AndroidNotification();
n.Title = "SendNotificationNotShownInForeground_ISDeliveredButNotShown";
n.Text = "SendNotificationNotShownInForeground_ISDeliveredButNotShown Text";
n.FireTime = System.DateTime.Now;
n.ShowInForeground = false;
Debug.LogWarning("SendNotificationNotShownInForeground_ISDeliveredButNotShown sends notification");
int originalId = AndroidNotificationCenter.SendNotification(n, kDefaultTestChannel);
yield return WaitForNotification(5.0f);
Debug.LogWarning("SendNotificationNotShownInForeground_ISDeliveredButNotShown sends completed");
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
yield return new WaitForSeconds(2.0f); // give some time, since on some devices we don't immediately get infor on delivered notifications
var status = AndroidNotificationCenter.CheckScheduledNotificationStatus(originalId);
Assert.AreEqual(NotificationStatus.Unknown, status); // status should be unknown, rather than Delivered
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator SendBigPictureNotification_Roundtrip()
{
var n = new AndroidNotification("SendBigPictureNotification_Roundtrip", "SendBigPictureNotification_Roundtrip text", DateTime.Now);
n.BigPicture = new BigPictureStyle()
{
LargeIcon = "icon_1",
Picture = "icon_0",
ContentTitle = "ContentTitle",
ContentDescription = "ContentDescription",
SummaryText = "summary",
ShowWhenCollapsed = true,
};
Debug.LogWarning("SendBigPictureNotification_Roundtrip send");
int id = AndroidNotificationCenter.SendNotification(n, kDefaultTestChannel);
yield return WaitForNotification(8.0f);
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
var received = currentHandler.lastNotification.Notification;
Assert.AreEqual("SendBigPictureNotification_Roundtrip", received.Title);
Assert.AreEqual("SendBigPictureNotification_Roundtrip text", received.Text);
Assert.AreEqual(NotificationStyle.BigPictureStyle, received.Style);
var bigPicture = received.BigPicture;
Assert.IsTrue(bigPicture.HasValue);
var bigPictureData = bigPicture.Value;
Assert.AreEqual("icon_1", bigPictureData.LargeIcon);
Assert.AreEqual("icon_0", bigPictureData.Picture);
Assert.AreEqual("ContentTitle", bigPictureData.ContentTitle);
Assert.AreEqual("ContentDescription", bigPictureData.ContentDescription);
Assert.AreEqual("summary", bigPictureData.SummaryText);
Assert.IsTrue(bigPictureData.ShowWhenCollapsed);
}
[UnityTest]
[UnityPlatform(RuntimePlatform.Android)]
public IEnumerator SendAndReplaceNotification()
{
var original = new AndroidNotification("NotificationToBeReplaced", "This should be replaced", DateTime.Now.AddSeconds(5));
int id = AndroidNotificationCenter.SendNotification(original, kDefaultTestChannel);
yield return new WaitForSeconds(1);
var replacement = new AndroidNotification("ReplacementNotification", "Replacement text", DateTime.Now.AddSeconds(3));
AndroidNotificationCenter.UpdateScheduledNotification(id, replacement, kDefaultTestChannel);
yield return WaitForNotification(8.0f);
Assert.AreEqual(1, currentHandler.receivedNotificationCount);
var received = currentHandler.lastNotification.Notification;
Assert.AreEqual(replacement.Title, received.Title);
Assert.AreEqual(replacement.Text, received.Text);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f5e41e41f251d43eab8e92409720999a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,779 @@
using System;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Notifications.Android;
#if UNITY_EDITOR
using UnityEditor;
#endif
class AndroidNotificationSimpleTests
: IPrebuildSetup, IPostBuildCleanup
{
const string kChannelId = "SerializeDeserializeNotificationChannel";
#if UNITY_EDITOR
PluginImporter GetTestUtils()
{
var assets = AssetDatabase.FindAssets("UnityNotificationTestUtils");
if (assets.Length != 1)
throw new Exception("UnityNotificationTestUtils.java not found");
return (PluginImporter)AssetImporter.GetAtPath(AssetDatabase.GUIDToAssetPath(assets[0]));
}
#endif
public void Setup()
{
#if UNITY_EDITOR
var testUtils = GetTestUtils();
testUtils.SetCompatibleWithPlatform(BuildTarget.Android, true);
testUtils.SaveAndReimport();
#endif
}
public void Cleanup()
{
#if UNITY_EDITOR
var testUtils = GetTestUtils();
testUtils.SetCompatibleWithPlatform(BuildTarget.Android, false);
testUtils.SaveAndReimport();
#endif
}
[OneTimeSetUp]
public void BeforeAllTests()
{
var c = CreateNotificationChannelWithAllParameters();
var group = new AndroidNotificationChannelGroup()
{
Id = c.Group,
Name = "the group",
};
AndroidNotificationCenter.RegisterNotificationChannelGroup(group);
AndroidNotificationCenter.RegisterNotificationChannel(c);
}
AndroidNotificationChannel CreateNotificationChannelWithAllParameters()
{
var c = new AndroidNotificationChannel();
c.Id = kChannelId;
c.Name = "SerializeDeserializeNotification channel";
c.Description = "SerializeDeserializeNotification channel";
c.Importance = Importance.High;
c.Group = "Default";
c.CanBypassDnd = true;
c.CanShowBadge = true;
c.EnableLights = true;
c.EnableVibration = true;
c.VibrationPattern = new long[] { 5, 10 };
c.LockScreenVisibility = LockScreenVisibility.Public;
return c;
}
[Test]
public void AllAndroidNotificationChannelParametersAreTested()
{
var channel = CreateNotificationChannelWithAllParameters();
AndroidNotificationChannel defVals = default;
foreach (var field in typeof(AndroidNotificationChannel).GetFields())
{
var v1 = field.GetValue(channel);
var v2 = field.GetValue(defVals);
if (object.Equals(v1, v2))
Assert.Fail("Unassigned field " + field.Name);
}
foreach (var prop in typeof(AndroidNotificationChannel).GetProperties())
{
var v1 = prop.GetValue(channel);
var v2 = prop.GetValue(defVals);
if (object.Equals(v1, v2))
Assert.Fail("Unassigned property " + prop.Name);
}
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void CreateNotificationChannel_NotificationChannelIsCreated()
{
var testChannelId = "default_test_channel_10";
AndroidNotificationCenter.DeleteNotificationChannel(testChannelId);
Assert.AreNotEqual("default_test_channel_10", AndroidNotificationCenter.GetNotificationChannel(testChannelId).Id);
var newChannel = new AndroidNotificationChannel();
newChannel.Id = testChannelId;
newChannel.Name = "Default Channel";
newChannel.Description = "Generic spam";
var currentChannelCount = AndroidNotificationCenter.GetNotificationChannels().Length;
AndroidNotificationCenter.RegisterNotificationChannel(newChannel);
currentChannelCount++;
Assert.AreEqual(currentChannelCount, AndroidNotificationCenter.GetNotificationChannels().Length);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void GetNotificationChannel_ReturnsTheChannel()
{
var channel = AndroidNotificationCenter.GetNotificationChannel(kChannelId);
Assert.IsNotNull(channel);
var expected = CreateNotificationChannelWithAllParameters();
foreach (var field in typeof(AndroidNotificationChannel).GetFields())
{
var v1 = field.GetValue(channel);
var v2 = field.GetValue(expected);
if (!object.Equals(v1, v2))
Assert.Fail($"Unexpected value for field {field.Name}; expected {v2}, was {v1}");
}
foreach (var prop in typeof(AndroidNotificationChannel).GetProperties())
{
if (prop.Name == "CanBypassDnd") // this one returns the actual value, not the requested one (may differ)
continue;
if (prop.Name == "VibrationPattern")
{
Assert.IsNotNull(channel.VibrationPattern);
Assert.AreEqual(expected.VibrationPattern.Length, channel.VibrationPattern.Length);
for (int i = 0; i < expected.VibrationPattern.Length; ++i)
Assert.AreEqual(expected.VibrationPattern[i], channel.VibrationPattern[i]);
continue;
}
var v1 = prop.GetValue(channel);
var v2 = prop.GetValue(expected);
if (!object.Equals(v1, v2))
Assert.Fail($"Unexpected value for property {prop.Name}; expected {v2}, was {v1}");
}
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void GetNotificationChannel_NonExistentChannel_ReturnsNull()
{
var channel = AndroidNotificationCenter.GetNotificationChannel("DoesNotExist");
Assert.IsNotNull(channel);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void GetNotificationChannels_NoChannels_ReturnsEmptyArray()
{
var channels = AndroidNotificationCenter.GetNotificationChannels();
foreach (var channel in channels)
AndroidNotificationCenter.DeleteNotificationChannel(channel.Id);
try
{
var chans = AndroidNotificationCenter.GetNotificationChannels();
Assert.IsNotNull(chans);
Assert.AreEqual(0, chans.Length);
}
finally
{
// recreate test channels to not break other tests
foreach (var channel in channels)
AndroidNotificationCenter.RegisterNotificationChannel(channel);
}
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void DeleteNotificationChannelGroup_GroupIsDeleted()
{
var group = new AndroidNotificationChannelGroup()
{
Id = "TestDelete",
Name = "Group for deletion",
};
AndroidNotificationCenter.RegisterNotificationChannelGroup(group);
var channel = new AndroidNotificationChannel()
{
Id = "Temp",
Name = "Group testing",
Description = "Testing group",
Importance = Importance.Low,
Group = "TestDelete",
};
AndroidNotificationCenter.RegisterNotificationChannel(channel);
AndroidNotificationCenter.DeleteNotificationChannelGroup("TestDelete");
var ch = AndroidNotificationCenter.GetNotificationChannel("Temp");
Assert.IsNull(ch.Id);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void DeleteNotificationChannel_NotificationChannelIsDeleted()
{
var ch = new AndroidNotificationChannel();
ch.Id = "default_test_channel_0";
ch.Name = "Default Channel";
ch.Description = "Generic spam";
ch.Importance = Importance.Default;
AndroidNotificationCenter.RegisterNotificationChannel(ch);
int numChannels = AndroidNotificationCenter.GetNotificationChannels().Length;
AndroidNotificationCenter.DeleteNotificationChannel(ch.Id);
Assert.AreEqual(numChannels - 1, AndroidNotificationCenter.GetNotificationChannels().Length);
}
[Test]
public void SetNotificationFireTime_TimeIsConvertedToUnixTimeAndBack()
{
var n = new AndroidNotification();
var fireTime = new DateTime(2018, 5, 24, 12, 41, 30, 122);
n.FireTime = new DateTime(2018, 5, 24, 12, 41, 30, 122);
Assert.AreEqual(fireTime, n.FireTime);
}
[Test]
public void SetNotificationRepeatInterval_TimeIsConvertedToUnixTimeAndBack()
{
var n = new AndroidNotification();
var repeatInterval = TimeSpan.FromSeconds(666);
n.RepeatInterval = repeatInterval;
Assert.AreEqual(repeatInterval, n.RepeatInterval);
}
AndroidNotification CreateNotificationWithAllParameters()
{
var notification = new AndroidNotification();
notification.Title = "title";
notification.Text = "text";
notification.SmallIcon = "small_icon";
notification.FireTime = DateTime.Now;
notification.RepeatInterval = new TimeSpan(0, 0, 5);
notification.LargeIcon = "large_icon";
notification.Style = NotificationStyle.BigTextStyle;
notification.Color = new Color(0.2f, 0.4f, 0.6f, 1.0f);
notification.Number = 15;
notification.ShouldAutoCancel = true;
notification.UsesStopwatch = true;
notification.Group = "group";
notification.GroupSummary = true;
notification.GroupAlertBehaviour = GroupAlertBehaviours.GroupAlertChildren;
notification.SortKey = "sorting";
notification.IntentData = "string for intent";
notification.ShowTimestamp = true;
notification.ShowInForeground = false; // this one defaults to true
notification.CustomTimestamp = new DateTime(2018, 5, 24, 12, 41, 30, 122);
return notification;
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void BasicSerializeDeserializeNotification_AllParameters()
{
const int notificationId = 123;
var original = CreateNotificationWithAllParameters();
var deserializedData = SerializeDeserializeNotification(original, notificationId);
Assert.AreEqual(notificationId, deserializedData.Id);
Assert.AreEqual(kChannelId, deserializedData.Channel);
CheckNotificationsMatch(original, deserializedData.Notification);
}
AndroidNotificationIntentData SerializeDeserializeNotification(AndroidNotification original, int notificationId)
{
using (var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId))
{
return SerializeDeserializeNotification(builder);
}
}
AndroidNotificationIntentData SerializeDeserializeNotification(AndroidJavaObject builder)
{
return SerializeDeserializeNotificationWithFunc(builder, (u, s, j) => SerializeNotificationCustom(u, s, j));
}
AndroidNotificationIntentData SerializeDeserializeNotificationWithFunc(AndroidJavaObject builder, Func<AndroidJavaClass, AndroidJavaObject, AndroidJavaObject, bool> serialize)
{
var javaNotif = builder.Call<AndroidJavaObject>("build");
var utilsClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationUtilities");
AndroidJavaObject serializedBytes; // use java object, since we don't need the bytes, so don't waste time on marshalling
using (var byteStream = new AndroidJavaObject("java.io.ByteArrayOutputStream"))
{
var dataStream = new AndroidJavaObject("java.io.DataOutputStream", byteStream);
var didSerialize = serialize(utilsClass, dataStream, javaNotif);
Assert.IsTrue(didSerialize);
dataStream.Call("close");
serializedBytes = byteStream.Call<AndroidJavaObject>("toByteArray");
}
Assert.IsNotNull(serializedBytes);
using (var byteStream = new AndroidJavaObject("java.io.ByteArrayInputStream", serializedBytes))
{
var dataStream = new AndroidJavaObject("java.io.DataInputStream", byteStream);
var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
// don't dispose notification, it is kept in AndroidNotificationIntentData
using (var deserializedNotificationBuilder = utilsClass.CallStatic<AndroidJavaObject>("deserializeNotificationCustom", activity, dataStream))
{
Assert.IsNotNull(deserializedNotificationBuilder);
var deserializedNotification = deserializedNotificationBuilder.Call<AndroidJavaObject>("build");
Assert.IsNotNull(deserializedNotification);
return AndroidNotificationCenter.GetNotificationData(deserializedNotification);
}
}
}
static bool SerializeNotificationCustom(AndroidJavaClass utilsClass, AndroidJavaObject byteStream, AndroidJavaObject javaNotif)
{
using (var dataStream = new AndroidJavaObject("java.io.DataOutputStream", byteStream))
{
var didSerialize = utilsClass.CallStatic<bool>("serializeNotificationCustom", javaNotif, dataStream);
dataStream.Call("close");
return didSerialize;
}
}
static bool SerializeNotificationCustom_v0(AndroidJavaClass utilsClass, AndroidJavaObject byteStream, AndroidJavaObject javaNotif)
{
return SerializeNotificationCustom_old("serializeNotificationCustom_v0", byteStream, javaNotif);
}
static bool SerializeNotificationCustom_v1(AndroidJavaClass utilsClass, AndroidJavaObject byteStream, AndroidJavaObject javaNotif)
{
return SerializeNotificationCustom_old("serializeNotificationCustom_v1", byteStream, javaNotif);
}
static bool SerializeNotificationCustom_v2(AndroidJavaClass utilsClass, AndroidJavaObject byteStream, AndroidJavaObject javaNotif)
{
return SerializeNotificationCustom_old("serializeNotificationCustom_v2", byteStream, javaNotif);
}
static bool SerializeNotificationCustom_old(string method, AndroidJavaObject byteStream, AndroidJavaObject javaNotif)
{
using (var dataStream = new AndroidJavaObject("java.io.DataOutputStream", byteStream))
{
bool didSerialize;
using (var testUtils = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationTestUtils"))
{
didSerialize = testUtils.CallStatic<bool>(method, javaNotif, dataStream);
}
dataStream.Call("close");
return didSerialize;
}
}
void CheckNotificationsMatch(AndroidNotification original, AndroidNotification other)
{
Assert.AreEqual(original.Title, other.Title);
Assert.AreEqual(original.Text, other.Text);
Assert.AreEqual(original.SmallIcon, other.SmallIcon);
Assert.AreEqual(original.FireTime.ToString(), other.FireTime.ToString());
Assert.AreEqual(original.RepeatInterval, other.RepeatInterval);
Assert.AreEqual(original.LargeIcon, other.LargeIcon);
Assert.AreEqual(original.Style, other.Style);
Assert.AreEqual(original.Color, other.Color);
Assert.AreEqual(original.Number, other.Number);
Assert.AreEqual(original.ShouldAutoCancel, other.ShouldAutoCancel);
Assert.AreEqual(original.UsesStopwatch, other.UsesStopwatch);
Assert.AreEqual(original.Group, other.Group);
Assert.AreEqual(original.GroupSummary, other.GroupSummary);
Assert.AreEqual(original.GroupAlertBehaviour, other.GroupAlertBehaviour);
Assert.AreEqual(original.SortKey, other.SortKey);
Assert.AreEqual(original.IntentData, other.IntentData);
Assert.AreEqual(original.ShowTimestamp, other.ShowTimestamp);
Assert.AreEqual(original.ShowInForeground, other.ShowInForeground);
Assert.AreEqual(original.CustomTimestamp, other.CustomTimestamp);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void BasicSerializeDeserializeNotification_MinimumParameters()
{
const int notificationId = 124;
var original = new AndroidNotification();
original.FireTime = DateTime.Now;
var deserializedData = SerializeDeserializeNotification(original, notificationId);
Assert.AreEqual(notificationId, deserializedData.Id);
Assert.AreEqual(kChannelId, deserializedData.Channel);
CheckNotificationsMatch(original, deserializedData.Notification);
}
AndroidJavaObject CreateBitmap()
{
var configClass = new AndroidJavaClass("android.graphics.Bitmap$Config");
var ARGB_8888 = configClass.GetStatic<AndroidJavaObject>("ARGB_8888");
var bitmapClass = new AndroidJavaClass("android.graphics.Bitmap");
return bitmapClass.CallStatic<AndroidJavaObject>("createBitmap", 1000, 1000, ARGB_8888);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void BasicSerializeDeserializeNotification_WorksWithBinderExtras()
{
const int notificationId = 126;
var original = new AndroidNotification();
original.FireTime = DateTime.Now.AddSeconds(2);
var bitmap = CreateBitmap();
Assert.IsNotNull(bitmap);
var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId);
var extras = builder.Call<AndroidJavaObject>("getExtras");
extras.Call("putParcelable", "binder_item", bitmap);
var deserializedData = SerializeDeserializeNotification(builder);
var deserializedExtras = deserializedData.NativeNotification.Get<AndroidJavaObject>("extras");
var bitmapAfterSerialization = deserializedExtras.Call<AndroidJavaObject>("getParcelable", "binder_item");
// both these are in extras, so we should have lost bitmap, but preserved fire time
// bitmap is binder object and can't be parcelled, while our fallback custom serialization only preserves our stuff
Assert.IsNull(bitmapAfterSerialization);
Assert.AreEqual(original.FireTime.ToString(), deserializedData.Notification.FireTime.ToString());
}
AndroidNotificationIntentData SerializeDeserializeNotification(AndroidNotification original, int notificationId, Action<AndroidJavaObject> inBetween = null)
{
using (var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId))
{
return SerializeDeserializeNotification(builder, inBetween);
}
}
AndroidNotificationIntentData SerializeDeserializeNotification(AndroidJavaObject builder, Action<AndroidJavaObject> inBetween = null)
{
var managerClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationManager");
var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
var context = activity.Call<AndroidJavaObject>("getApplicationContext");
var javaNotif = builder.Call<AndroidJavaObject>("build");
var utilsClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationUtilities");
var prefs = context.Call<AndroidJavaObject>("getSharedPreferences", "android.notification.test.key", 0 /* MODE_PRIVATE */);
utilsClass.CallStatic("serializeNotification", prefs, javaNotif);
if (inBetween != null)
inBetween(prefs);
var deserializedNotificationBuilder = utilsClass.CallStatic<AndroidJavaObject>("deserializeNotification", context, prefs);
// don't dispose notification, it is kept in AndroidNotificationIntentData
Assert.IsNotNull(deserializedNotificationBuilder);
var deserializedNotification = deserializedNotificationBuilder.Call<AndroidJavaObject>("build");
Assert.IsNotNull(deserializedNotification);
return AndroidNotificationCenter.GetNotificationData(deserializedNotification);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void NotificationSerialization_SimpleNotification()
{
const int notificationId = 1234;
var original = new AndroidNotification();
original.FireTime = DateTime.Now.AddSeconds(2);
var deserializedData = SerializeDeserializeNotification(original, notificationId);
Assert.AreEqual(original.FireTime.ToString(), deserializedData.Notification.FireTime.ToString());
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void NotificationSerialization_NotificationWithBinderObject()
{
const int notificationId = 1234;
var original = new AndroidNotification();
original.FireTime = DateTime.Now.AddSeconds(2);
original.ShowInForeground = false; // non default value
var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId);
var extras = builder.Call<AndroidJavaObject>("getExtras");
var bitmap = CreateBitmap();
Assert.IsNotNull(bitmap);
extras.Call("putParcelable", "binder_item", bitmap);
var deserializedData = SerializeDeserializeNotification(builder);
Assert.AreEqual(original.FireTime.ToString(), deserializedData.Notification.FireTime.ToString());
Assert.IsFalse(deserializedData.Notification.ShowInForeground);
var deserializedExtras = deserializedData.NativeNotification.Get<AndroidJavaObject>("extras");
var bitmapAfterSerialization = deserializedExtras.Call<AndroidJavaObject>("getParcelable", "binder_item");
// bitmap is binder object and can't be parcelled, while our fallback custom serialization only preserves our stuff
Assert.IsNull(bitmapAfterSerialization);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void NotificationSerialization_BigPictureStyle()
{
const int notificationId = 816;
var original = new AndroidNotification("title", "content", DateTime.Now);
original.BigPicture = new BigPictureStyle()
{
LargeIcon = "icon_1",
Picture = "icon_0",
ContentTitle = "content_title",
ContentDescription = "content_description",
SummaryText = "summary",
ShowWhenCollapsed = true,
};
var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId);
var deserializedData = SerializeDeserializeNotification(builder);
Assert.AreEqual(NotificationStyle.BigPictureStyle, deserializedData.Notification.Style);
Assert.IsTrue(deserializedData.Notification.BigPicture.HasValue);
var bigPicture = deserializedData.Notification.BigPicture.Value;
Assert.AreEqual(original.BigPicture.Value.LargeIcon, bigPicture.LargeIcon);
Assert.AreEqual(original.BigPicture.Value.Picture, bigPicture.Picture);
Assert.AreEqual(original.BigPicture.Value.ContentTitle, bigPicture.ContentTitle);
Assert.AreEqual(original.BigPicture.Value.ContentDescription, bigPicture.ContentDescription);
Assert.AreEqual(original.BigPicture.Value.SummaryText, bigPicture.SummaryText);
Assert.AreEqual(original.BigPicture.Value.ShowWhenCollapsed, bigPicture.ShowWhenCollapsed);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void OldTypeSerializedNotificationCanBedeserialized()
{
const int notificationId = 12345;
var managerClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationManager");
var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
var context = activity.Call<AndroidJavaObject>("getApplicationContext");
var notificationIntent = new AndroidJavaObject("android.content.Intent", context, managerClass);
var fireTime = DateTime.Now.AddSeconds(3);
var repeatInterval = new TimeSpan(0, 0, 5);
Color? color = new Color(0.2f, 0.4f, 0.6f, 1.0f);
notificationIntent.Call<AndroidJavaObject>("putExtra", "id", notificationId);
notificationIntent.Call<AndroidJavaObject>("putExtra", "channelID", kChannelId);
notificationIntent.Call<AndroidJavaObject>("putExtra", "textTitle", "notification.Title");
notificationIntent.Call<AndroidJavaObject>("putExtra", "textContent", "notification.Text");
notificationIntent.Call<AndroidJavaObject>("putExtra", "smallIconStr", "notification.SmallIcon");
notificationIntent.Call<AndroidJavaObject>("putExtra", "autoCancel", true);
notificationIntent.Call<AndroidJavaObject>("putExtra", "usesChronometer", true);
notificationIntent.Call<AndroidJavaObject>("putExtra", "fireTime", fireTime.ToLong());
notificationIntent.Call<AndroidJavaObject>("putExtra", "repeatInterval", (long)repeatInterval.TotalMilliseconds);
notificationIntent.Call<AndroidJavaObject>("putExtra", "largeIconStr", "notification.LargeIcon");
notificationIntent.Call<AndroidJavaObject>("putExtra", "style", (int)NotificationStyle.BigTextStyle);
notificationIntent.Call<AndroidJavaObject>("putExtra", "color", color.ToInt());
notificationIntent.Call<AndroidJavaObject>("putExtra", "number", 25);
notificationIntent.Call<AndroidJavaObject>("putExtra", "data", "notification.IntentData");
notificationIntent.Call<AndroidJavaObject>("putExtra", "group", "notification.Group");
notificationIntent.Call<AndroidJavaObject>("putExtra", "groupSummary", true);
notificationIntent.Call<AndroidJavaObject>("putExtra", "sortKey", "notification.SortKey");
notificationIntent.Call<AndroidJavaObject>("putExtra", "groupAlertBehaviour", (int)GroupAlertBehaviours.GroupAlertChildren);
notificationIntent.Call<AndroidJavaObject>("putExtra", "showTimestamp", true);
var utilsClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationUtilities");
var bundle = notificationIntent.Call<AndroidJavaObject>("getExtras");
var parcelClass = new AndroidJavaClass("android.os.Parcel");
var parcel = parcelClass.CallStatic<AndroidJavaObject>("obtain");
bundle.Call("writeToParcel", parcel, 0);
var serialized = parcel.Call<AndroidJavaObject>("marshall");
Assert.IsNotNull(serialized);
var deserializedNotificationBuilder = utilsClass.CallStatic<AndroidJavaObject>("deserializeNotification", context, serialized);
Assert.IsNotNull(deserializedNotificationBuilder);
var deserializedNotification = deserializedNotificationBuilder.Call<AndroidJavaObject>("build");
Assert.IsNotNull(deserializedNotification);
var notificationData = AndroidNotificationCenter.GetNotificationData(deserializedNotification);
Assert.IsNotNull(notificationData);
Assert.AreEqual(notificationId, notificationData.Id);
Assert.AreEqual(kChannelId, notificationData.Channel);
Assert.AreEqual("notification.Title", notificationData.Notification.Title);
Assert.AreEqual("notification.Text", notificationData.Notification.Text);
Assert.AreEqual("notification.SmallIcon", notificationData.Notification.SmallIcon);
Assert.AreEqual(true, notificationData.Notification.ShouldAutoCancel);
Assert.AreEqual(true, notificationData.Notification.UsesStopwatch);
Assert.AreEqual(fireTime.ToString(), notificationData.Notification.FireTime.ToString());
Assert.AreEqual(repeatInterval.TotalMilliseconds, notificationData.Notification.RepeatInterval.Value.TotalMilliseconds);
Assert.AreEqual("notification.LargeIcon", notificationData.Notification.LargeIcon);
Assert.AreEqual(NotificationStyle.BigTextStyle, notificationData.Notification.Style);
Assert.AreEqual(color.ToInt(), notificationData.Notification.Color.ToInt());
Assert.AreEqual(25, notificationData.Notification.Number);
Assert.AreEqual("notification.IntentData", notificationData.Notification.IntentData);
Assert.AreEqual("notification.Group", notificationData.Notification.Group);
Assert.AreEqual(true, notificationData.Notification.GroupSummary);
Assert.AreEqual("notification.SortKey", notificationData.Notification.SortKey);
Assert.AreEqual(GroupAlertBehaviours.GroupAlertChildren, notificationData.Notification.GroupAlertBehaviour);
Assert.AreEqual(true, notificationData.Notification.ShowTimestamp);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void LegacyRecoverBuilderProducesTheSameNotification()
{
const int notificationId = 123;
var original = new AndroidNotification();
original.Title = "title";
original.Text = "text";
original.SmallIcon = "small_icon";
original.FireTime = DateTime.Now;
original.RepeatInterval = new TimeSpan(0, 0, 5);
original.LargeIcon = "large_icon";
original.Style = NotificationStyle.BigTextStyle;
original.Color = new Color(0.2f, 0.4f, 0.6f, 1.0f);
original.Number = 15;
original.ShouldAutoCancel = true;
original.UsesStopwatch = true;
original.Group = "group";
original.GroupSummary = true;
original.GroupAlertBehaviour = GroupAlertBehaviours.GroupAlertChildren;
original.SortKey = "sorting";
original.IntentData = "string for intent";
original.ShowTimestamp = true;
original.CustomTimestamp = new DateTime(2018, 5, 24, 12, 41, 30, 122);
var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId);
var notification = builder.Call<AndroidJavaObject>("build");
var managerClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationManager");
var manager = managerClass.GetStatic<AndroidJavaObject>("mUnityNotificationManager");
var context = manager.Get<AndroidJavaObject>("mContext");
var utils = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationUtilities");
var recoveredBuilder = utils.CallStatic<AndroidJavaObject>("recoverBuilderCustom", context, notification);
Assert.IsNotNull(recoveredBuilder);
var notificationAfterRecover = recoveredBuilder.Call<AndroidJavaObject>("build");
Assert.IsNotNull(notificationAfterRecover);
var notificationData = AndroidNotificationCenter.GetNotificationData(notificationAfterRecover);
Assert.IsNotNull(notificationData);
var notification2 = notificationData.Notification;
CheckNotificationsMatch(original, notification2);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void CorruptedPrimarySerialization_FallsBack()
{
const int notificationId = 234;
var original = new AndroidNotification();
original.Title = "title";
original.Text = "text";
original.SmallIcon = "small_icon";
original.FireTime = DateTime.Now;
original.LargeIcon = "large_icon";
AndroidJavaObject context, prefs;
using (var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId))
{
var managerClass = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationManager");
var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
context = activity.Call<AndroidJavaObject>("getApplicationContext");
var javaNotif = builder.Call<AndroidJavaObject>("build");
var testUtils = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationTestUtils");
prefs = context.Call<AndroidJavaObject>("getSharedPreferences", "android.notification.test.key", 0 /* MODE_PRIVATE */);
testUtils.CallStatic("serializeNotification", prefs, javaNotif);
}
var data = prefs.Call<string>("getString", "data", "");
// corrupt data
using (var editor = prefs.Call<AndroidJavaObject>("edit"))
{
editor.Call<AndroidJavaObject>("putString", "data", "jfkasjflksdjflkasdjflkjdsafkjsadfl").Dispose();
editor.Call("apply");
}
var data2 = prefs.Call<string>("getString", "data", "");
Assert.AreNotEqual(data, data2);
var utils = new AndroidJavaClass("com.unity.androidnotifications.UnityNotificationUtilities");
var deserializedNotificationBuilder = utils.CallStatic<AndroidJavaObject>("deserializeNotification", context, prefs);
// don't dispose notification, it is kept in AndroidNotificationIntentData
Assert.IsNotNull(deserializedNotificationBuilder);
var deserializedNotification = deserializedNotificationBuilder.Call<AndroidJavaObject>("build");
Assert.IsNotNull(deserializedNotification);
var deserializedData = AndroidNotificationCenter.GetNotificationData(deserializedNotification);
Assert.AreEqual(original.Title, deserializedData.Notification.Title);
Assert.AreEqual(original.Text, deserializedData.Notification.Text);
Assert.AreEqual(original.SmallIcon, deserializedData.Notification.SmallIcon);
Assert.AreEqual(original.LargeIcon, deserializedData.Notification.LargeIcon);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void CanDeserializeCustomSerializedNotification_v0()
{
const int notificationId = 245;
var original = CreateNotificationWithAllParameters();
AndroidNotificationIntentData deserialized;
using (var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId))
{
// put something to extrax to force completely custom serialization of them
var bitmap = CreateBitmap();
Assert.IsNotNull(bitmap);
var extras = builder.Call<AndroidJavaObject>("getExtras");
extras.Call("putParcelable", "binder_item", bitmap);
// Serialize like we did in version 0
deserialized = SerializeDeserializeNotificationWithFunc(builder, (u, s, j) => SerializeNotificationCustom_v0(u, s, j));
}
Assert.IsNotNull(deserialized);
original.ShowInForeground = true; // v0 did not have this, so should default to true
CheckNotificationsMatch(original, deserialized.Notification);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void CanDeserializeCustomSerializedNotification_v1()
{
const int notificationId = 255;
var original = CreateNotificationWithAllParameters();
AndroidNotificationIntentData deserialized;
using (var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId))
{
// put something to extrax to force completely custom serialization of them
var bitmap = CreateBitmap();
Assert.IsNotNull(bitmap);
var extras = builder.Call<AndroidJavaObject>("getExtras");
extras.Call("putParcelable", "binder_item", bitmap);
// Serialize like we did in version 1
deserialized = SerializeDeserializeNotificationWithFunc(builder, (u, s, j) => SerializeNotificationCustom_v1(u, s, j));
}
Assert.IsNotNull(deserialized);
CheckNotificationsMatch(original, deserialized.Notification);
}
[Test]
[UnityPlatform(RuntimePlatform.Android)]
public void CanDeserializeCustomSerializedNotification_v2()
{
const int notificationId = 255;
var original = CreateNotificationWithAllParameters();
AndroidNotificationIntentData deserialized;
using (var builder = AndroidNotificationCenter.CreateNotificationBuilder(notificationId, original, kChannelId))
{
// Serialize like we did in version 2
deserialized = SerializeDeserializeNotificationWithFunc(builder, (u, s, j) => SerializeNotificationCustom_v2(u, s, j));
}
Assert.IsNotNull(deserialized);
CheckNotificationsMatch(original, deserialized.Notification);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f2d51a3855e994c70bc3396a4f82b55d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,25 @@
{
"name": "Unity.Android.Notifications.Tests",
"rootNamespace": "",
"references": [
"Unity.Notifications.Android",
"UnityEngine.TestRunner",
"UnityEditor.TestRunner"
],
"includePlatforms": [
"Android",
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d6bcb02e32b9c47c8a8a5af0676695d5
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,200 @@
package com.unity.androidnotifications;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import android.app.Notification;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.util.Base64;
import android.util.Log;
import static com.unity.androidnotifications.UnityNotificationManager.KEY_ID;
import static com.unity.androidnotifications.UnityNotificationManager.KEY_FIRE_TIME;
import static com.unity.androidnotifications.UnityNotificationManager.KEY_REPEAT_INTERVAL;
import static com.unity.androidnotifications.UnityNotificationManager.KEY_INTENT_DATA;
import static com.unity.androidnotifications.UnityNotificationManager.KEY_SHOW_IN_FOREGROUND;
import static com.unity.androidnotifications.UnityNotificationManager.KEY_SMALL_ICON;
import static com.unity.androidnotifications.UnityNotificationManager.KEY_LARGE_ICON;
import static com.unity.androidnotifications.UnityNotificationManager.KEY_NOTIFICATION;
import static com.unity.androidnotifications.UnityNotificationManager.TAG_UNITY;
import static com.unity.androidnotifications.UnityNotificationUtilities.UNITY_MAGIC_NUMBER;
import static com.unity.androidnotifications.UnityNotificationUtilities.SAVED_NOTIFICATION_PRIMARY_KEY;
import static com.unity.androidnotifications.UnityNotificationUtilities.SAVED_NOTIFICATION_FALLBACK_KEY;
import static com.unity.androidnotifications.UnityNotificationUtilities.serializeNotificationParcel;
import static com.unity.androidnotifications.UnityNotificationUtilities.serializeParcelable;
import static com.unity.androidnotifications.UnityNotificationUtilities.serializeString;
// Java class for testing purposes, not included in regular build
public class UnityNotificationTestUtils {
// copy-paste of what serialization was in version 0 (except for hardcoded version number in here)
private static boolean serializeNotificationCustom_v0(Notification notification, DataOutputStream out) {
try {
out.write(UNITY_MAGIC_NUMBER);
out.writeInt(0); // NOTIFICATION_SERIALIZATION_VERSION
// serialize extras
boolean showWhen = notification.extras.getBoolean(Notification.EXTRA_SHOW_WHEN, false);
byte[] extras = serializeParcelable(notification.extras);
out.writeInt(extras == null ? 0 : extras.length);
if (extras != null && extras.length > 0)
out.write(extras);
else {
// parcelling may fail in case it contains binder object, when that happens serialize manually what we care about
out.writeInt(notification.extras.getInt(KEY_ID));
serializeString(out, notification.extras.getString(Notification.EXTRA_TITLE));
serializeString(out, notification.extras.getString(Notification.EXTRA_TEXT));
serializeString(out, notification.extras.getString(KEY_SMALL_ICON));
serializeString(out, notification.extras.getString(KEY_LARGE_ICON));
out.writeLong(notification.extras.getLong(KEY_FIRE_TIME, -1));
out.writeLong(notification.extras.getLong(KEY_REPEAT_INTERVAL, -1));
serializeString(out, Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? null : notification.extras.getString(Notification.EXTRA_BIG_TEXT));
out.writeBoolean(notification.extras.getBoolean(Notification.EXTRA_SHOW_CHRONOMETER, false));
out.writeBoolean(showWhen);
serializeString(out, notification.extras.getString(KEY_INTENT_DATA));
}
serializeString(out, Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? null : notification.getChannelId());
Integer color = UnityNotificationManager.getNotificationColor(notification);
out.writeBoolean(color != null);
if (color != null)
out.writeInt(color);
out.writeInt(notification.number);
out.writeBoolean(0 != (notification.flags & Notification.FLAG_AUTO_CANCEL));
serializeString(out, notification.getGroup());
out.writeBoolean(0 != (notification.flags & Notification.FLAG_GROUP_SUMMARY));
out.writeInt(UnityNotificationManager.getNotificationGroupAlertBehavior(notification));
serializeString(out, notification.getSortKey());
if (showWhen)
out.writeLong(notification.when);
return true;
} catch (Exception e) {
Log.e(TAG_UNITY, "Failed to serialize notification", e);
return false;
}
}
// copy-paste of what serialization was in version 1 (except for hardcoded version number in here)
private static boolean serializeNotificationCustom_v1(Notification notification, DataOutputStream out) {
try {
out.write(UNITY_MAGIC_NUMBER);
out.writeInt(1); // NOTIFICATION_SERIALIZATION_VERSION
// serialize extras
boolean showWhen = notification.extras.getBoolean(Notification.EXTRA_SHOW_WHEN, false);
byte[] extras = serializeParcelable(notification.extras);
out.writeInt(extras == null ? 0 : extras.length);
if (extras != null && extras.length > 0)
out.write(extras);
else {
// parcelling may fail in case it contains binder object, when that happens serialize manually what we care about
out.writeInt(notification.extras.getInt(KEY_ID));
serializeString(out, notification.extras.getString(Notification.EXTRA_TITLE));
serializeString(out, notification.extras.getString(Notification.EXTRA_TEXT));
serializeString(out, notification.extras.getString(KEY_SMALL_ICON));
serializeString(out, notification.extras.getString(KEY_LARGE_ICON));
out.writeLong(notification.extras.getLong(KEY_FIRE_TIME, -1));
out.writeLong(notification.extras.getLong(KEY_REPEAT_INTERVAL, -1));
serializeString(out, Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? null : notification.extras.getString(Notification.EXTRA_BIG_TEXT));
out.writeBoolean(notification.extras.getBoolean(Notification.EXTRA_SHOW_CHRONOMETER, false));
out.writeBoolean(showWhen);
serializeString(out, notification.extras.getString(KEY_INTENT_DATA));
out.writeBoolean(notification.extras.getBoolean(KEY_SHOW_IN_FOREGROUND, true));
}
serializeString(out, Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? null : notification.getChannelId());
Integer color = UnityNotificationManager.getNotificationColor(notification);
out.writeBoolean(color != null);
if (color != null)
out.writeInt(color);
out.writeInt(notification.number);
out.writeBoolean(0 != (notification.flags & Notification.FLAG_AUTO_CANCEL));
serializeString(out, notification.getGroup());
out.writeBoolean(0 != (notification.flags & Notification.FLAG_GROUP_SUMMARY));
out.writeInt(UnityNotificationManager.getNotificationGroupAlertBehavior(notification));
serializeString(out, notification.getSortKey());
if (showWhen)
out.writeLong(notification.when);
return true;
} catch (Exception e) {
Log.e(TAG_UNITY, "Failed to serialize notification", e);
return false;
}
}
// copy-paste of serializeNotification when it was primary & fallback keys
// minor altereration: call serializeNotificationCustom_v1
private static void serializeNotification(SharedPreferences prefs, Notification notification) {
try {
String serialized = null, fallback = null;
ByteArrayOutputStream data = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(data);
if (serializeNotificationCustom_v1(notification, out)) {
out.flush();
byte[] bytes = data.toByteArray();
fallback = Base64.encodeToString(bytes, 0, bytes.length, 0);
}
data.reset();
Intent intent = new Intent();
intent.putExtra(KEY_NOTIFICATION, notification);
if (serializeNotificationParcel(intent, out)) {
out.close();
byte[] bytes = data.toByteArray();
serialized = Base64.encodeToString(bytes, 0, bytes.length, 0);
}
else
serialized = fallback;
SharedPreferences.Editor editor = prefs.edit().clear();
editor.putString(SAVED_NOTIFICATION_PRIMARY_KEY, serialized);
editor.putString(SAVED_NOTIFICATION_FALLBACK_KEY, fallback);
editor.apply();
} catch (Exception e) {
Log.e(TAG_UNITY, "Failed to serialize notification", e);
}
}
// copy-paste of what serialization was in version 2 (except for hardcoded version number in here)
private static boolean serializeNotificationCustom_v2(Notification notification, DataOutputStream out) {
try {
out.write(UNITY_MAGIC_NUMBER);
out.writeInt(2); // NOTIFICATION_SERIALIZATION_VERSION
// serialize extras
boolean showWhen = notification.extras.getBoolean(Notification.EXTRA_SHOW_WHEN, false);
out.writeInt(notification.extras.getInt(KEY_ID));
serializeString(out, notification.extras.getString(Notification.EXTRA_TITLE));
serializeString(out, notification.extras.getString(Notification.EXTRA_TEXT));
serializeString(out, notification.extras.getString(KEY_SMALL_ICON));
serializeString(out, notification.extras.getString(KEY_LARGE_ICON));
out.writeLong(notification.extras.getLong(KEY_FIRE_TIME, -1));
out.writeLong(notification.extras.getLong(KEY_REPEAT_INTERVAL, -1));
serializeString(out, Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? null : notification.extras.getString(Notification.EXTRA_BIG_TEXT));
out.writeBoolean(notification.extras.getBoolean(Notification.EXTRA_SHOW_CHRONOMETER, false));
out.writeBoolean(showWhen);
serializeString(out, notification.extras.getString(KEY_INTENT_DATA));
out.writeBoolean(notification.extras.getBoolean(KEY_SHOW_IN_FOREGROUND, true));
serializeString(out, Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? null : notification.getChannelId());
Integer color = UnityNotificationManager.getNotificationColor(notification);
out.writeBoolean(color != null);
if (color != null)
out.writeInt(color);
out.writeInt(notification.number);
out.writeBoolean(0 != (notification.flags & Notification.FLAG_AUTO_CANCEL));
serializeString(out, notification.getGroup());
out.writeBoolean(0 != (notification.flags & Notification.FLAG_GROUP_SUMMARY));
out.writeInt(UnityNotificationManager.getNotificationGroupAlertBehavior(notification));
serializeString(out, notification.getSortKey());
if (showWhen)
out.writeLong(notification.when);
return true;
} catch (Exception e) {
Log.e(TAG_UNITY, "Failed to serialize notification", e);
return false;
}
}
}
@@ -0,0 +1,71 @@
fileFormatVersion: 2
guid: 3fc1afb2bf2c84b6f8919786f2f47b3f
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 1
Exclude Linux64: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
- first:
Android: Android
second:
enabled: 0
settings:
AndroidSharedLibraryType: Executable
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: x86_64
userData:
assetBundleName:
assetBundleVariant: