提交
This commit is contained in:
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 789bd7058dd3c4044ba6a7d9fe840a2b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Notifications.iOS;
|
||||
|
||||
namespace Unity.Notifications.Tests
|
||||
{
|
||||
public class ApiTestsiOS
|
||||
{
|
||||
[Test]
|
||||
public void TimeIntervalTrigger_MeasuredInSeconds()
|
||||
{
|
||||
var trigger = new iOSNotificationTimeIntervalTrigger();
|
||||
var interval = TimeSpan.FromMinutes(1);
|
||||
trigger.TimeInterval = interval;
|
||||
Assert.AreEqual(60, trigger.timeInterval);
|
||||
var outInterval = trigger.TimeInterval;
|
||||
Assert.AreEqual(interval, outInterval);
|
||||
|
||||
trigger.TimeInterval = new TimeSpan(0, 0, 1, 5, 50);
|
||||
// milliseconds should get discarded
|
||||
Assert.AreEqual(65, trigger.timeInterval);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TimeIntervalTrigger_RejectsLessThanSecond()
|
||||
{
|
||||
CheckTimeSpanIsRected(new TimeSpan(0, 0, 0, 0, 100));
|
||||
CheckTimeSpanIsRected(TimeSpan.FromSeconds(-3));
|
||||
}
|
||||
|
||||
void CheckTimeSpanIsRected(TimeSpan interval)
|
||||
{
|
||||
try
|
||||
{
|
||||
var trigger = new iOSNotificationTimeIntervalTrigger();
|
||||
trigger.TimeInterval = interval;
|
||||
Assert.Fail("Exception expected");
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 934f7d9817a584e38af6c229150b5480
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using Unity.Notifications.iOS;
|
||||
|
||||
namespace Unity.Notifications.Tests
|
||||
{
|
||||
internal class NotificationSettingsTests
|
||||
{
|
||||
[OneTimeSetUp]
|
||||
public void ResetSettings()
|
||||
{
|
||||
if (File.Exists(NotificationSettingsManager.k_SettingsPath))
|
||||
{
|
||||
File.Delete(NotificationSettingsManager.k_SettingsPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetAndroidNotifcationSettings_Works()
|
||||
{
|
||||
NotificationSettings.AndroidSettings.CustomActivityString = "com.test.dummy.activity";
|
||||
NotificationSettings.AndroidSettings.UseCustomActivity = true;
|
||||
NotificationSettings.AndroidSettings.RescheduleOnDeviceRestart = true;
|
||||
|
||||
Assert.AreEqual("com.test.dummy.activity", NotificationSettings.AndroidSettings.CustomActivityString);
|
||||
Assert.IsTrue(NotificationSettings.AndroidSettings.UseCustomActivity);
|
||||
Assert.IsTrue(NotificationSettings.AndroidSettings.RescheduleOnDeviceRestart);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetiOSNotifcationSettings_Works()
|
||||
{
|
||||
NotificationSettings.iOSSettings.AddRemoteNotificationCapability = true;
|
||||
NotificationSettings.iOSSettings.DefaultAuthorizationOptions = AuthorizationOption.Alert;
|
||||
NotificationSettings.iOSSettings.UseLocationNotificationTrigger = true;
|
||||
NotificationSettings.iOSSettings.UseAPSReleaseEnvironment = true;
|
||||
NotificationSettings.iOSSettings.RemoteNotificationForegroundPresentationOptions = PresentationOption.Alert;
|
||||
NotificationSettings.iOSSettings.RequestAuthorizationOnAppLaunch = true;
|
||||
NotificationSettings.iOSSettings.NotificationRequestAuthorizationForRemoteNotificationsOnAppLaunch = true;
|
||||
|
||||
Assert.IsTrue(NotificationSettings.iOSSettings.AddRemoteNotificationCapability);
|
||||
Assert.IsTrue(NotificationSettings.iOSSettings.UseLocationNotificationTrigger);
|
||||
Assert.IsTrue(NotificationSettings.iOSSettings.UseAPSReleaseEnvironment);
|
||||
Assert.IsTrue(NotificationSettings.iOSSettings.RequestAuthorizationOnAppLaunch);
|
||||
Assert.IsTrue(NotificationSettings.iOSSettings.NotificationRequestAuthorizationForRemoteNotificationsOnAppLaunch);
|
||||
|
||||
Assert.AreEqual(PresentationOption.Alert, NotificationSettings.iOSSettings.RemoteNotificationForegroundPresentationOptions);
|
||||
Assert.AreEqual(AuthorizationOption.Alert, NotificationSettings.iOSSettings.DefaultAuthorizationOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c12d2439337c4d1d90aa2a02fbab9bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
using System.Xml;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Unity.Notifications.Tests
|
||||
{
|
||||
internal class PostprocessorTests
|
||||
{
|
||||
[Test]
|
||||
public void DummmyTest()
|
||||
{
|
||||
Assert.AreEqual(true, true);
|
||||
}
|
||||
|
||||
const string kManifestTemplate = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<manifest xmlns:android=""http://schemas.android.com/apk/res/android"" package=""com.UnityTestRunner.UnityTestRunner"" xmlns:tools=""http://schemas.android.com/tools"" android:installLocation=""preferExternal"">
|
||||
<supports-screens android:smallScreens=""true"" android:normalScreens=""true"" android:largeScreens=""true"" android:xlargeScreens=""true"" android:anyDensity=""true"" />
|
||||
<application android:theme=""@style/UnityThemeSelector"" android:icon=""@mipmap/app_icon"" android:label=""@string/app_name"" android:isGame=""true"" android:banner=""@drawable/app_banner"">
|
||||
<activity android:label=""@string/app_name"" android:screenOrientation=""fullSensor"" android:launchMode=""singleTask"" android:configChanges=""mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"" android:hardwareAccelerated=""false"" android:name=""com.UnityTestRunner.UnityTestRunner.UnityPlayerActivity"">
|
||||
<intent-filter>
|
||||
<action android:name=""android.intent.action.MAIN"" />
|
||||
<category android:name=""android.intent.category.LAUNCHER"" />
|
||||
<category android:name=""android.intent.category.LEANBACK_LAUNCHER"" />
|
||||
</intent-filter>
|
||||
<meta-data android:name=""unityplayer.UnityActivity"" android:value=""true"" />
|
||||
</activity>
|
||||
<meta-data android:name=""unity.build-id"" android:value=""8a616d3b-0433-49d8-bbaf-fd1415e8701e"" />
|
||||
<meta-data android:name=""unity.splash-mode"" android:value=""0"" />
|
||||
<meta-data android:name=""unity.splash-enable"" android:value=""True"" />{0}
|
||||
</application>
|
||||
<uses-feature android:glEsVersion=""0x00020000"" />
|
||||
<uses-permission android:name=""android.permission.INTERNET"" />
|
||||
<uses-permission android:name=""android.permission.WRITE_EXTERNAL_STORAGE"" android:maxSdkVersion=""18"" />
|
||||
<uses-permission android:name=""android.permission.READ_EXTERNAL_STORAGE"" android:maxSdkVersion=""18"" />{1}
|
||||
<uses-feature android:name=""android.hardware.touchscreen"" android:required=""false"" />
|
||||
<uses-feature android:name=""android.hardware.touchscreen.multitouch"" android:required=""false"" />
|
||||
<uses-feature android:name=""android.hardware.touchscreen.multitouch.distinct"" android:required=""false"" />
|
||||
</manifest>";
|
||||
const string kRescheduleOnRestartFalse = "<meta-data android:name=\"reschedule_notifications_on_restart\" android:value=\"false\" />";
|
||||
const string kRescheduleOnRestartTrue = "<meta-data android:name=\"reschedule_notifications_on_restart\" android:value=\"true\" />";
|
||||
const string kExactSchedulingOn = "<meta-data android:name=\"com.unity.androidnotifications.exact_scheduling\" android:value=\"1\" />";
|
||||
const string kExactSchedulingOff = "<meta-data android:name=\"com.unity.androidnotifications.exact_scheduling\" android:value=\"0\" />";
|
||||
const string kReceiveBookCompletedPermission = "<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />";
|
||||
const string kScheduleExactAlarmPermission = "<uses-permission android:name=\"android.permission.SCHEDULE_EXACT_ALARM\" />";
|
||||
const string kUseExactAlarmPermission = "<uses-permission android:name=\"android.permission.USE_EXACT_ALARM\" />";
|
||||
const string kRequestIgnoreBatteryOptimizationsPermission = "<uses-permission-sdk-23 android:name=\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\" />";
|
||||
|
||||
string GetSourceXml(string metaDataExtra, string permissionExtra)
|
||||
{
|
||||
if (metaDataExtra == null)
|
||||
metaDataExtra = "";
|
||||
if (permissionExtra == null)
|
||||
permissionExtra = "";
|
||||
return string.Format(kManifestTemplate, metaDataExtra, permissionExtra);
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID
|
||||
[Test]
|
||||
public void AppendMetadataToManifest_WhenSameValue_Works()
|
||||
{
|
||||
string sourceXmlContent = GetSourceXml(kRescheduleOnRestartTrue, null);
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
xmlDoc.LoadXml(sourceXmlContent);
|
||||
|
||||
|
||||
AndroidNotificationPostProcessor.AppendAndroidMetadataField(null, xmlDoc, "reschedule_notifications_on_restart", "true");
|
||||
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains(kRescheduleOnRestartTrue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AppendMetadataToManifest_WhenOtherValue_Works()
|
||||
{
|
||||
string sourceXmlContent = GetSourceXml(kRescheduleOnRestartFalse, null);
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
xmlDoc.LoadXml(sourceXmlContent);
|
||||
|
||||
|
||||
AndroidNotificationPostProcessor.AppendAndroidMetadataField(null, xmlDoc, "reschedule_notifications_on_restart", "true");
|
||||
|
||||
Assert.IsFalse(xmlDoc.InnerXml.Contains(kRescheduleOnRestartFalse));
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains(kRescheduleOnRestartTrue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AppendMetadataToManifest_WhenNotPresent_Works()
|
||||
{
|
||||
string sourceXmlContent = GetSourceXml(null, null);
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
xmlDoc.LoadXml(sourceXmlContent);
|
||||
|
||||
|
||||
AndroidNotificationPostProcessor.AppendAndroidMetadataField(null, xmlDoc, "reschedule_notifications_on_restart", "true");
|
||||
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains(kRescheduleOnRestartTrue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AppendMetadataToManifest_WhenOtherFieldPresentWorks()
|
||||
{
|
||||
string sourceXmlContent = GetSourceXml(kRescheduleOnRestartTrue, null);
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
xmlDoc.LoadXml(sourceXmlContent);
|
||||
|
||||
|
||||
AndroidNotificationPostProcessor.AppendAndroidMetadataField(null, xmlDoc, "do_something", "true");
|
||||
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains(kRescheduleOnRestartTrue));
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains("<meta-data android:name=\"do_something\" android:value=\"true\" />"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AppendPermissionToManifest_WhenNoPresentWorks()
|
||||
{
|
||||
string sourceXmlContent = GetSourceXml(null, null);
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
xmlDoc.LoadXml(sourceXmlContent);
|
||||
|
||||
|
||||
AndroidNotificationPostProcessor.AppendAndroidPermissionField(null, xmlDoc, "android.permission.RECEIVE_BOOT_COMPLETED");
|
||||
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains(kReceiveBookCompletedPermission));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AppendPermissionToManifest_WhenAlreadyPresentWorks()
|
||||
{
|
||||
string sourceXmlContent = GetSourceXml(null, kReceiveBookCompletedPermission);
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
xmlDoc.LoadXml(sourceXmlContent);
|
||||
|
||||
|
||||
AndroidNotificationPostProcessor.AppendAndroidPermissionField(null, xmlDoc, "android.permission.RECEIVE_BOOT_COMPLETED");
|
||||
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains(kReceiveBookCompletedPermission));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectAndroidManifest_AddsScheduleExactWhenEnabled()
|
||||
{
|
||||
InjectAndroidManifest_AddsPermissionWhenEnabled(AndroidExactSchedulingOption.AddScheduleExactPermission, kScheduleExactAlarmPermission);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectAndroidManifest_AddsUseExactWhenEnabled()
|
||||
{
|
||||
InjectAndroidManifest_AddsPermissionWhenEnabled(AndroidExactSchedulingOption.AddUseExactAlarmPermission, kUseExactAlarmPermission);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectAndroidManifest_AddsBatteryOptimizationsWhenEnabled()
|
||||
{
|
||||
InjectAndroidManifest_AddsPermissionWhenEnabled(AndroidExactSchedulingOption.AddRequestIgnoreBatteryOptimizationsPermission, kRequestIgnoreBatteryOptimizationsPermission);
|
||||
//InjectAndroidManifest_AddsPermissionWhenEnabled(AndroidExactSchedulingOption.AddRequestIgnoreBatteryOptimizationsPermission, "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS");
|
||||
}
|
||||
|
||||
public void InjectAndroidManifest_AddsPermissionWhenEnabled(AndroidExactSchedulingOption flag, string permission)
|
||||
{
|
||||
string sourceXmlContent = GetSourceXml(null, null);
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
xmlDoc.LoadXml(sourceXmlContent);
|
||||
var settings = new AndroidNotificationPostProcessor.ManifestSettings()
|
||||
{
|
||||
ExactAlarm = AndroidExactSchedulingOption.ExactWhenAvailable | flag,
|
||||
};
|
||||
|
||||
AndroidNotificationPostProcessor.InjectAndroidManifest("test", xmlDoc, settings);
|
||||
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains(kExactSchedulingOn));
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains(permission));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectAndroidManifest_DoesNotAddScheduleExactWhenExactNotEnabled()
|
||||
{
|
||||
InjectAndroidManifest_DoesNotAddPermissionWhenExactNotEnabled("android.permission.SCHEDULE_EXACT_ALARM");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectAndroidManifest_DoesNotAddUseExactWhenExactNotEnabled()
|
||||
{
|
||||
InjectAndroidManifest_DoesNotAddPermissionWhenExactNotEnabled("android.permission.USE_EXACT_ALARM");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InjectAndroidManifest_DoesNotAddBatteryOptimizationsWhenExactNotEnabled()
|
||||
{
|
||||
InjectAndroidManifest_DoesNotAddPermissionWhenExactNotEnabled("android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS");
|
||||
}
|
||||
|
||||
public void InjectAndroidManifest_DoesNotAddPermissionWhenExactNotEnabled(string permission)
|
||||
{
|
||||
string sourceXmlContent = GetSourceXml(null, null);
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
xmlDoc.LoadXml(sourceXmlContent);
|
||||
var settings = new AndroidNotificationPostProcessor.ManifestSettings()
|
||||
{
|
||||
// AndroidExactSchedulingOption.ExactWhenAvailable absent, so this one is ignored
|
||||
ExactAlarm = AndroidExactSchedulingOption.AddScheduleExactPermission,
|
||||
};
|
||||
|
||||
AndroidNotificationPostProcessor.InjectAndroidManifest("test", xmlDoc, settings);
|
||||
|
||||
Assert.IsTrue(xmlDoc.InnerXml.Contains(kExactSchedulingOff));
|
||||
Assert.IsFalse(xmlDoc.InnerXml.Contains(permission));
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad29723af4e864cf2bce62d266ce900a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Unity.Notifications.Tests",
|
||||
"references": [
|
||||
"Unity.Notifications",
|
||||
"Unity.Notifications.iOS"
|
||||
],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
]
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c29b1cefd8e67404885a0dafaded033c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f94bb771ac3e54dcba889a55ee20b179
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f00e76f28f7d840f7a9fe86e0eb2342d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+512
@@ -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);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5e41e41f251d43eab8e92409720999a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+779
@@ -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);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2d51a3855e994c70bc3396a4f82b55d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+25
@@ -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
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6bcb02e32b9c47c8a8a5af0676695d5
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+200
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -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:
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 581bf0866e80342aea7a3090af8acef6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "Unity.iOS.Notifications.Tests",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Unity.Notifications.iOS",
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"Unity.Notifications"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor",
|
||||
"iOS"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d95fe6c738866495fa62f4d53295ef83
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+501
@@ -0,0 +1,501 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
using System.Collections;
|
||||
using Unity.Notifications.iOS;
|
||||
#if UNITY_EDITOR
|
||||
using Unity.Notifications;
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
class iOSNotificationTests
|
||||
: IPrebuildSetup, IPostBuildCleanup
|
||||
{
|
||||
private static int receivedNotificationCount = 0;
|
||||
private static iOSNotification lastReceivedNotification = null;
|
||||
#if UNITY_EDITOR
|
||||
private static iOSSdkVersion originaliOSSDK;
|
||||
private static bool originalRequestAuthorizationOnAppLaunch;
|
||||
private static AuthorizationOption originalAuthorizationOptions;
|
||||
private static bool originalAddRemoteNotificationCapability;
|
||||
private static bool originalRequestRemoteOnLaunch;
|
||||
#endif
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
originaliOSSDK = PlayerSettings.iOS.sdkVersion;
|
||||
originalRequestAuthorizationOnAppLaunch = NotificationSettings.iOSSettings.RequestAuthorizationOnAppLaunch;
|
||||
originalAuthorizationOptions = NotificationSettings.iOSSettings.DefaultAuthorizationOptions;
|
||||
originalAddRemoteNotificationCapability = NotificationSettings.iOSSettings.AddRemoteNotificationCapability;
|
||||
originalRequestRemoteOnLaunch = NotificationSettings.iOSSettings.NotificationRequestAuthorizationForRemoteNotificationsOnAppLaunch;
|
||||
|
||||
PlayerSettings.iOS.sdkVersion = iOSSdkVersion.SimulatorSDK;
|
||||
NotificationSettings.iOSSettings.RequestAuthorizationOnAppLaunch = true;
|
||||
NotificationSettings.iOSSettings.DefaultAuthorizationOptions = originalAuthorizationOptions | AuthorizationOption.Provisional;
|
||||
NotificationSettings.iOSSettings.AddRemoteNotificationCapability = false;
|
||||
NotificationSettings.iOSSettings.NotificationRequestAuthorizationForRemoteNotificationsOnAppLaunch = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
PlayerSettings.iOS.sdkVersion = originaliOSSDK;
|
||||
NotificationSettings.iOSSettings.RequestAuthorizationOnAppLaunch = originalRequestAuthorizationOnAppLaunch;
|
||||
NotificationSettings.iOSSettings.DefaultAuthorizationOptions = originalAuthorizationOptions;
|
||||
NotificationSettings.iOSSettings.AddRemoteNotificationCapability = originalAddRemoteNotificationCapability;
|
||||
NotificationSettings.iOSSettings.NotificationRequestAuthorizationForRemoteNotificationsOnAppLaunch = originalRequestRemoteOnLaunch;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !UNITY_EDITOR
|
||||
[OneTimeSetUp]
|
||||
public void BeforeTests()
|
||||
{
|
||||
iOSNotificationCenter.OnNotificationReceived += receivedNotification =>
|
||||
{
|
||||
receivedNotificationCount += 1;
|
||||
lastReceivedNotification = receivedNotification;
|
||||
var msg = "Notification received : " + receivedNotification.Identifier + "\n";
|
||||
msg += "\n Notification received: ";
|
||||
msg += "\n .Title: " + receivedNotification.Title;
|
||||
msg += "\n .Badge: " + receivedNotification.Badge;
|
||||
msg += "\n .Body: " + receivedNotification.Body;
|
||||
msg += "\n .CategoryIdentifier: " + receivedNotification.CategoryIdentifier;
|
||||
msg += "\n .Subtitle: " + receivedNotification.Subtitle;
|
||||
Debug.Log(msg);
|
||||
};
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void AfterEachTest()
|
||||
{
|
||||
receivedNotificationCount = 0;
|
||||
lastReceivedNotification = null;
|
||||
iOSNotificationCenter.RemoveAllScheduledNotifications();
|
||||
}
|
||||
#endif
|
||||
|
||||
IEnumerator WaitForNotification(float timeout)
|
||||
{
|
||||
var startCount = receivedNotificationCount;
|
||||
float timePassed = 0;
|
||||
while (receivedNotificationCount == startCount && timePassed < timeout)
|
||||
{
|
||||
yield return null;
|
||||
timePassed += Time.deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(RuntimePlatform.IPhonePlayer)]
|
||||
public IEnumerator SendSimpleNotification_NotificationIsReceived()
|
||||
{
|
||||
var timeTrigger = new iOSNotificationTimeIntervalTrigger()
|
||||
{
|
||||
TimeInterval = new TimeSpan(0, 0, 5),
|
||||
Repeats = false
|
||||
};
|
||||
|
||||
// You can optionally specify a custom Identifier which can later be
|
||||
// used to cancel the notification, if you don't set one, an unique
|
||||
// string will be generated automatically.
|
||||
var notification = new iOSNotification()
|
||||
{
|
||||
Identifier = "_notification_01",
|
||||
Title = "SendSimpleNotification_NotificationIsReceived",
|
||||
Body = "Scheduled at: " + DateTime.Now.ToShortDateString() + " triggered in 5 seconds",
|
||||
Subtitle = "This is a subtitle, something, something important...",
|
||||
ShowInForeground = true,
|
||||
ForegroundPresentationOption = (PresentationOption.Alert |
|
||||
PresentationOption.Sound),
|
||||
CategoryIdentifier = "category_a",
|
||||
ThreadIdentifier = "thread1",
|
||||
Trigger = timeTrigger,
|
||||
};
|
||||
|
||||
iOSNotificationCenter.ScheduleNotification(notification);
|
||||
|
||||
yield return WaitForNotification(10.0f);
|
||||
Assert.AreEqual(1, receivedNotificationCount);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(RuntimePlatform.IPhonePlayer)]
|
||||
public IEnumerator SendNotificationWithUserInfo_NotificationIsReceivedWithSameUserInfo()
|
||||
{
|
||||
var timeTrigger = new iOSNotificationTimeIntervalTrigger()
|
||||
{
|
||||
TimeInterval = new TimeSpan(0, 0, 5),
|
||||
Repeats = false
|
||||
};
|
||||
|
||||
var notification = new iOSNotification()
|
||||
{
|
||||
Identifier = "_notification_02",
|
||||
Title = "SendNotificationWithUserInfo_NotificationIsReceivedWithSameUserInfo",
|
||||
Body = "Scheduled at: " + DateTime.Now.ToShortDateString() + " triggered in 5 seconds",
|
||||
Subtitle = "This is a subtitle, something, something important...",
|
||||
ShowInForeground = true,
|
||||
ForegroundPresentationOption = PresentationOption.Alert | PresentationOption.Sound,
|
||||
CategoryIdentifier = "category_a",
|
||||
ThreadIdentifier = "thread1",
|
||||
Trigger = timeTrigger,
|
||||
};
|
||||
|
||||
notification.UserInfo.Add("key1", "value1");
|
||||
|
||||
iOSNotificationCenter.ScheduleNotification(notification);
|
||||
|
||||
yield return WaitForNotification(10.0f);
|
||||
Assert.AreEqual(1, receivedNotificationCount);
|
||||
Assert.IsNotNull(lastReceivedNotification);
|
||||
Assert.IsTrue(lastReceivedNotification.UserInfo.ContainsKey("key1"));
|
||||
Assert.AreEqual("value1", lastReceivedNotification.UserInfo["key1"]);
|
||||
}
|
||||
|
||||
IEnumerator SendNotificationUsingCalendarTrigger_NotificationIsReceived(string text, bool useUtc)
|
||||
{
|
||||
var dateTime = useUtc ? DateTime.UtcNow : DateTime.Now;
|
||||
var dt = dateTime.AddSeconds(5);
|
||||
var trigger = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Year = dt.Year,
|
||||
Month = dt.Month,
|
||||
Day = dt.Day,
|
||||
Hour = dt.Hour,
|
||||
Minute = dt.Minute,
|
||||
Second = dt.Second,
|
||||
UtcTime = useUtc,
|
||||
};
|
||||
|
||||
var notification = new iOSNotification()
|
||||
{
|
||||
Title = text,
|
||||
Body = text,
|
||||
ShowInForeground = true,
|
||||
ForegroundPresentationOption = PresentationOption.Alert,
|
||||
Trigger = trigger,
|
||||
};
|
||||
|
||||
iOSNotificationCenter.ScheduleNotification(notification);
|
||||
Debug.Log($"SendNotificationUsingCalendarTrigger_NotificationIsReceived, Now: {dateTime}, Notification should arrive on: {dt}");
|
||||
yield return WaitForNotification(20.0f);
|
||||
Debug.Log($"SendNotificationUsingCalendarTrigger_NotificationIsReceived, wait finished at: {DateTime.Now}");
|
||||
Assert.AreEqual(1, receivedNotificationCount);
|
||||
Assert.IsNotNull(lastReceivedNotification);
|
||||
Assert.AreEqual(text, lastReceivedNotification.Title);
|
||||
var retTrigger = (iOSNotificationCalendarTrigger)lastReceivedNotification.Trigger;
|
||||
Assert.AreEqual(useUtc, retTrigger.UtcTime);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(RuntimePlatform.IPhonePlayer)]
|
||||
public IEnumerator SendNotificationUsingCalendarTriggerLocalTime_NotificationIsReceived()
|
||||
{
|
||||
yield return SendNotificationUsingCalendarTrigger_NotificationIsReceived("SendNotificationUsingCalendarTriggerLocalTime_NotificationIsReceived", false);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(RuntimePlatform.IPhonePlayer)]
|
||||
public IEnumerator SendNotificationUsingCalendarTriggerUtcTime_NotificationIsReceived()
|
||||
{
|
||||
yield return SendNotificationUsingCalendarTrigger_NotificationIsReceived("SendNotificationUsingCalendarTriggerUtcTime_NotificationIsReceived", true);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(RuntimePlatform.IPhonePlayer)]
|
||||
public IEnumerator SendNotification_AllPropertiesRoundtrip()
|
||||
{
|
||||
var trigger = new iOSNotificationTimeIntervalTrigger()
|
||||
{
|
||||
TimeInterval = new TimeSpan(0, 0, 5),
|
||||
Repeats = false,
|
||||
};
|
||||
|
||||
var notification = new iOSNotification()
|
||||
{
|
||||
Trigger = trigger,
|
||||
Identifier = "roundtrip",
|
||||
CategoryIdentifier = "category",
|
||||
ThreadIdentifier = "thread",
|
||||
Title = "Title",
|
||||
Subtitle = "subtitle",
|
||||
Body = "body",
|
||||
Badge = 2,
|
||||
InterruptionLevel = NotificationInterruptionLevel.Critical,
|
||||
RelevanceScore = 1.0,
|
||||
ShowInForeground = true,
|
||||
ForegroundPresentationOption = PresentationOption.Alert,
|
||||
};
|
||||
|
||||
iOSNotificationCenter.ScheduleNotification(notification);
|
||||
|
||||
yield return WaitForNotification(10.0f);
|
||||
Assert.AreEqual(1, receivedNotificationCount);
|
||||
Assert.IsNotNull(lastReceivedNotification);
|
||||
CompareNotifications(notification, lastReceivedNotification);
|
||||
}
|
||||
|
||||
void CompareNotifications(iOSNotification expected, iOSNotification actual)
|
||||
{
|
||||
// these don't roundtrip or are tested separately
|
||||
var ignoredProps = new[]
|
||||
{
|
||||
"Attachments",
|
||||
"SoundName",
|
||||
"SoundType",
|
||||
"SoundVolume",
|
||||
"UserInfo",
|
||||
};
|
||||
foreach (var prop in typeof(iOSNotification).GetProperties())
|
||||
{
|
||||
if (ignoredProps.Contains(prop.Name))
|
||||
continue;
|
||||
var v1 = prop.GetValue(expected);
|
||||
var v2 = prop.GetValue(actual);
|
||||
if (prop.PropertyType.IsValueType)
|
||||
{
|
||||
if (prop.PropertyType.IsPrimitive)
|
||||
{
|
||||
if (prop.PropertyType == typeof(bool))
|
||||
{
|
||||
if (!(bool)v2)
|
||||
Assert.Fail($"Expected property {prop.Name} to be true");
|
||||
}
|
||||
else
|
||||
{
|
||||
int intVal = ((IConvertible)v2).ToInt32(System.Globalization.CultureInfo.InvariantCulture);
|
||||
if (intVal == 0)
|
||||
Assert.Fail($"Expected property {prop.Name} to be non-zero");
|
||||
}
|
||||
}
|
||||
else if (prop.PropertyType.IsEnum)
|
||||
{
|
||||
int intVal = (int)v2;
|
||||
if (intVal == 0)
|
||||
Assert.Fail($"Expected property {prop.Name} to be non-zero");
|
||||
}
|
||||
else
|
||||
Assert.Fail($"Property {prop.Name} not handled");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v2 == null)
|
||||
Assert.Fail($"Property {prop.Name} value is null");
|
||||
}
|
||||
|
||||
if (!object.Equals(v1, v2))
|
||||
Assert.Fail($"Value missmatch for property {prop.Name}: '{v1}' vs '{v2}'");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void iOSNotificationCalendarTrigger_ToUtc_DoesNotConvertUtcTrigger()
|
||||
{
|
||||
var trigger = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Hour = 5,
|
||||
Minute = 5,
|
||||
UtcTime = true,
|
||||
};
|
||||
|
||||
var utcTrigger = trigger.ToUtc();
|
||||
|
||||
Assert.AreEqual(5, utcTrigger.Hour);
|
||||
Assert.AreEqual(5, utcTrigger.Minute);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void iOSNotificationCalendarTrigger_ToUtc_ConvertsLocalTrigger()
|
||||
{
|
||||
var localTime = DateTime.Now;
|
||||
var utcTime = localTime.ToUniversalTime();
|
||||
if (DateTime.Compare(localTime, utcTime) == 0)
|
||||
return; // running test in GMT time zode
|
||||
|
||||
var trigger = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Hour = localTime.Hour,
|
||||
Minute = localTime.Minute,
|
||||
UtcTime = false,
|
||||
};
|
||||
|
||||
var utcTrigger = trigger.ToUtc();
|
||||
|
||||
Assert.AreEqual(utcTime.Hour, utcTrigger.Hour);
|
||||
Assert.AreEqual(utcTime.Minute, utcTrigger.Minute);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void iOSNotificationCalendarTrigger_ToLocal_DoesNotConvertLocalTrigger()
|
||||
{
|
||||
var trigger = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Hour = 5,
|
||||
Minute = 5,
|
||||
UtcTime = false,
|
||||
};
|
||||
|
||||
var localTrigger = trigger.ToLocal();
|
||||
|
||||
Assert.AreEqual(5, localTrigger.Hour);
|
||||
Assert.AreEqual(5, localTrigger.Minute);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void iOSNotificationCalendarTrigger_ToLocal_ConvertsUtcTrigger()
|
||||
{
|
||||
var localTime = DateTime.Now;
|
||||
var utcTime = localTime.ToUniversalTime();
|
||||
if (DateTime.Compare(localTime, utcTime) == 0)
|
||||
return; // running test in GMT time zode
|
||||
|
||||
var trigger = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Hour = utcTime.Hour,
|
||||
Minute = utcTime.Minute,
|
||||
UtcTime = true,
|
||||
};
|
||||
|
||||
var localTrigger = trigger.ToLocal();
|
||||
|
||||
Assert.AreEqual(localTime.Hour, localTrigger.Hour);
|
||||
Assert.AreEqual(localTime.Minute, localTrigger.Minute);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void iOSNotificationCalendarTrigger_AssignDateTimeComponents_OnlyChangesNonNullFields()
|
||||
{
|
||||
var dt = new DateTime(2025, 5, 5, 6, 6, 6);
|
||||
|
||||
var trigger = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Year = 2020,
|
||||
Month = 10,
|
||||
Day = 8,
|
||||
};
|
||||
|
||||
var check = trigger.AssignDateTimeComponents(dt);
|
||||
Assert.AreEqual(2020, check.Year);
|
||||
Assert.AreEqual(10, check.Month);
|
||||
Assert.AreEqual(8, check.Day);
|
||||
Assert.AreEqual(6, check.Hour);
|
||||
Assert.AreEqual(6, check.Minute);
|
||||
Assert.AreEqual(6, check.Second);
|
||||
|
||||
trigger = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Hour = 3,
|
||||
Minute = 4,
|
||||
Second = 20,
|
||||
};
|
||||
|
||||
check = trigger.AssignDateTimeComponents(dt);
|
||||
Assert.AreEqual(2025, check.Year);
|
||||
Assert.AreEqual(5, check.Month);
|
||||
Assert.AreEqual(5, check.Day);
|
||||
Assert.AreEqual(3, check.Hour);
|
||||
Assert.AreEqual(4, check.Minute);
|
||||
Assert.AreEqual(20, check.Second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void iOSNotificationCalendarTrigger_AssignNonEmptyComponents_Works()
|
||||
{
|
||||
var dt = new DateTime(2025, 1, 2, 3, 4, 5);
|
||||
|
||||
var trigger = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Year = 2020,
|
||||
Month = 10,
|
||||
Day = 10,
|
||||
};
|
||||
|
||||
trigger.AssignNonEmptyComponents(dt);
|
||||
Assert.AreEqual(2025, trigger.Year);
|
||||
Assert.AreEqual(1, trigger.Month);
|
||||
Assert.AreEqual(2, trigger.Day);
|
||||
Assert.IsTrue(null == trigger.Hour);
|
||||
Assert.IsTrue(null == trigger.Minute);
|
||||
Assert.IsTrue(null == trigger.Second);
|
||||
|
||||
trigger = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Hour = 10,
|
||||
Minute = 10,
|
||||
Second = 10,
|
||||
};
|
||||
|
||||
trigger.AssignNonEmptyComponents(dt);
|
||||
Assert.IsTrue(null == trigger.Year);
|
||||
Assert.IsTrue(null == trigger.Month);
|
||||
Assert.IsTrue(null == trigger.Day);
|
||||
Assert.AreEqual(3, trigger.Hour);
|
||||
Assert.AreEqual(4, trigger.Minute);
|
||||
Assert.AreEqual(5, trigger.Second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void iOSNotification_CalendarTrigger_ReturnsSameKindDateTime()
|
||||
{
|
||||
var trigger1 = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Hour = 8,
|
||||
Minute = 30,
|
||||
UtcTime = false,
|
||||
};
|
||||
|
||||
var trigger2 = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Hour = 8,
|
||||
Minute = 30,
|
||||
UtcTime = false,
|
||||
};
|
||||
|
||||
var notification = new iOSNotification()
|
||||
{
|
||||
Title = "text",
|
||||
Body = "text",
|
||||
Trigger = trigger1,
|
||||
};
|
||||
|
||||
var retTrigger = (iOSNotificationCalendarTrigger)notification.Trigger;
|
||||
|
||||
Assert.AreEqual(trigger1.Hour, retTrigger.Hour);
|
||||
Assert.AreEqual(trigger1.Minute, retTrigger.Minute);
|
||||
Assert.AreEqual(trigger1.UtcTime, retTrigger.UtcTime);
|
||||
|
||||
notification.Trigger = trigger2;
|
||||
retTrigger = (iOSNotificationCalendarTrigger)notification.Trigger;
|
||||
|
||||
Assert.AreEqual(trigger2.Hour, retTrigger.Hour);
|
||||
Assert.AreEqual(trigger2.Minute, retTrigger.Minute);
|
||||
Assert.AreEqual(trigger2.UtcTime, retTrigger.UtcTime);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void iOSNotificationCalendarTrigger_HandlesMissingUtcField()
|
||||
{
|
||||
var original = new iOSNotificationCalendarTrigger()
|
||||
{
|
||||
Day = 5,
|
||||
};
|
||||
|
||||
var notification = new iOSNotification()
|
||||
{
|
||||
Trigger = original,
|
||||
};
|
||||
|
||||
// clear UserInfo, where UTC flag is stored
|
||||
notification.UserInfo.Clear();
|
||||
|
||||
Assert.AreEqual(iOSNotificationTriggerType.Calendar, notification.Trigger.Type);
|
||||
var result = (iOSNotificationCalendarTrigger)notification.Trigger;
|
||||
Assert.AreEqual(5, result.Day);
|
||||
Assert.IsFalse(result.UtcTime);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3f7a1ae7f099482db44467671fc8ef6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60e17545d141d4641a43105c257e6d2f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using Unity.Notifications;
|
||||
|
||||
class UnifiedNotificationsSendingTests
|
||||
{
|
||||
[OneTimeSetUp]
|
||||
public void BeforeTests()
|
||||
{
|
||||
var args = NotificationCenterArgs.Default;
|
||||
args.AndroidChannelId = "Unified";
|
||||
args.AndroidChannelName = "Unified";
|
||||
args.AndroidChannelDescription = "Unified notifications";
|
||||
NotificationCenter.Initialize(args);
|
||||
NotificationCenter.OnNotificationReceived += OnNotificationReceived;
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void AfterAllTests()
|
||||
{
|
||||
NotificationCenter.CancelAllScheduledNotifications();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void BeforeEachTest()
|
||||
{
|
||||
NotificationCenter.CancelAllScheduledNotifications();
|
||||
receivedNotificationCount = 0;
|
||||
lastNotification = null;
|
||||
}
|
||||
|
||||
uint receivedNotificationCount = 0;
|
||||
Notification? lastNotification;
|
||||
void OnNotificationReceived(Notification notification)
|
||||
{
|
||||
++receivedNotificationCount;
|
||||
lastNotification = notification;
|
||||
}
|
||||
|
||||
IEnumerator WaitForNotification(float timeout)
|
||||
{
|
||||
var startCount = receivedNotificationCount;
|
||||
float timePassed = 0;
|
||||
while (receivedNotificationCount == startCount && timePassed < timeout)
|
||||
{
|
||||
yield return null;
|
||||
timePassed += Time.deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer })]
|
||||
public IEnumerator SendNotificationAllOptionsRoundtrip()
|
||||
{
|
||||
var notification = new Notification()
|
||||
{
|
||||
Identifier = 15,
|
||||
Title = "Test",
|
||||
Text = "Testing",
|
||||
Data = "TestData",
|
||||
Badge = 2,
|
||||
};
|
||||
NotificationCenter.ScheduleNotification(notification, new NotificationIntervalSchedule(TimeSpan.FromSeconds(2)));
|
||||
|
||||
yield return new WaitForSeconds(0.5f); // test notification is trully delayed
|
||||
yield return WaitForNotification(60.0f);
|
||||
|
||||
Assert.AreEqual(1, receivedNotificationCount);
|
||||
Assert.IsTrue(lastNotification.HasValue);
|
||||
var n = lastNotification.Value;
|
||||
Assert.AreEqual(15, n.Identifier);
|
||||
Assert.AreEqual("Test", n.Title);
|
||||
Assert.AreEqual("Testing", n.Text);
|
||||
Assert.AreEqual("TestData", n.Data);
|
||||
Assert.AreEqual(2, n.Badge);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer })]
|
||||
public IEnumerator ScheduleNotificationAtSpecificTime()
|
||||
{
|
||||
var notification = new Notification()
|
||||
{
|
||||
Title = "AtTime",
|
||||
Text = "AtSpecificTime",
|
||||
};
|
||||
NotificationCenter.ScheduleNotification(notification, new NotificationDateTimeSchedule(DateTime.Now.AddSeconds(2)));
|
||||
|
||||
yield return new WaitForSeconds(0.5f); // test notification is trully delayed
|
||||
yield return WaitForNotification(60.0f);
|
||||
|
||||
Assert.AreEqual(1, receivedNotificationCount);
|
||||
Assert.IsTrue(lastNotification.HasValue);
|
||||
var n = lastNotification.Value;
|
||||
Assert.AreEqual("AtTime", n.Title);
|
||||
Assert.AreEqual("AtSpecificTime", n.Text);
|
||||
Assert.AreNotEqual(0, n.Identifier); // ID should be auto-generated
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer })]
|
||||
public IEnumerator ScheduleAndCancelNotification_DoesNotArrive()
|
||||
{
|
||||
var notification = new Notification()
|
||||
{
|
||||
Title = "Cancel",
|
||||
Text = "To be cancelled",
|
||||
};
|
||||
int id = NotificationCenter.ScheduleNotification(notification, new NotificationDateTimeSchedule(DateTime.Now.AddSeconds(3)));
|
||||
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
NotificationCenter.CancelScheduledNotification(id);
|
||||
yield return WaitForNotification(6.0f);
|
||||
|
||||
Assert.AreEqual(0, receivedNotificationCount);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(new[] { RuntimePlatform.Android })]
|
||||
public IEnumerator ScheduleNotification_WithExplicitCategory_UsesAndroidChannel()
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
const string category = "the_category";
|
||||
Unity.Notifications.Android.AndroidNotificationCenter.RegisterNotificationChannel(
|
||||
new Unity.Notifications.Android.AndroidNotificationChannel()
|
||||
{
|
||||
Id = category,
|
||||
Name = "Category",
|
||||
Description = "For category testing",
|
||||
Importance = Unity.Notifications.Android.Importance.Default,
|
||||
}
|
||||
);
|
||||
Unity.Notifications.Android.AndroidNotificationCenter.OnNotificationReceived += OnAndroidNotification;
|
||||
|
||||
yield return ScheduleNotification_WithExplicitCategory(category);
|
||||
|
||||
Unity.Notifications.Android.AndroidNotificationCenter.OnNotificationReceived -= OnAndroidNotification;
|
||||
|
||||
Assert.IsNotNull(lastAndroidNotification);
|
||||
Assert.AreEqual(category, lastAndroidNotification.Channel);
|
||||
#else
|
||||
yield break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID
|
||||
Unity.Notifications.Android.AndroidNotificationIntentData lastAndroidNotification;
|
||||
void OnAndroidNotification(Unity.Notifications.Android.AndroidNotificationIntentData intentData)
|
||||
{
|
||||
lastAndroidNotification = intentData;
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(new[] { RuntimePlatform.IPhonePlayer })]
|
||||
public IEnumerator ScheduleNotification_WithExplicitCategory_UsesiOSCategory()
|
||||
{
|
||||
#if UNITY_IOS
|
||||
const string category = "the_category";
|
||||
yield return ScheduleNotification_WithExplicitCategory(category);
|
||||
|
||||
var notification = (Unity.Notifications.iOS.iOSNotification)lastNotification.Value;
|
||||
Assert.AreEqual(category, notification.CategoryIdentifier);
|
||||
#else
|
||||
yield break;
|
||||
#endif
|
||||
}
|
||||
|
||||
public IEnumerator ScheduleNotification_WithExplicitCategory(string category)
|
||||
{
|
||||
var notification = new Notification()
|
||||
{
|
||||
Title = "With category",
|
||||
Text = "Sent to category",
|
||||
};
|
||||
NotificationCenter.ScheduleNotification(notification, category, new NotificationDateTimeSchedule(DateTime.Now.AddSeconds(3)));
|
||||
yield return WaitForNotification(60.0f);
|
||||
|
||||
Assert.AreEqual(1, receivedNotificationCount);
|
||||
Assert.IsTrue(lastNotification.HasValue);
|
||||
var n = lastNotification.Value;
|
||||
Assert.AreEqual("With category", n.Title);
|
||||
Assert.AreEqual("Sent to category", n.Text);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(new[] { RuntimePlatform.IPhonePlayer })]
|
||||
public IEnumerator ScheduleNotification_WithoutCategory_UsesNoiOSCategory()
|
||||
{
|
||||
var notification = new Notification()
|
||||
{
|
||||
Title = "Without category",
|
||||
Text = "Sent to no category",
|
||||
};
|
||||
NotificationCenter.ScheduleNotification(notification, new NotificationDateTimeSchedule(DateTime.Now.AddSeconds(3)));
|
||||
yield return WaitForNotification(60.0f);
|
||||
|
||||
Assert.AreEqual(1, receivedNotificationCount);
|
||||
Assert.IsTrue(lastNotification.HasValue);
|
||||
var n = lastNotification.Value;
|
||||
Assert.AreEqual("Without category", n.Title);
|
||||
Assert.AreEqual("Sent to no category", n.Text);
|
||||
|
||||
#if UNITY_IOS
|
||||
var iosNotification = (Unity.Notifications.iOS.iOSNotification)n;
|
||||
Assert.IsNull(iosNotification.CategoryIdentifier);
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer })]
|
||||
public IEnumerator ScheduleWithSameID_ReplacesNotification()
|
||||
{
|
||||
var notification = new Notification()
|
||||
{
|
||||
Identifier = 123,
|
||||
Title = "Replace",
|
||||
Text = "To be replaced",
|
||||
};
|
||||
NotificationCenter.ScheduleNotification(notification, new NotificationDateTimeSchedule(DateTime.Now.AddSeconds(2)));
|
||||
yield return null;
|
||||
|
||||
notification.Text = "Replacement text";
|
||||
NotificationCenter.ScheduleNotification(notification, new NotificationDateTimeSchedule(DateTime.Now.AddSeconds(3)));
|
||||
|
||||
yield return WaitForNotification(60.0f);
|
||||
yield return new WaitForSeconds(5); // wait a bit more in case the second notification does arrive
|
||||
|
||||
Assert.AreEqual(1, receivedNotificationCount);
|
||||
Assert.IsTrue(lastNotification.HasValue);
|
||||
var n = lastNotification.Value;
|
||||
Assert.AreEqual(123, n.Identifier.Value);
|
||||
Assert.AreEqual("Replace", n.Title);
|
||||
Assert.AreEqual("Replacement text", n.Text);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
[UnityPlatform(new[] { RuntimePlatform.Android, RuntimePlatform.IPhonePlayer })]
|
||||
public IEnumerator ScheduleWithoutIDTwice_DeliversTwo()
|
||||
{
|
||||
var notification = new Notification()
|
||||
{
|
||||
Title = "No replace",
|
||||
Text = "Not replaced",
|
||||
};
|
||||
var id1 = NotificationCenter.ScheduleNotification(notification, new NotificationDateTimeSchedule(DateTime.Now.AddSeconds(2)));
|
||||
yield return null;
|
||||
|
||||
var id2 = NotificationCenter.ScheduleNotification(notification, new NotificationDateTimeSchedule(DateTime.Now.AddSeconds(3)));
|
||||
|
||||
Assert.AreNotEqual(id1, id2);
|
||||
|
||||
yield return WaitForNotification(60.0f);
|
||||
// Both could be batched
|
||||
if (receivedNotificationCount < 2)
|
||||
yield return WaitForNotification(60.0f);
|
||||
|
||||
Assert.AreEqual(2, receivedNotificationCount);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df9756fcdfcd6480aa4dcc1daf2d78cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "Unity.Notifications.Unified.Tests",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Unity.Notifications.Android",
|
||||
"Unity.Notifications.iOS",
|
||||
"Unity.Notifications.Unified",
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"Unity.Notifications"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor",
|
||||
"Android",
|
||||
"iOS"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7cc401a5f39bf44dd915187717042be7
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user