diff --git a/OneSignalSDK/build.gradle b/OneSignalSDK/build.gradle index b41f3ee1db..41c95594f1 100644 --- a/OneSignalSDK/build.gradle +++ b/OneSignalSDK/build.gradle @@ -15,8 +15,8 @@ buildscript { huaweiHMSLocationVersion = '4.0.0.300' kotlinVersion = '1.7.10' kotestVersion = '5.5.0' - ktlintPluginVersion = '11.3.1' - ktlintVersion = '0.48.2' + ktlintPluginVersion = '11.6.1' + ktlintVersion = '1.0.1' junitVersion = '4.13.2' } diff --git a/OneSignalSDK/onesignal/core/build.gradle b/OneSignalSDK/onesignal/core/build.gradle index de1f6a60ff..50df86cd10 100644 --- a/OneSignalSDK/onesignal/core/build.gradle +++ b/OneSignalSDK/onesignal/core/build.gradle @@ -93,6 +93,9 @@ dependencies { ktlint { version = "$ktlintVersion" + additionalEditorconfig = [ + "max_line_length": "500", + ] } apply from: '../maven-push.gradle' \ No newline at end of file diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/Continue.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/Continue.kt index 0333793adf..9be203f2fc 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/Continue.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/Continue.kt @@ -11,18 +11,16 @@ import kotlin.coroutines.CoroutineContext * The result provided by [Continue.with] when the Java user wants to inspect the results * of a Kotlin coroutine completing. */ -class ContinueResult ( +class ContinueResult( /** * Whether the coroutine call was successful (`true`) or not (`false`) */ val isSuccess: Boolean, - /** * The data that is returned by the coroutine when complete. This will be `null` if [isSuccess] * is `false`. */ val data: R?, - /** * The throwable that was thrown by the coroutine. This will be `null` if [isSuccess] is `true`. */ @@ -47,7 +45,6 @@ class ContinueResult ( * ``` */ object Continue { - /** * Allows java code to provide a lambda as a continuation to a Kotlin coroutine. * @@ -62,7 +59,10 @@ object Continue { @RequiresApi(Build.VERSION_CODES.N) @JvmOverloads @JvmStatic - fun with(onFinished: Consumer>, context: CoroutineContext = Dispatchers.Main): Continuation { + fun with( + onFinished: Consumer>, + context: CoroutineContext = Dispatchers.Main, + ): Continuation { return object : Continuation { override val context: CoroutineContext get() = context diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/IOneSignal.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/IOneSignal.kt index 691fa919b2..cb707e4fe4 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/IOneSignal.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/IOneSignal.kt @@ -23,30 +23,30 @@ interface IOneSignal { * The user manager for accessing user-scoped * management. */ - val User: IUserManager + val user: IUserManager /** * The session manager for accessing session-scoped management. */ - val Session: ISessionManager + val session: ISessionManager /** * The notification manager for accessing device-scoped * notification management. */ - val Notifications: INotificationsManager + val notifications: INotificationsManager /** * The location manager for accessing device-scoped * location management. */ - val Location: ILocationManager + val location: ILocationManager /** * The In App Messaging manager for accessing device-scoped * IAP management. */ - val InAppMessages: IInAppMessagesManager + val inAppMessages: IInAppMessagesManager /** * Access to debug the SDK in the event additional information is required to diagnose any @@ -54,7 +54,7 @@ interface IOneSignal { * * WARNING: This should not be used in a production setting. */ - val Debug: IDebugManager + val debug: IDebugManager /** * Determines whether a user must consent to privacy prior @@ -83,11 +83,14 @@ interface IOneSignal { * * @return true if the SDK could be successfully initialized, false otherwise. */ - fun initWithContext(context: Context, appId: String?): Boolean + fun initWithContext( + context: Context, + appId: String?, + ): Boolean /** * Login to OneSignal under the user identified by the [externalId] provided. The act of - * logging a user into the OneSignal SDK will switch the [User] context to that specific user. + * logging a user into the OneSignal SDK will switch the [user] context to that specific user. * * * If the [externalId] exists the user will be retrieved and the context set from that * user information. If operations have already been performed under a guest user, they @@ -106,11 +109,15 @@ interface IOneSignal { * trust for the login operation. Required when identity verification has been enabled. See * [Identity Verification | OneSignal](https://documentation.onesignal.com/docs/identity-verification) */ - fun login(externalId: String, jwtBearerToken: String? = null) + fun login( + externalId: String, + jwtBearerToken: String? = null, + ) + fun login(externalId: String) = login(externalId, null) /** - * Logout the user previously logged in via [login]. The [User] property now references + * Logout the user previously logged in via [login]. The [user] property now references * a new device-scoped user. A device-scoped user has no user identity that can later * be retrieved, except through this device as long as the app remains installed and the app * data is not cleared. diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/OneSignal.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/OneSignal.kt index 431e0ce3e0..580cd63252 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/OneSignal.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/OneSignal.kt @@ -43,7 +43,7 @@ object OneSignal { */ @JvmStatic val User: IUserManager - get() = oneSignal.User + get() = oneSignal.user /** * The session manager for accessing session-scoped management. Initialized only after [initWithContext] @@ -51,7 +51,7 @@ object OneSignal { */ @JvmStatic val Session: ISessionManager - get() = oneSignal.Session + get() = oneSignal.session /** * The notification manager for accessing device-scoped notification management. Initialized @@ -59,7 +59,7 @@ object OneSignal { */ @JvmStatic val Notifications: INotificationsManager - get() = oneSignal.Notifications + get() = oneSignal.notifications /** * The location manager for accessing device-scoped location management. Initialized @@ -67,7 +67,7 @@ object OneSignal { */ @JvmStatic val Location: ILocationManager - get() = oneSignal.Location + get() = oneSignal.location /** * The In App Messaging manager for accessing device-scoped IAP management. Initialized @@ -75,7 +75,7 @@ object OneSignal { */ @JvmStatic val InAppMessages: IInAppMessagesManager - get() = oneSignal.InAppMessages + get() = oneSignal.inAppMessages /** * Access to debug the SDK in the additional information is required to diagnose any @@ -85,7 +85,7 @@ object OneSignal { */ @JvmStatic val Debug: IDebugManager - get() = oneSignal.Debug + get() = oneSignal.debug /** * Determines whether a user must consent to privacy prior @@ -96,7 +96,9 @@ object OneSignal { @JvmStatic var consentRequired: Boolean get() = oneSignal.consentRequired - set(value) { oneSignal.consentRequired = value } + set(value) { + oneSignal.consentRequired = value + } /** * Indicates whether privacy consent has been granted. This field is only relevant when @@ -105,7 +107,9 @@ object OneSignal { @JvmStatic var consentGiven: Boolean get() = oneSignal.consentGiven - set(value) { oneSignal.consentGiven = value } + set(value) { + oneSignal.consentGiven = value + } /** * Whether to disable the "GMS is missing" prompt to the user. @@ -113,7 +117,9 @@ object OneSignal { @JvmStatic var disableGMSMissingPrompt: Boolean get() = oneSignal.disableGMSMissingPrompt - set(value) { oneSignal.disableGMSMissingPrompt = value } + set(value) { + oneSignal.disableGMSMissingPrompt = value + } /** * Initialize the OneSignal SDK. This should be called during startup of the application. @@ -122,7 +128,10 @@ object OneSignal { * @param appId The application ID the OneSignal SDK is bound to. */ @JvmStatic - fun initWithContext(context: Context, appId: String) { + fun initWithContext( + context: Context, + appId: String, + ) { oneSignal.initWithContext(context, appId) } @@ -169,7 +178,10 @@ object OneSignal { * [Identity Verification | OneSignal](https://documentation.onesignal.com/docs/identity-verification) */ @JvmStatic - fun login(externalId: String, jwtBearerToken: String? = null) = oneSignal.login(externalId, jwtBearerToken) + fun login( + externalId: String, + jwtBearerToken: String? = null, + ) = oneSignal.login(externalId, jwtBearerToken) /** * Logout the user previously logged in via [login]. The [User] property now references diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/AndroidSupportV4Compat.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/AndroidSupportV4Compat.kt index b9aaad8f83..ac1159fad0 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/AndroidSupportV4Compat.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/AndroidSupportV4Compat.kt @@ -39,7 +39,10 @@ import android.util.Log // Designed as a compat for use of Android Support v4 revision 23.+ methods when an older revision of the library is included with the app developer's project. class AndroidSupportV4Compat { object ContextCompat { - fun checkSelfPermission(context: Context, permission: String): Int { + fun checkSelfPermission( + context: Context, + permission: String, + ): Int { // Catch for rare "Unknown exception code: 1 msg null" exception // See https://github.com/one-signal/OneSignal-Android-SDK/issues/48 for more details. return try { @@ -50,7 +53,10 @@ class AndroidSupportV4Compat { } } - fun getColor(context: Context, id: Int): Int { + fun getColor( + context: Context, + id: Int, + ): Int { return if (Build.VERSION.SDK_INT > 22) { context.getColor(id) } else { @@ -66,7 +72,11 @@ class AndroidSupportV4Compat { } internal object ActivityCompat { - fun requestPermissions(activity: Activity, permissions: Array, requestCode: Int) { + fun requestPermissions( + activity: Activity, + permissions: Array, + requestCode: Int, + ) { // OneSignal SDK code already checks that device is Android M, omit else code from the support library. ActivityCompatApi23.requestPermissions(activity, permissions, requestCode) } @@ -81,7 +91,11 @@ class AndroidSupportV4Compat { @TargetApi(23) internal object ActivityCompatApi23 { - fun requestPermissions(activity: Activity, permissions: Array?, requestCode: Int) { + fun requestPermissions( + activity: Activity, + permissions: Array?, + requestCode: Int, + ) { if (activity is RequestPermissionsRequestCodeValidator) { (activity as RequestPermissionsRequestCodeValidator).validateRequestPermissionsRequestCode( requestCode, diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/AndroidUtils.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/AndroidUtils.kt index ba52cab13a..6a827fadbd 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/AndroidUtils.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/AndroidUtils.kt @@ -20,7 +20,10 @@ import com.onesignal.debug.internal.logging.Logging import java.util.Random object AndroidUtils { - fun getRandomDelay(minDelay: Int, maxDelay: Int): Int { + fun getRandomDelay( + minDelay: Int, + maxDelay: Int, + ): Int { return Random().nextInt(maxDelay + 1 - minDelay) + minDelay } @@ -47,7 +50,10 @@ object AndroidUtils { } } - fun hasConfigChangeFlag(activity: Activity, configChangeFlag: Int): Boolean { + fun hasConfigChangeFlag( + activity: Activity, + configChangeFlag: Int, + ): Boolean { var hasFlag = false try { val configChanges = @@ -71,12 +77,18 @@ object AndroidUtils { return appVersion?.toString() } - fun getManifestMeta(context: Context, metaName: String?): String? { + fun getManifestMeta( + context: Context, + metaName: String?, + ): String? { val bundle = getManifestMetaBundle(context) return bundle?.getString(metaName) } - fun getManifestMetaBoolean(context: Context, metaName: String?): Boolean { + fun getManifestMetaBoolean( + context: Context, + metaName: String?, + ): Boolean { val bundle = getManifestMetaBundle(context) return bundle?.getBoolean(metaName) ?: false } @@ -84,10 +96,11 @@ object AndroidUtils { fun getManifestMetaBundle(context: Context): Bundle? { val ai: ApplicationInfo try { - ai = context.packageManager.getApplicationInfo( - context.packageName, - PackageManager.GET_META_DATA, - ) + ai = + context.packageManager.getApplicationInfo( + context.packageName, + PackageManager.GET_META_DATA, + ) return ai.metaData } catch (e: PackageManager.NameNotFoundException) { Logging.error("Manifest application info not found", e) @@ -95,7 +108,11 @@ object AndroidUtils { return null } - fun getResourceString(context: Context, key: String?, defaultStr: String?): String? { + fun getResourceString( + context: Context, + key: String?, + defaultStr: String?, + ): String? { val resources = context.resources val bodyResId = resources.getIdentifier(key, "string", context.packageName) return if (bodyResId != 0) resources.getString(bodyResId) else defaultStr @@ -160,11 +177,17 @@ object AndroidUtils { } } - fun openURLInBrowser(appContext: Context, url: String) { + fun openURLInBrowser( + appContext: Context, + url: String, + ) { openURLInBrowser(appContext, Uri.parse(url.trim { it <= ' ' })) } - fun openURLInBrowser(appContext: Context, uri: Uri) { + fun openURLInBrowser( + appContext: Context, + uri: Uri, + ) { val intent = openURLInBrowserIntent(uri) appContext.startActivity(intent) } @@ -204,14 +227,19 @@ object AndroidUtils { * * @return true if the permission is granted, false otherwise. */ - fun hasPermission(permission: String, isUserGranted: Boolean, applicationService: IApplicationService): Boolean { + fun hasPermission( + permission: String, + isUserGranted: Boolean, + applicationService: IApplicationService, + ): Boolean { try { - val packageInfo: PackageInfo = applicationService.appContext - .packageManager - .getPackageInfo( - applicationService.appContext.packageName, - PackageManager.GET_PERMISSIONS, - ) + val packageInfo: PackageInfo = + applicationService.appContext + .packageManager + .getPackageInfo( + applicationService.appContext.packageName, + PackageManager.GET_PERMISSIONS, + ) val permissionList = listOf(*packageInfo.requestedPermissions) return if (!permissionList.contains(permission)) { @@ -219,10 +247,11 @@ object AndroidUtils { } else if (!isUserGranted) { true } else { - val permissionGrant = AndroidSupportV4Compat.ContextCompat.checkSelfPermission( - applicationService.appContext, - permission, - ) + val permissionGrant = + AndroidSupportV4Compat.ContextCompat.checkSelfPermission( + applicationService.appContext, + permission, + ) permissionGrant != PackageManager.PERMISSION_DENIED } } catch (e: PackageManager.NameNotFoundException) { @@ -239,11 +268,15 @@ object AndroidUtils { * * @return The list of permissions within [permissions] that are granted. */ - fun filterManifestPermissions(permissions: List, applicationService: IApplicationService): List { + fun filterManifestPermissions( + permissions: List, + applicationService: IApplicationService, + ): List { var requestPermission: String? = null - val packageInfo: PackageInfo = applicationService.appContext - .packageManager - .getPackageInfo(applicationService.appContext.packageName, PackageManager.GET_PERMISSIONS) + val packageInfo: PackageInfo = + applicationService.appContext + .packageManager + .getPackageInfo(applicationService.appContext.packageName, PackageManager.GET_PERMISSIONS) val permissionList = listOf(*packageInfo.requestedPermissions) return permissions.filter { permissionList.contains(it) } @@ -262,7 +295,10 @@ object AndroidUtils { } enum class SchemaType(private val text: String) { - DATA("data"), HTTPS("https"), HTTP("http"); + DATA("data"), + HTTPS("https"), + HTTP("http"), + ; companion object { fun fromString(text: String?): SchemaType? { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/JSONObjectExtensions.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/JSONObjectExtensions.kt index 89ad550d6e..06ae8dcce4 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/JSONObjectExtensions.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/JSONObjectExtensions.kt @@ -113,13 +113,19 @@ fun JSONObject.toMap(): Map { * @param into The lambda method that will be executed to explore the [JSONObject] value, if the * attribute exists. */ -fun JSONObject.expandJSONObject(name: String, into: (childObject: JSONObject) -> Unit) { +fun JSONObject.expandJSONObject( + name: String, + into: (childObject: JSONObject) -> Unit, +) { if (this.has(name)) { into(this.getJSONObject(name)) } } -fun JSONObject.expandJSONArray(name: String, into: (childObject: JSONObject) -> T?): List { +fun JSONObject.expandJSONArray( + name: String, + into: (childObject: JSONObject) -> T?, +): List { val listToRet = mutableListOf() if (this.has(name)) { val jsonArray = this.getJSONArray(name) @@ -158,7 +164,10 @@ fun JSONObject.putMap(map: Map): JSONObject { * * @return The [JSONObject] itself, to allow for chaining. */ -fun JSONObject.putMap(name: String, map: Map?): JSONObject { +fun JSONObject.putMap( + name: String, + map: Map?, +): JSONObject { if (map != null) { this.putJSONObject(name) { it.putMap(map) @@ -177,7 +186,10 @@ fun JSONObject.putMap(name: String, map: Map?): JSONObject { * * @return The [JSONObject] itself, to allow for chaining. */ -fun JSONObject.putJSONObject(name: String, expand: (item: JSONObject) -> Unit): JSONObject { +fun JSONObject.putJSONObject( + name: String, + expand: (item: JSONObject) -> Unit, +): JSONObject { val childJSONObject = JSONObject() expand(childJSONObject) @@ -194,7 +206,11 @@ fun JSONObject.putJSONObject(name: String, expand: (item: JSONObject) -> Unit): * @param list: The list of items that will be converted into the [JSONArray]. * @param create: The lambda that will be called for each item in [list], expecting a [JSONObject] to be added to the array. */ -fun JSONObject.putJSONArray(name: String, list: List?, create: (item: T) -> JSONObject?): JSONObject { +fun JSONObject.putJSONArray( + name: String, + list: List?, + create: (item: T) -> JSONObject?, +): JSONObject { if (list != null) { val jsonArray = JSONArray() list.forEach { @@ -218,7 +234,10 @@ fun JSONObject.putJSONArray(name: String, list: List?, create: (item: T) * * @return The [JSONObject] itself, to allow for chaining. */ -fun JSONObject.putSafe(name: String, value: Any?): JSONObject { +fun JSONObject.putSafe( + name: String, + value: Any?, +): JSONObject { if (value != null) { this.put(name, value) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/JSONUtils.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/JSONUtils.kt index ae6acd59dd..75ba75db7c 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/JSONUtils.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/JSONUtils.kt @@ -109,7 +109,10 @@ object JSONUtils { /** * Compare two JSONArrays too determine if they are equal or not */ - fun compareJSONArrays(jsonArray1: JSONArray?, jsonArray2: JSONArray?): Boolean { + fun compareJSONArrays( + jsonArray1: JSONArray?, + jsonArray2: JSONArray?, + ): Boolean { // If both JSONArrays are null, they are equal if (jsonArray1 == null && jsonArray2 == null) return true diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/NetworkUtils.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/NetworkUtils.kt index 4d598acc2b..9d1b3b7a83 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/NetworkUtils.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/NetworkUtils.kt @@ -9,7 +9,7 @@ object NetworkUtils { CONFLICT, } - var MAX_NETWORK_REQUEST_ATTEMPT_COUNT = 3 + var maxNetworkRequestAttemptCount = 3 fun getResponseStatusType(statusCode: Int): ResponseStatusType { return when (statusCode) { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/OneSignalUtils.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/OneSignalUtils.kt index 9880cb8510..b87b3a885f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/OneSignalUtils.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/OneSignalUtils.kt @@ -6,7 +6,7 @@ object OneSignalUtils { /** * The version of this SDK. */ - const val sdkVersion: String = "050003" + const val SDK_VERSION: String = "050003" fun isValidEmail(email: String): Boolean { if (email.isEmpty()) { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/RootToolsInternalMethods.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/RootToolsInternalMethods.kt index 8713b0f871..7df42446fd 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/RootToolsInternalMethods.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/RootToolsInternalMethods.kt @@ -1,3 +1,5 @@ +// Namespaced in com.onesignal to prevent class name conflicts if app developer includes the full RootTools library. + /** * This file is part of the RootTools Project: http://code.google.com/p/roottools/ * @@ -19,7 +21,7 @@ * See each License for the specific language governing permissions and * limitations under that License. */ -// Namespaced in com.onesignal to prevent class name conflicts if app developer includes the full RootTools library. + package com.onesignal.common import java.io.File @@ -29,16 +31,17 @@ object RootToolsInternalMethods { // issues #857 val isRooted: Boolean get() { - val places = arrayOf( - "/sbin/", - "/system/bin/", - "/system/xbin/", - "/data/local/xbin/", - "/data/local/bin/", - "/system/sd/xbin/", - "/system/bin/failsafe/", - "/data/local/", - ) + val places = + arrayOf( + "/sbin/", + "/system/bin/", + "/system/xbin/", + "/data/local/xbin/", + "/data/local/bin/", + "/system/sd/xbin/", + "/system/bin/failsafe/", + "/data/local/", + ) try { for (where in places) { if (File(where + "su").exists()) return true diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/events/CallbackProducer.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/events/CallbackProducer.kt index dbd7a702d5..79dea48a3c 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/events/CallbackProducer.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/events/CallbackProducer.kt @@ -9,14 +9,13 @@ import kotlinx.coroutines.withContext * make callbacks less burdensome to the user. */ open class CallbackProducer() : ICallbackNotifier { - - private var _callback: THandler? = null + private var callback: THandler? = null override val hasCallback: Boolean - get() = _callback != null + get() = callback != null override fun set(handler: THandler?) { - _callback = handler + callback = handler } /** @@ -27,8 +26,8 @@ open class CallbackProducer() : ICallbackNotifier { * @param callback The callback will be invoked if one exists, allowing you to call the handler. */ fun fire(callback: (THandler) -> Unit) { - if (_callback != null) { - callback(_callback!!) + if (this.callback != null) { + callback(this.callback!!) } } @@ -43,8 +42,8 @@ open class CallbackProducer() : ICallbackNotifier { */ fun fireOnMain(callback: (THandler) -> Unit) { suspendifyOnMain { - if (_callback != null) { - callback(_callback!!) + if (this.callback != null) { + callback(this.callback!!) } } } @@ -57,8 +56,8 @@ open class CallbackProducer() : ICallbackNotifier { * @param callback The callback will be invoked if one exists, allowing you to call the handler. */ suspend fun suspendingFire(callback: suspend (THandler) -> Unit) { - if (_callback != null) { - callback(_callback!!) + if (this.callback != null) { + callback(this.callback!!) } } @@ -71,9 +70,9 @@ open class CallbackProducer() : ICallbackNotifier { * @param callback The callback will be invoked if one exists, allowing you to call the handler. */ suspend fun suspendingFireOnMain(callback: suspend (THandler) -> Unit) { - if (_callback != null) { + if (this.callback != null) { withContext(Dispatchers.Main) { - callback(_callback!!) + callback(this@CallbackProducer.callback!!) } } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/events/EventProducer.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/events/EventProducer.kt index 7311cf7ff7..ae49ecf512 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/events/EventProducer.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/events/EventProducer.kt @@ -3,32 +3,31 @@ package com.onesignal.common.events import com.onesignal.common.threading.suspendifyOnMain import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.util.* +import java.util.Collections /** * A standard implementation that implements [IEventNotifier] and additional functionality to make * event firing less burdensome to the user. */ open class EventProducer : IEventNotifier { - override val hasSubscribers: Boolean - get() = _subscribers.any() + get() = subscribers.any() - private val _subscribers: MutableList = Collections.synchronizedList(mutableListOf()) + private val subscribers: MutableList = Collections.synchronizedList(mutableListOf()) override fun subscribe(handler: THandler) { - _subscribers.add(handler) + subscribers.add(handler) } override fun unsubscribe(handler: THandler) { - _subscribers.remove(handler) + subscribers.remove(handler) } /** * Subscribe all from an existing producer to this subscriber. */ fun subscribeAll(from: EventProducer) { - for (s in from._subscribers) { + for (s in from.subscribers) { subscribe(s) } } @@ -40,7 +39,7 @@ open class EventProducer : IEventNotifier { * @param callback The callback will be invoked for each subscribed handler, allowing you to call the handler. */ fun fire(callback: (THandler) -> Unit) { - for (s in _subscribers) { + for (s in subscribers) { callback(s) } } @@ -54,7 +53,7 @@ open class EventProducer : IEventNotifier { */ fun fireOnMain(callback: (THandler) -> Unit) { suspendifyOnMain { - for (s in _subscribers) { + for (s in subscribers) { callback(s) } } @@ -67,7 +66,7 @@ open class EventProducer : IEventNotifier { * @param callback The callback will be invoked for each subscribed handler, allowing you to call the handler. */ suspend fun suspendingFire(callback: suspend (THandler) -> Unit) { - for (s in _subscribers) { + for (s in subscribers) { callback(s) } } @@ -80,7 +79,7 @@ open class EventProducer : IEventNotifier { */ suspend fun suspendingFireOnMain(callback: suspend (THandler) -> Unit) { withContext(Dispatchers.Main) { - for (s in _subscribers) { + for (s in subscribers) { callback(s) } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/exceptions/BackendException.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/exceptions/BackendException.kt index 1c29ae5fad..fd0faeff3e 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/exceptions/BackendException.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/exceptions/BackendException.kt @@ -8,7 +8,6 @@ class BackendException( * The status code of the response. */ val statusCode: Int, - /** * The response, if one exists. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelChangedHandler.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelChangedHandler.kt index 3c21908fec..ba526dc4ad 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelChangedHandler.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelChangedHandler.kt @@ -5,14 +5,16 @@ package com.onesignal.common.modeling * be notified when the [Model] has changed. */ interface IModelChangedHandler { - /** * Called when the subscribed model has been changed. * * @param args Information related to what has changed. * @param tag The tag which identifies how/why the model was changed. */ - fun onChanged(args: ModelChangedArgs, tag: String) + fun onChanged( + args: ModelChangedArgs, + tag: String, + ) } /** @@ -23,7 +25,6 @@ class ModelChangedArgs( * The full model in its current state. */ val model: Model, - /** * The path to the property, from the root [Model], that has changed. When the root model has * changed, [path] and [property] will be identical. When it's a nested property that @@ -35,17 +36,14 @@ class ModelChangedArgs( * */ val path: String, - /** * The property that was changed. */ val property: String, - /** * The old value of the property, prior to it being changed. */ val oldValue: Any?, - /** * The new value of the property, after it has been changed. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelStore.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelStore.kt index 28d7428567..7a9e5c6afd 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelStore.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelStore.kt @@ -9,7 +9,6 @@ import org.json.JSONObject */ interface IModelStore : IEventNotifier> where TModel : Model { - /** * Create a new instance of the model and add it to the store. The new instance is *not* added * to the model store, because it may not yet have an [Model.id] which is required. @@ -34,7 +33,10 @@ interface IModelStore : * @param model The model being added to the model store. * @param tag The tag which identifies how/why the model is being added. */ - fun add(model: TModel, tag: String = ModelChangeTags.NORMAL) + fun add( + model: TModel, + tag: String = ModelChangeTags.NORMAL, + ) /** * Add a new model to this model store. Once added, any changes to the @@ -46,7 +48,11 @@ interface IModelStore : * @param model The model being added to the model store. * @param tag The tag which identifies how/why the model is being added. */ - fun add(index: Int, model: TModel, tag: String = ModelChangeTags.NORMAL) + fun add( + index: Int, + model: TModel, + tag: String = ModelChangeTags.NORMAL, + ) /** * Retrieve the model associated to the id provided. @@ -63,7 +69,10 @@ interface IModelStore : * @param id The unique identifier to the model to remove. * @param tag The tag which identifies how/why the model is being removed. */ - fun remove(id: String, tag: String = ModelChangeTags.NORMAL) + fun remove( + id: String, + tag: String = ModelChangeTags.NORMAL, + ) /** * Remove all models from the store. @@ -78,7 +87,10 @@ interface IModelStore : * @param models The models to track in the model store. * @param tag The tag which identifies how/why the model store is being replaced. */ - fun replaceAll(models: List, tag: String = ModelChangeTags.NORMAL) + fun replaceAll( + models: List, + tag: String = ModelChangeTags.NORMAL, + ) } object ModelChangeTags { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelStoreChangeHandler.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelStoreChangeHandler.kt index d59f06e3bf..a212e4dd75 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelStoreChangeHandler.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/IModelStoreChangeHandler.kt @@ -11,7 +11,10 @@ interface IModelStoreChangeHandler where TModel : Model { * @param model The model that has been added. * @param tag The tag which identifies how/why the model was added. */ - fun onModelAdded(model: TModel, tag: String) + fun onModelAdded( + model: TModel, + tag: String, + ) /** * Called when a model has been updated. This callback wraps [IModelChangedHandler.onChanged] @@ -21,7 +24,10 @@ interface IModelStoreChangeHandler where TModel : Model { * @param args The model changed arguments. * @param tag The tag which identifies how/why the model was updated. */ - fun onModelUpdated(args: ModelChangedArgs, tag: String) + fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) /** * Called when a model has been removed from the model store. @@ -29,5 +35,8 @@ interface IModelStoreChangeHandler where TModel : Model { * @param model The model that has been removed. * @param tag The tag which identifies how/why the model was removed. */ - fun onModelRemoved(model: TModel, tag: String) + fun onModelRemoved( + model: TModel, + tag: String, + ) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ISingletonModelStore.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ISingletonModelStore.kt index 3592cb6743..5740a34906 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ISingletonModelStore.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ISingletonModelStore.kt @@ -20,5 +20,8 @@ interface ISingletonModelStore : * @param model A model that contains all the data for the new effective model. * @param tag The tag which identifies how/why the model is being replaced. */ - fun replace(model: TModel, tag: String = ModelChangeTags.NORMAL) + fun replace( + model: TModel, + tag: String = ModelChangeTags.NORMAL, + ) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ISingletonModelStoreChangeHandler.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ISingletonModelStoreChangeHandler.kt index b0fcaf7215..c929fe8ff9 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ISingletonModelStoreChangeHandler.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ISingletonModelStoreChangeHandler.kt @@ -5,14 +5,16 @@ package com.onesignal.common.modeling * to model change events for a specific model store. */ interface ISingletonModelStoreChangeHandler where TModel : Model { - /** * Called when the model has been replaced. * * @param model The model * @param tag The tag which identifies how/why the model was replaced. */ - fun onModelReplaced(model: TModel, tag: String) + fun onModelReplaced( + model: TModel, + tag: String, + ) /** * Called when a property within the model has been updated. This callback wraps [IModelChangedHandler.onChanged] @@ -22,5 +24,8 @@ interface ISingletonModelStoreChangeHandler where TModel : Model { * @param args The model changed arguments. * @param tag The tag which identifies how/why the model was updated. */ - fun onModelUpdated(args: ModelChangedArgs, tag: String) + fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/MapModel.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/MapModel.kt index dd88b94865..e9ae7d2d56 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/MapModel.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/MapModel.kt @@ -9,7 +9,6 @@ open class MapModel( parentModel: Model? = null, parentProperty: String? = null, ) : Model(parentModel, parentProperty), MutableMap { - override val size: Int get() = data.size @@ -43,7 +42,10 @@ open class MapModel( setOptAnyProperty(property, null) } - override fun put(key: String, value: V): V { + override fun put( + key: String, + value: V, + ): V { setOptAnyProperty(key, value) return value } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/Model.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/Model.kt index 9b4e245727..8542acb133 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/Model.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/Model.kt @@ -5,7 +5,7 @@ import com.onesignal.common.events.IEventNotifier import org.json.JSONArray import org.json.JSONObject import java.math.BigDecimal -import java.util.* +import java.util.Collections /** * The base class for a [Model]. A model is effectively a map of data, each key in the map being @@ -46,24 +46,23 @@ open class Model( * this is specified, must also specify [_parentProperty] */ private var _parentModel: Model? = null, - /** * The optional parent model property that references this model. When this is * specified, must also specify [_parentModel] */ private val _parentProperty: String? = null, - ) : IEventNotifier { - /** * A unique identifier for this model. */ var id: String get() = getStringProperty(::id.name) - set(value) { setStringProperty(::id.name, value) } + set(value) { + setStringProperty(::id.name, value) + } protected val data: MutableMap = Collections.synchronizedMap(mutableMapOf()) - private val _changeNotifier = EventProducer() + private val changeNotifier = EventProducer() init { if (_parentModel != null && _parentProperty == null) { @@ -119,7 +118,10 @@ open class Model( * @param id The id of the model to initialze to. * @param model The model to initialize this model from. */ - fun initializeFromModel(id: String?, model: Model) { + fun initializeFromModel( + id: String?, + model: Model, + ) { data.clear() for (item in model.data) { if (item.value is Model) { @@ -147,7 +149,10 @@ open class Model( * * @return The created [Model], or null if the property should not be set. */ - protected open fun createModelForProperty(property: String, jsonObject: JSONObject): Model? = null + protected open fun createModelForProperty( + property: String, + jsonObject: JSONObject, + ): Model? = null /** * Called via [initializeFromJson] when the property being initialized is a [JSONArray], @@ -160,32 +165,269 @@ open class Model( * * @return The created [List], or null if the property should not be set. */ - protected open fun createListForProperty(property: String, jsonArray: JSONArray): List<*>? = null - - inline fun > setEnumProperty(name: String, value: T, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptEnumProperty(name, value, tag, forceChange) - fun setMapModelProperty(name: String, value: MapModel, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptMapModelProperty(name, value, tag, forceChange) - fun setListProperty(name: String, value: List, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptListProperty(name, value, tag, forceChange) - fun setStringProperty(name: String, value: String, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptStringProperty(name, value, tag, forceChange) - fun setBooleanProperty(name: String, value: Boolean, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptBooleanProperty(name, value, tag, forceChange) - fun setLongProperty(name: String, value: Long, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptLongProperty(name, value, tag, forceChange) - fun setDoubleProperty(name: String, value: Double, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptDoubleProperty(name, value, tag, forceChange) - fun setFloatProperty(name: String, value: Float, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptFloatProperty(name, value, tag, forceChange) - fun setIntProperty(name: String, value: Int, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptIntProperty(name, value, tag, forceChange) - fun setBigDecimalProperty(name: String, value: BigDecimal, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptBigDecimalProperty(name, value, tag, forceChange) - fun setAnyProperty(name: String, value: Any, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value, tag, forceChange) - - inline fun > setOptEnumProperty(name: String, value: T?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value?.toString(), tag, forceChange) - fun setOptMapModelProperty(name: String, value: MapModel?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value, tag, forceChange) - fun setOptListProperty(name: String, value: List?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value, tag, forceChange) - fun setOptStringProperty(name: String, value: String?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value, tag, forceChange) - fun setOptBooleanProperty(name: String, value: Boolean?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value, tag, forceChange) - fun setOptLongProperty(name: String, value: Long?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value, tag, forceChange) - fun setOptDoubleProperty(name: String, value: Double?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value, tag, forceChange) - fun setOptFloatProperty(name: String, value: Float?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value, tag, forceChange) - fun setOptIntProperty(name: String, value: Int?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value, tag, forceChange) - fun setOptBigDecimalProperty(name: String, value: BigDecimal?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) = setOptAnyProperty(name, value?.toString(), tag, forceChange) - - fun setOptAnyProperty(name: String, value: Any?, tag: String = ModelChangeTags.NORMAL, forceChange: Boolean = false) { + protected open fun createListForProperty( + property: String, + jsonArray: JSONArray, + ): List<*>? = null + + inline fun > setEnumProperty( + name: String, + value: T, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptEnumProperty( + name, + value, + tag, + forceChange, + ) + + fun setMapModelProperty( + name: String, + value: MapModel, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptMapModelProperty( + name, + value, + tag, + forceChange, + ) + + fun setListProperty( + name: String, + value: List, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptListProperty( + name, + value, + tag, + forceChange, + ) + + fun setStringProperty( + name: String, + value: String, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptStringProperty( + name, + value, + tag, + forceChange, + ) + + fun setBooleanProperty( + name: String, + value: Boolean, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptBooleanProperty( + name, + value, + tag, + forceChange, + ) + + fun setLongProperty( + name: String, + value: Long, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptLongProperty( + name, + value, + tag, + forceChange, + ) + + fun setDoubleProperty( + name: String, + value: Double, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptDoubleProperty( + name, + value, + tag, + forceChange, + ) + + fun setFloatProperty( + name: String, + value: Float, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptFloatProperty( + name, + value, + tag, + forceChange, + ) + + fun setIntProperty( + name: String, + value: Int, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptIntProperty( + name, + value, + tag, + forceChange, + ) + + fun setBigDecimalProperty( + name: String, + value: BigDecimal, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptBigDecimalProperty( + name, + value, + tag, + forceChange, + ) + + fun setAnyProperty( + name: String, + value: Any, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value, + tag, + forceChange, + ) + + inline fun > setOptEnumProperty( + name: String, + value: T?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value?.toString(), + tag, + forceChange, + ) + + fun setOptMapModelProperty( + name: String, + value: MapModel?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value, + tag, + forceChange, + ) + + fun setOptListProperty( + name: String, + value: List?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value, + tag, + forceChange, + ) + + fun setOptStringProperty( + name: String, + value: String?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value, + tag, + forceChange, + ) + + fun setOptBooleanProperty( + name: String, + value: Boolean?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value, + tag, + forceChange, + ) + + fun setOptLongProperty( + name: String, + value: Long?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value, + tag, + forceChange, + ) + + fun setOptDoubleProperty( + name: String, + value: Double?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value, + tag, + forceChange, + ) + + fun setOptFloatProperty( + name: String, + value: Float?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value, + tag, + forceChange, + ) + + fun setOptIntProperty( + name: String, + value: Int?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value, + tag, + forceChange, + ) + + fun setOptBigDecimalProperty( + name: String, + value: BigDecimal?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) = setOptAnyProperty( + name, + value?.toString(), + tag, + forceChange, + ) + + fun setOptAnyProperty( + name: String, + value: Any?, + tag: String = ModelChangeTags.NORMAL, + forceChange: Boolean = false, + ) { val oldValue = data[name] if (oldValue == value && !forceChange) { @@ -211,16 +453,68 @@ open class Model( fun hasProperty(name: String): Boolean = data.containsKey(name) protected inline fun > getEnumProperty(name: String): T = getOptEnumProperty(name) as T - protected fun getMapModelProperty(name: String, create: (() -> MapModel)? = null): MapModel = getOptMapModelProperty(name, create) as MapModel - protected fun getListProperty(name: String, create: (() -> List)? = null): List = getOptListProperty(name, create) as List - protected fun getStringProperty(name: String, create: (() -> String)? = null): String = getOptStringProperty(name, create) as String - protected fun getBooleanProperty(name: String, create: (() -> Boolean)? = null): Boolean = getOptBooleanProperty(name, create) as Boolean - protected fun getLongProperty(name: String, create: (() -> Long)? = null): Long = getOptLongProperty(name, create) as Long - protected fun getDoubleProperty(name: String, create: (() -> Double)? = null): Double = getOptDoubleProperty(name, create) as Double - protected fun getFloatProperty(name: String, create: (() -> Float)? = null): Float = getOptFloatProperty(name, create) as Float - protected fun getIntProperty(name: String, create: (() -> Int)? = null): Int = getOptIntProperty(name, create) as Int - protected fun getBigDecimalProperty(name: String, create: (() -> BigDecimal)? = null): BigDecimal = getOptBigDecimalProperty(name, create) as BigDecimal - protected fun getAnyProperty(name: String, create: (() -> Any)? = null): Any = getOptAnyProperty(name, create) as Any + + protected fun getMapModelProperty( + name: String, + create: (() -> MapModel)? = null, + ): MapModel = + getOptMapModelProperty( + name, + create, + ) as MapModel + + protected fun getListProperty( + name: String, + create: (() -> List)? = null, + ): List = getOptListProperty(name, create) as List + + protected fun getStringProperty( + name: String, + create: (() -> String)? = null, + ): String = getOptStringProperty(name, create) as String + + protected fun getBooleanProperty( + name: String, + create: (() -> Boolean)? = null, + ): Boolean = + getOptBooleanProperty( + name, + create, + ) as Boolean + + protected fun getLongProperty( + name: String, + create: (() -> Long)? = null, + ): Long = getOptLongProperty(name, create) as Long + + protected fun getDoubleProperty( + name: String, + create: (() -> Double)? = null, + ): Double = getOptDoubleProperty(name, create) as Double + + protected fun getFloatProperty( + name: String, + create: (() -> Float)? = null, + ): Float = getOptFloatProperty(name, create) as Float + + protected fun getIntProperty( + name: String, + create: (() -> Int)? = null, + ): Int = getOptIntProperty(name, create) as Int + + protected fun getBigDecimalProperty( + name: String, + create: (() -> BigDecimal)? = null, + ): BigDecimal = + getOptBigDecimalProperty( + name, + create, + ) as BigDecimal + + protected fun getAnyProperty( + name: String, + create: (() -> Any)? = null, + ): Any = getOptAnyProperty(name, create) as Any protected inline fun > getOptEnumProperty(name: String): T? { val value = getOptAnyProperty(name) ?: return null @@ -230,11 +524,42 @@ open class Model( return value as T } - protected fun getOptMapModelProperty(name: String, create: (() -> MapModel?)? = null): MapModel? = getOptAnyProperty(name, create) as MapModel? - protected fun getOptListProperty(name: String, create: (() -> List?)? = null): List? = getOptAnyProperty(name, create) as List? - protected fun getOptStringProperty(name: String, create: (() -> String?)? = null): String? = getOptAnyProperty(name, create) as String? - protected fun getOptBooleanProperty(name: String, create: (() -> Boolean?)? = null): Boolean? = getOptAnyProperty(name, create) as Boolean? - protected fun getOptLongProperty(name: String, create: (() -> Long?)? = null): Long? { + protected fun getOptMapModelProperty( + name: String, + create: (() -> MapModel?)? = null, + ): MapModel? = + getOptAnyProperty( + name, + create, + ) as MapModel? + + protected fun getOptListProperty( + name: String, + create: (() -> List?)? = null, + ): List? = + getOptAnyProperty( + name, + create, + ) as List? + + protected fun getOptStringProperty( + name: String, + create: (() -> String?)? = null, + ): String? = getOptAnyProperty(name, create) as String? + + protected fun getOptBooleanProperty( + name: String, + create: (() -> Boolean?)? = null, + ): Boolean? = + getOptAnyProperty( + name, + create, + ) as Boolean? + + protected fun getOptLongProperty( + name: String, + create: (() -> Long?)? = null, + ): Long? { val value = getOptAnyProperty(name, create) ?: return null if (value is Long) return value @@ -243,7 +568,11 @@ open class Model( if (value is Double) return value.toLong() return value as Long? } - protected fun getOptFloatProperty(name: String, create: (() -> Float?)? = null): Float? { + + protected fun getOptFloatProperty( + name: String, + create: (() -> Float?)? = null, + ): Float? { val value = getOptAnyProperty(name, create) ?: return null if (value is Float) return value @@ -252,7 +581,11 @@ open class Model( if (value is Long) return value.toFloat() return value as Float? } - protected fun getOptDoubleProperty(name: String, create: (() -> Double?)? = null): Double? { + + protected fun getOptDoubleProperty( + name: String, + create: (() -> Double?)? = null, + ): Double? { val value = getOptAnyProperty(name, create) ?: return null if (value is Double) return value @@ -261,7 +594,11 @@ open class Model( if (value is Long) return value.toDouble() return value as Double? } - protected fun getOptIntProperty(name: String, create: (() -> Int?)? = null): Int? { + + protected fun getOptIntProperty( + name: String, + create: (() -> Int?)? = null, + ): Int? { val value = getOptAnyProperty(name, create) ?: return null if (value is Int) return value @@ -270,7 +607,11 @@ open class Model( if (value is Double) return value.toInt() return value as Int? } - protected fun getOptBigDecimalProperty(name: String, create: (() -> BigDecimal?)? = null): BigDecimal? { + + protected fun getOptBigDecimalProperty( + name: String, + create: (() -> BigDecimal?)? = null, + ): BigDecimal? { val value = getOptAnyProperty(name, create) ?: return null if (value is Int) return BigDecimal(value) @@ -280,7 +621,11 @@ open class Model( if (value is String) return BigDecimal(value) return value as BigDecimal? } - protected fun getOptAnyProperty(name: String, create: (() -> Any?)? = null): Any? { + + protected fun getOptAnyProperty( + name: String, + create: (() -> Any?)? = null, + ): Any? { return if (data.containsKey(name) || create == null) { data[name] } else { @@ -290,10 +635,16 @@ open class Model( } } - private fun notifyChanged(path: String, property: String, tag: String, oldValue: Any?, newValue: Any?) { + private fun notifyChanged( + path: String, + property: String, + tag: String, + oldValue: Any?, + newValue: Any?, + ) { // if there are any changed listeners for this specific model, notify them. val changeArgs = ModelChangedArgs(this, path, property, oldValue, newValue) - _changeNotifier.fire { it.onChanged(changeArgs, tag) } + changeNotifier.fire { it.onChanged(changeArgs, tag) } // if there is a parent model, propagate the change up to the parent for it's own processing. if (_parentModel != null) { @@ -333,8 +684,10 @@ open class Model( return jsonObject } - override fun subscribe(handler: IModelChangedHandler) = _changeNotifier.subscribe(handler) - override fun unsubscribe(handler: IModelChangedHandler) = _changeNotifier.unsubscribe(handler) + override fun subscribe(handler: IModelChangedHandler) = changeNotifier.subscribe(handler) + + override fun unsubscribe(handler: IModelChangedHandler) = changeNotifier.unsubscribe(handler) + override val hasSubscribers: Boolean - get() = _changeNotifier.hasSubscribers + get() = changeNotifier.hasSubscribers } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ModelStore.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ModelStore.kt index 185b60415d..314054fe18 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ModelStore.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/ModelStore.kt @@ -33,12 +33,14 @@ abstract class ModelStore( ) : IEventNotifier>, IModelStore, IModelChangedHandler where TModel : Model { - - private val _changeSubscription: EventProducer> = EventProducer() - private val _models: MutableList = mutableListOf() - - override fun add(model: TModel, tag: String) { - val oldModel = _models.firstOrNull { it.id == model.id } + private val changeSubscription: EventProducer> = EventProducer() + private val models: MutableList = mutableListOf() + + override fun add( + model: TModel, + tag: String, + ) { + val oldModel = models.firstOrNull { it.id == model.id } if (oldModel != null) { removeItem(oldModel, tag) } @@ -46,8 +48,12 @@ abstract class ModelStore( addItem(model, tag) } - override fun add(index: Int, model: TModel, tag: String) { - val oldModel = _models.firstOrNull { it.id == model.id } + override fun add( + index: Int, + model: TModel, + tag: String, + ) { + val oldModel = models.firstOrNull { it.id == model.id } if (oldModel != null) { removeItem(oldModel, tag) } @@ -56,25 +62,34 @@ abstract class ModelStore( } override fun list(): Collection { - return _models + return models } override fun get(id: String): TModel? { - return _models.firstOrNull { it.id == id } + return models.firstOrNull { it.id == id } } - override fun remove(id: String, tag: String) { - val model = _models.firstOrNull { it.id == id } ?: return + override fun remove( + id: String, + tag: String, + ) { + val model = models.firstOrNull { it.id == id } ?: return removeItem(model, tag) } - override fun onChanged(args: ModelChangedArgs, tag: String) { + override fun onChanged( + args: ModelChangedArgs, + tag: String, + ) { persist() - _changeSubscription.fire { it.onModelUpdated(args, tag) } + changeSubscription.fire { it.onModelUpdated(args, tag) } } - override fun replaceAll(models: List, tag: String) { + override fun replaceAll( + models: List, + tag: String, + ) { clear(tag) for (model in models) { @@ -83,23 +98,27 @@ abstract class ModelStore( } override fun clear(tag: String) { - val localList = _models.toList() - _models.clear() + val localList = models.toList() + models.clear() persist() for (item in localList) { // no longer listen for changes to this model item.unsubscribe(this) - _changeSubscription.fire { it.onModelRemoved(item, tag) } + changeSubscription.fire { it.onModelRemoved(item, tag) } } } - private fun addItem(model: TModel, tag: String, index: Int? = null) { + private fun addItem( + model: TModel, + tag: String, + index: Int? = null, + ) { if (index != null) { - _models.add(index, model) + models.add(index, model) } else { - _models.add(model) + models.add(model) } // listen for changes to this model @@ -107,18 +126,21 @@ abstract class ModelStore( persist() - _changeSubscription.fire { it.onModelAdded(model, tag) } + changeSubscription.fire { it.onModelAdded(model, tag) } } - private fun removeItem(model: TModel, tag: String) { - _models.remove(model) + private fun removeItem( + model: TModel, + tag: String, + ) { + models.remove(model) // no longer listen for changes to this model model.unsubscribe(this) persist() - _changeSubscription.fire { it.onModelRemoved(model, tag) } + changeSubscription.fire { it.onModelRemoved(model, tag) } } protected fun load() { @@ -127,7 +149,7 @@ abstract class ModelStore( val jsonArray = JSONArray(str) for (index in 0 until jsonArray.length()) { val newModel = create(jsonArray.getJSONObject(index)) ?: continue - _models.add(newModel) + models.add(newModel) // listen for changes to this model newModel.subscribe(this) } @@ -137,7 +159,7 @@ abstract class ModelStore( fun persist() { if (name != null && _prefs != null) { val jsonArray = JSONArray() - for (model in _models) { + for (model in models) { jsonArray.put(model.toJSON()) } @@ -145,8 +167,10 @@ abstract class ModelStore( } } - override fun subscribe(handler: IModelStoreChangeHandler) = _changeSubscription.subscribe(handler) - override fun unsubscribe(handler: IModelStoreChangeHandler) = _changeSubscription.unsubscribe(handler) + override fun subscribe(handler: IModelStoreChangeHandler) = changeSubscription.subscribe(handler) + + override fun unsubscribe(handler: IModelStoreChangeHandler) = changeSubscription.unsubscribe(handler) + override val hasSubscribers: Boolean - get() = _changeSubscription.hasSubscribers + get() = changeSubscription.hasSubscribers } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/SimpleModelStore.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/SimpleModelStore.kt index 60b9e08205..fd8c293dad 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/SimpleModelStore.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/SimpleModelStore.kt @@ -13,14 +13,12 @@ open class SimpleModelStore( * Will be called whenever a new [TModel] needs to be instantiated. */ private val _create: () -> TModel, - /** * The persistable name of the model store. If not specified no persisting will occur. */ name: String? = null, _prefs: IPreferencesService? = null, ) : ModelStore(name, _prefs) where TModel : Model { - init { load() } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/SingletonModelStore.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/SingletonModelStore.kt index 73ba0aabd0..86458fba58 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/SingletonModelStore.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modeling/SingletonModelStore.kt @@ -9,9 +9,8 @@ import com.onesignal.common.events.EventProducer open class SingletonModelStore( val store: ModelStore, ) : ISingletonModelStore, IModelStoreChangeHandler where TModel : Model { - - private val _changeSubscription: EventProducer> = EventProducer() - private val _singletonId: String = "-singleton-" + private val changeSubscription: EventProducer> = EventProducer() + private val singletonId: String = "-singleton-" init { store.subscribe(this) @@ -19,38 +18,52 @@ open class SingletonModelStore( override val model: TModel get() { - val model = store.get(_singletonId) + val model = store.get(singletonId) if (model != null) { return model } val createdModel = store.create() ?: throw Exception("Unable to initialize model from store $store") - createdModel.id = _singletonId + createdModel.id = singletonId store.add(createdModel) return createdModel } - override fun replace(model: TModel, tag: String) { + override fun replace( + model: TModel, + tag: String, + ) { val existingModel = this.model - existingModel.initializeFromModel(_singletonId, model) + existingModel.initializeFromModel(singletonId, model) store.persist() - _changeSubscription.fire { it.onModelReplaced(existingModel, tag) } + changeSubscription.fire { it.onModelReplaced(existingModel, tag) } } - override fun subscribe(handler: ISingletonModelStoreChangeHandler) = _changeSubscription.subscribe(handler) - override fun unsubscribe(handler: ISingletonModelStoreChangeHandler) = _changeSubscription.unsubscribe(handler) + override fun subscribe(handler: ISingletonModelStoreChangeHandler) = changeSubscription.subscribe(handler) + + override fun unsubscribe(handler: ISingletonModelStoreChangeHandler) = changeSubscription.unsubscribe(handler) + override val hasSubscribers: Boolean - get() = _changeSubscription.hasSubscribers + get() = changeSubscription.hasSubscribers - override fun onModelAdded(model: TModel, tag: String) { + override fun onModelAdded( + model: TModel, + tag: String, + ) { // singleton is assumed to always exist. It gets added transparently therefore no event. } - override fun onModelUpdated(args: ModelChangedArgs, tag: String) { - _changeSubscription.fire { it.onModelUpdated(args, tag) } + override fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) { + changeSubscription.fire { it.onModelUpdated(args, tag) } } - override fun onModelRemoved(model: TModel, tag: String) { + override fun onModelRemoved( + model: TModel, + tag: String, + ) { // singleton is assumed to always exist. It never gets removed therefore no event. } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modules/IModule.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modules/IModule.kt index 474b1f2d23..786b7eb8c9 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modules/IModule.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/modules/IModule.kt @@ -8,7 +8,6 @@ import com.onesignal.common.services.ServiceBuilder * property. */ interface IModule { - /** * Register all services and behaviors for this module. This is called during the initialization * of the OneSignal SDK. diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceBuilder.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceBuilder.kt index 56b469d0f2..14d9864b5d 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceBuilder.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceBuilder.kt @@ -1,7 +1,7 @@ package com.onesignal.common.services class ServiceBuilder : IServiceBuilder { - private val _registrations: MutableList> = mutableListOf() + private val registrations: MutableList> = mutableListOf() /** * A reified version of [register] to allow the use of generics when registering @@ -13,23 +13,23 @@ class ServiceBuilder : IServiceBuilder { override fun register(c: Class): ServiceRegistration { val registration = ServiceRegistrationReflection(c) - _registrations.add(registration) + registrations.add(registration) return registration } override fun register(create: (IServiceProvider) -> T): ServiceRegistration { val registration = ServiceRegistrationLambda(create) - _registrations.add(registration) + registrations.add(registration) return registration } override fun register(obj: T): ServiceRegistration { val registration = ServiceRegistrationSingleton(obj) - _registrations.add(registration) + registrations.add(registration) return registration } override fun build(): ServiceProvider { - return ServiceProvider(_registrations) + return ServiceProvider(registrations) } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceProvider.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceProvider.kt index 12ecbde10a..c2630baa39 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceProvider.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceProvider.kt @@ -8,8 +8,7 @@ import com.onesignal.debug.internal.logging.Logging class ServiceProvider( registrations: List>, ) : IServiceProvider { - - private var _serviceMap: Map, List>> + private var serviceMap: Map, List>> init { val serviceMap = mutableMapOf, MutableList>>() @@ -25,7 +24,7 @@ class ServiceProvider( } } - _serviceMap = serviceMap + this.serviceMap = serviceMap } internal inline fun hasService(): Boolean { @@ -45,16 +44,17 @@ class ServiceProvider( } override fun hasService(c: Class): Boolean { - return _serviceMap.containsKey(c) + return serviceMap.containsKey(c) } override fun getAllServices(c: Class): List { val listOfServices: MutableList = mutableListOf() - if (_serviceMap.containsKey(c)) { - for (serviceReg in _serviceMap!![c]!!) { - val service = serviceReg.resolve(this) as T? - ?: throw Exception("Could not instantiate service: $serviceReg") + if (serviceMap.containsKey(c)) { + for (serviceReg in serviceMap!![c]!!) { + val service = + serviceReg.resolve(this) as T? + ?: throw Exception("Could not instantiate service: $serviceReg") listOfServices.add(service) } @@ -76,7 +76,7 @@ class ServiceProvider( override fun getServiceOrNull(c: Class): T? { Logging.debug("${indent}Retrieving service $c") // indent += " " - val service = _serviceMap[c]?.last()?.resolve(this) as T? + val service = serviceMap[c]?.last()?.resolve(this) as T? // indent = indent.substring(0, indent.length-2) return service } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceRegistration.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceRegistration.kt index 87b493fc17..0298381be9 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceRegistration.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/services/ServiceRegistration.kt @@ -49,7 +49,6 @@ abstract class ServiceRegistration { class ServiceRegistrationReflection( private val clazz: Class<*>, ) : ServiceRegistration() { - private var obj: T? = null override fun resolve(provider: IServiceProvider): Any? { @@ -95,7 +94,10 @@ class ServiceRegistrationReflection( return obj } - private fun doesHaveAllParameters(constructor: Constructor<*>, provider: IServiceProvider): Boolean { + private fun doesHaveAllParameters( + constructor: Constructor<*>, + provider: IServiceProvider, + ): Boolean { for (param in constructor.genericParameterTypes) { if (param is ParameterizedType) { val argType = param.actualTypeArguments.firstOrNull() @@ -139,7 +141,6 @@ class ServiceRegistrationReflection( class ServiceRegistrationSingleton( private var obj: T, ) : ServiceRegistration() { - override fun resolve(provider: IServiceProvider): Any? = obj } @@ -153,7 +154,6 @@ class ServiceRegistrationSingleton( class ServiceRegistrationLambda( private val create: ((IServiceProvider) -> T), ) : ServiceRegistration() { - private var obj: T? = null override fun resolve(provider: IServiceProvider): Any? { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/threading/ThreadUtils.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/threading/ThreadUtils.kt index a55bcb91c0..7590f7e12d 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/threading/ThreadUtils.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/threading/ThreadUtils.kt @@ -55,7 +55,10 @@ fun suspendifyOnMain(block: suspend () -> Unit) { * means the scope will run on a background thread. This will * return immediately!!! */ -fun suspendifyOnThread(priority: Int = -1, block: suspend () -> Unit) { +fun suspendifyOnThread( + priority: Int = -1, + block: suspend () -> Unit, +) { thread(priority = priority) { runBlocking { block() @@ -69,7 +72,11 @@ fun suspendifyOnThread(priority: Int = -1, block: suspend () -> Unit) { * means the scope will run on a background thread. This will * return immediately!!! */ -fun suspendifyOnThread(name: String, priority: Int = -1, block: suspend () -> Unit) { +fun suspendifyOnThread( + name: String, + priority: Int = -1, + block: suspend () -> Unit, +) { thread(name = name, priority = priority) { runBlocking { block() diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/threading/Waiter.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/threading/Waiter.kt index 4e94e6dd48..b6dcdfff2e 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/threading/Waiter.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/threading/Waiter.kt @@ -8,17 +8,17 @@ import kotlinx.coroutines.runBlocking * the completion of an event. */ class Waiter { - private val _channel = Channel(Channel.CONFLATED) + private val channel = Channel(Channel.CONFLATED) /** * Suspend the caller until [wake] has been called at least one time. */ - suspend fun waitForWake() = _channel.receive() + suspend fun waitForWake() = channel.receive() /** * Wake the suspending function that has called [waitForWake]. */ - fun wake() = runBlocking { _channel.send(null) } + fun wake() = runBlocking { channel.send(null) } } /** @@ -26,19 +26,19 @@ class Waiter { * the completion of an event, where the event can pass data. */ open class WaiterWithValue { - private val _channel = Channel(Channel.CONFLATED) + private val channel = Channel(Channel.CONFLATED) /** * Suspend the caller until [wake] has been called at least one time. * * @return the data provided by the caller of [wake]. */ - suspend fun waitForWake(): TType = _channel.receive() + suspend fun waitForWake(): TType = channel.receive() /** * Wake the suspending function that has called [waitForWake]. * * @param value The data to be returned by the [waitForWake]. */ - fun wake(value: TType) = runBlocking { _channel.send(value) } + fun wake(value: TType) = runBlocking { channel.send(value) } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/activities/PermissionsActivity.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/activities/PermissionsActivity.kt index e3b2f5d696..52d9bbb16a 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/activities/PermissionsActivity.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/activities/PermissionsActivity.kt @@ -15,8 +15,8 @@ import com.onesignal.core.internal.preferences.PreferenceOneSignalKeys import com.onesignal.core.internal.preferences.PreferenceStores class PermissionsActivity : Activity() { - private var _requestPermissionService: RequestPermissionService? = null - private var _preferenceService: IPreferencesService? = null + private var requestPermissionService: RequestPermissionService? = null + private var preferenceService: IPreferencesService? = null private var permissionRequestType: String? = null private var androidPermissionString: String? = null @@ -27,8 +27,8 @@ class PermissionsActivity : Activity() { return } - _requestPermissionService = OneSignal.getService() - _preferenceService = OneSignal.getService() + requestPermissionService = OneSignal.getService() + preferenceService = OneSignal.getService() handleBundleParams(intent.extras) } @@ -68,9 +68,9 @@ class PermissionsActivity : Activity() { } private fun requestPermission(androidPermissionString: String?) { - if (!_requestPermissionService!!.waiting) { - _requestPermissionService!!.waiting = true - _requestPermissionService!!.shouldShowRequestPermissionRationaleBeforeRequest = + if (!requestPermissionService!!.waiting) { + requestPermissionService!!.waiting = true + requestPermissionService!!.shouldShowRequestPermissionRationaleBeforeRequest = AndroidSupportV4Compat.ActivityCompat.shouldShowRequestPermissionRationale( this@PermissionsActivity, androidPermissionString, @@ -88,7 +88,7 @@ class PermissionsActivity : Activity() { permissions: Array, grantResults: IntArray, ) { - _requestPermissionService!!.waiting = false + requestPermissionService!!.waiting = false // TODO improve this method // TODO after we remove IAM from being an activity window we may be able to remove this handler @@ -100,11 +100,12 @@ class PermissionsActivity : Activity() { Handler().postDelayed({ val granted = grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED - val callback = _requestPermissionService!!.getCallback(permissionRequestType!!) - ?: throw RuntimeException("Missing handler for permissionRequestType: $permissionRequestType") + val callback = + requestPermissionService!!.getCallback(permissionRequestType!!) + ?: throw RuntimeException("Missing handler for permissionRequestType: $permissionRequestType") if (granted) { callback.onAccept() - _preferenceService!!.saveBool( + preferenceService!!.saveBool( PreferenceStores.ONESIGNAL, "${PreferenceOneSignalKeys.PREFS_OS_USER_RESOLVED_PERMISSION_PREFIX}$androidPermissionString", true, @@ -120,7 +121,7 @@ class PermissionsActivity : Activity() { } private fun shouldShowSettings(): Boolean { - if (!_requestPermissionService!!.fallbackToSettings) { + if (!requestPermissionService!!.fallbackToSettings) { return false } @@ -129,13 +130,13 @@ class PermissionsActivity : Activity() { // the second time shouldShowRequestPermissionRationale becomes false again. We // look for the change from `true` -> `false`. When this happens we remember this // rejection, as the user will never be prompted again. - if (_requestPermissionService!!.shouldShowRequestPermissionRationaleBeforeRequest) { + if (requestPermissionService!!.shouldShowRequestPermissionRationaleBeforeRequest) { if (!AndroidSupportV4Compat.ActivityCompat.shouldShowRequestPermissionRationale( this@PermissionsActivity, androidPermissionString, ) ) { - _preferenceService!!.saveBool( + preferenceService!!.saveBool( PreferenceStores.ONESIGNAL, "${PreferenceOneSignalKeys.PREFS_OS_USER_RESOLVED_PERMISSION_PREFIX}$androidPermissionString", true, @@ -144,7 +145,7 @@ class PermissionsActivity : Activity() { } } - return _preferenceService!!.getBool( + return preferenceService!!.getBool( PreferenceStores.ONESIGNAL, "${PreferenceOneSignalKeys.PREFS_OS_USER_RESOLVED_PERMISSION_PREFIX}$androidPermissionString", false, diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IActivityLifecycleHandler.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IActivityLifecycleHandler.kt index 093474f5c1..058199cd3b 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IActivityLifecycleHandler.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IActivityLifecycleHandler.kt @@ -9,7 +9,6 @@ import android.app.Application.ActivityLifecycleCallbacks * [ActivityLifecycleCallbacks], it provides an abstraction more specific to the OneSignal SDK */ interface IActivityLifecycleHandler { - /** * Called when an activity is made available to the application. */ @@ -27,5 +26,6 @@ interface IActivityLifecycleHandler { */ open class ActivityLifecycleHandlerBase : IActivityLifecycleHandler { override fun onActivityAvailable(activity: Activity) {} + override fun onActivityStopped(activity: Activity) {} } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationLifecycleHandler.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationLifecycleHandler.kt index 0ca09842bb..146396d82b 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationLifecycleHandler.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationLifecycleHandler.kt @@ -8,7 +8,6 @@ import android.app.Application.ActivityLifecycleCallbacks * [ActivityLifecycleCallbacks], it provides an abstraction more specific to the OneSignal SDK */ interface IApplicationLifecycleHandler { - /** * Called when the application is brought into the foreground. */ @@ -26,5 +25,6 @@ interface IApplicationLifecycleHandler { */ open class ApplicationLifecycleHandlerBase : IApplicationLifecycleHandler { override fun onFocus() {} + override fun onUnfocused() {} } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationService.kt index d5eb89ff1d..ed27e918f6 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationService.kt @@ -8,7 +8,6 @@ import android.content.Context * information and subscribe to application events. */ interface IApplicationService { - /** * The application context */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/impl/ApplicationService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/impl/ApplicationService.kt index 7514bc7140..c1a7f5f45f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/impl/ApplicationService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/impl/ApplicationService.kt @@ -26,9 +26,9 @@ import com.onesignal.debug.internal.logging.Logging import java.lang.ref.WeakReference class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, OnGlobalLayoutListener { - private val _activityLifecycleNotifier = EventProducer() - private val _applicationLifecycleNotifier = EventProducer() - private val _systemConditionNotifier = EventProducer() + private val activityLifecycleNotifier = EventProducer() + private val applicationLifecycleNotifier = EventProducer() + private val systemConditionNotifier = EventProducer() override val isInForeground: Boolean get() = entryState.isAppOpen || entryState.isNotificationClick @@ -47,7 +47,7 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On Logging.debug("ApplicationService: current activity=$current") if (value != null) { - _activityLifecycleNotifier.fire { it.onActivityAvailable(value) } + activityLifecycleNotifier.fire { it.onActivityAvailable(value) } try { value.window.decorView.viewTreeObserver.addOnGlobalLayoutListener(this) } catch (e: RuntimeException) { @@ -60,11 +60,11 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On } /** Whether the next resume is due to the first activity or not **/ - private var _nextResumeIsFirstActivity: Boolean = false + private var nextResumeIsFirstActivity: Boolean = false /** Used to determine when an app goes in focus and out of focus **/ - private var _activityReferences = 0 - private var _isActivityChangingConfigurations = false + private var activityReferences = 0 + private var isActivityChangingConfigurations = false /** * Call to "start" this service, expected to be called during initialization of the SDK. @@ -77,20 +77,22 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On val application = context.applicationContext as Application application.registerActivityLifecycleCallbacks(this) - val configuration = object : ComponentCallbacks { - override fun onConfigurationChanged(newConfig: Configuration) { - // If Activity contains the configChanges orientation flag, re-create the view this way - if (current != null && AndroidUtils.hasConfigChangeFlag( - current!!, - ActivityInfo.CONFIG_ORIENTATION, - ) - ) { - onOrientationChanged(newConfig.orientation, current!!) + val configuration = + object : ComponentCallbacks { + override fun onConfigurationChanged(newConfig: Configuration) { + // If Activity contains the configChanges orientation flag, re-create the view this way + if (current != null && + AndroidUtils.hasConfigChangeFlag( + current!!, + ActivityInfo.CONFIG_ORIENTATION, + ) + ) { + onOrientationChanged(newConfig.orientation, current!!) + } } - } - override fun onLowMemory() {} - } + override fun onLowMemory() {} + } application.registerComponentCallbacks(configuration) @@ -101,11 +103,11 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On entryState = AppEntryAction.APP_OPEN if (isCurrentActivityNull && isContextActivity) { current = context as Activity? - _activityReferences = 1 - _nextResumeIsFirstActivity = false + activityReferences = 1 + nextResumeIsFirstActivity = false } } else { - _nextResumeIsFirstActivity = true + nextResumeIsFirstActivity = true entryState = AppEntryAction.APP_CLOSE } @@ -113,30 +115,33 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On } override fun addApplicationLifecycleHandler(handler: IApplicationLifecycleHandler) { - _applicationLifecycleNotifier.subscribe(handler) + applicationLifecycleNotifier.subscribe(handler) } override fun removeApplicationLifecycleHandler(handler: IApplicationLifecycleHandler) { - _applicationLifecycleNotifier.unsubscribe(handler) + applicationLifecycleNotifier.unsubscribe(handler) } override fun addActivityLifecycleHandler(handler: IActivityLifecycleHandler) { - _activityLifecycleNotifier.subscribe(handler) + activityLifecycleNotifier.subscribe(handler) if (current != null) { handler.onActivityAvailable(current!!) } } override fun removeActivityLifecycleHandler(handler: IActivityLifecycleHandler) { - _activityLifecycleNotifier.unsubscribe(handler) + activityLifecycleNotifier.unsubscribe(handler) } - override fun onActivityCreated(activity: Activity, bundle: Bundle?) { - Logging.debug("ApplicationService.onActivityCreated($_activityReferences,$entryState): $activity") + override fun onActivityCreated( + activity: Activity, + bundle: Bundle?, + ) { + Logging.debug("ApplicationService.onActivityCreated($activityReferences,$entryState): $activity") } override fun onActivityStarted(activity: Activity) { - Logging.debug("ApplicationService.onActivityStarted($_activityReferences,$entryState): $activity") + Logging.debug("ApplicationService.onActivityStarted($activityReferences,$entryState): $activity") if (current == activity) { return @@ -144,16 +149,16 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On current = activity - if ((!isInForeground || _nextResumeIsFirstActivity) && !_isActivityChangingConfigurations) { - _activityReferences = 1 + if ((!isInForeground || nextResumeIsFirstActivity) && !isActivityChangingConfigurations) { + activityReferences = 1 handleFocus() } else { - _activityReferences++ + activityReferences++ } } override fun onActivityResumed(activity: Activity) { - Logging.debug("ApplicationService.onActivityResumed($_activityReferences,$entryState): $activity") + Logging.debug("ApplicationService.onActivityResumed($activityReferences,$entryState): $activity") // When an activity has something shown above it, it will be paused allowing // the new activity to be started (where current is set). However when that @@ -164,39 +169,42 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On current = activity } - if ((!isInForeground || _nextResumeIsFirstActivity) && !_isActivityChangingConfigurations) { - _activityReferences = 1 + if ((!isInForeground || nextResumeIsFirstActivity) && !isActivityChangingConfigurations) { + activityReferences = 1 handleFocus() } } override fun onActivityPaused(activity: Activity) { - Logging.debug("ApplicationService.onActivityPaused($_activityReferences,$entryState): $activity") + Logging.debug("ApplicationService.onActivityPaused($activityReferences,$entryState): $activity") } override fun onActivityStopped(activity: Activity) { - Logging.debug("ApplicationService.onActivityStopped($_activityReferences,$entryState): $activity") + Logging.debug("ApplicationService.onActivityStopped($activityReferences,$entryState): $activity") - _isActivityChangingConfigurations = activity.isChangingConfigurations - if (!_isActivityChangingConfigurations && --_activityReferences <= 0) { + isActivityChangingConfigurations = activity.isChangingConfigurations + if (!isActivityChangingConfigurations && --activityReferences <= 0) { current = null - _activityReferences = 0 + activityReferences = 0 handleLostFocus() } - _activityLifecycleNotifier.fire { it.onActivityStopped(activity) } + activityLifecycleNotifier.fire { it.onActivityStopped(activity) } } - override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) { + override fun onActivitySaveInstanceState( + p0: Activity, + p1: Bundle, + ) { // Intentionally left empty } override fun onActivityDestroyed(activity: Activity) { - Logging.debug("ApplicationService.onActivityDestroyed($_activityReferences,$entryState): $activity") + Logging.debug("ApplicationService.onActivityDestroyed($activityReferences,$entryState): $activity") } override fun onGlobalLayout() { - _systemConditionNotifier.fire { it.systemConditionChanged() } + systemConditionNotifier.fire { it.systemConditionChanged() } } override suspend fun waitUntilSystemConditionsAvailable(): Boolean { @@ -218,7 +226,10 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On manager.registerFragmentLifecycleCallbacks( object : FragmentManager.FragmentLifecycleCallbacks() { - override fun onFragmentDetached(fm: FragmentManager, fragmentDetached: Fragment) { + override fun onFragmentDetached( + fm: FragmentManager, + fragmentDetached: Fragment, + ) { super.onFragmentDetached(fm, fragmentDetached) if (fragmentDetached is DialogFragment) { manager.unregisterFragmentLifecycleCallbacks(this) @@ -233,29 +244,32 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On } } } catch (exception: NoClassDefFoundError) { - Logging.info("ApplicationService.waitUntilSystemConditionsAvailable: AppCompatActivity is not used in this app, skipping 'isDialogFragmentShowing' check: $exception") + Logging.info( + "ApplicationService.waitUntilSystemConditionsAvailable: AppCompatActivity is not used in this app, skipping 'isDialogFragmentShowing' check: $exception", + ) } val waiter = Waiter() - val systemConditionHandler = object : ISystemConditionHandler { - override fun systemConditionChanged() { - val keyboardUp = DeviceUtils.isKeyboardUp(WeakReference(current)) - if (!keyboardUp) { - waiter.wake() + val systemConditionHandler = + object : ISystemConditionHandler { + override fun systemConditionChanged() { + val keyboardUp = DeviceUtils.isKeyboardUp(WeakReference(current)) + if (!keyboardUp) { + waiter.wake() + } } } - } // Add the listener prior to checking the condition to avoid a race condition where // we'll never get a callback and will be waiting forever. - _systemConditionNotifier.subscribe(systemConditionHandler) + systemConditionNotifier.subscribe(systemConditionHandler) val keyboardUp = DeviceUtils.isKeyboardUp(WeakReference(currentActivity)) // if the keyboard is up we suspend until it is down if (keyboardUp) { Logging.warn("ApplicationService.waitUntilSystemConditionsAvailable: keyboard up detected") waiter.waitForWake() } - _systemConditionNotifier.unsubscribe(systemConditionHandler) + systemConditionNotifier.unsubscribe(systemConditionHandler) return true } @@ -273,20 +287,25 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On // Ensures the root decor view is ready by checking the following; // 1. Is fully attach to the root window and insets are available // 2. Ensure if any Activities are changed while waiting we use the updated one - fun decorViewReady(activity: Activity, runnable: Runnable) { + fun decorViewReady( + activity: Activity, + runnable: Runnable, + ) { val listenerKey = "decorViewReady:$runnable" val self = this activity.window.decorView.post { - self.addActivityLifecycleHandler(object : ActivityLifecycleHandlerBase() { - override fun onActivityAvailable(currentActivity: Activity) { - self.removeActivityLifecycleHandler(this) - if (AndroidUtils.isActivityFullyReady(currentActivity)) { - runnable.run() - } else { - decorViewReady(currentActivity, runnable) + self.addActivityLifecycleHandler( + object : ActivityLifecycleHandlerBase() { + override fun onActivityAvailable(currentActivity: Activity) { + self.removeActivityLifecycleHandler(this) + if (AndroidUtils.isActivityFullyReady(currentActivity)) { + runnable.run() + } else { + decorViewReady(currentActivity, runnable) + } } - } - }) + }, + ) } } @@ -296,20 +315,27 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On * This fix was originally implemented for In App Messages not being re-shown when orientation * was changed on wrapper SDK apps */ - private fun onOrientationChanged(orientation: Int, activity: Activity) { + private fun onOrientationChanged( + orientation: Int, + activity: Activity, + ) { // Log device orientation change if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - Logging.debug("ApplicationService.onOrientationChanged: Configuration Orientation Change: LANDSCAPE ($orientation) on activity: $activity") + Logging.debug( + "ApplicationService.onOrientationChanged: Configuration Orientation Change: LANDSCAPE ($orientation) on activity: $activity", + ) } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { - Logging.debug("ApplicationService.onOrientationChanged: Configuration Orientation Change: PORTRAIT ($orientation) on activity: $activity") + Logging.debug( + "ApplicationService.onOrientationChanged: Configuration Orientation Change: PORTRAIT ($orientation) on activity: $activity", + ) } // Remove view handleLostFocus() - _activityLifecycleNotifier.fire { it.onActivityStopped(activity) } + activityLifecycleNotifier.fire { it.onActivityStopped(activity) } // Show view - _activityLifecycleNotifier.fire { it.onActivityAvailable(activity) } + activityLifecycleNotifier.fire { it.onActivityAvailable(activity) } activity.window.decorView.viewTreeObserver.addOnGlobalLayoutListener(this) @@ -322,23 +348,25 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On entryState = AppEntryAction.APP_CLOSE - _applicationLifecycleNotifier.fire { it.onUnfocused() } + applicationLifecycleNotifier.fire { it.onUnfocused() } } else { Logging.debug("ApplicationService.handleLostFocus: application already out of focus") } } private fun handleFocus() { - if (!isInForeground || _nextResumeIsFirstActivity) { - Logging.debug("ApplicationService.handleFocus: application is now in focus, nextResumeIsFirstActivity=$_nextResumeIsFirstActivity") - _nextResumeIsFirstActivity = false + if (!isInForeground || nextResumeIsFirstActivity) { + Logging.debug( + "ApplicationService.handleFocus: application is now in focus, nextResumeIsFirstActivity=$nextResumeIsFirstActivity", + ) + nextResumeIsFirstActivity = false // We assume we are called *after* the notification module has determined entry due to notification. if (entryState != AppEntryAction.NOTIFICATION_CLICK) { entryState = AppEntryAction.APP_OPEN } - _applicationLifecycleNotifier.fire { it.onFocus() } + applicationLifecycleNotifier.fire { it.onFocus() } } else { Logging.debug("ApplicationService.handleFocus: application never lost focus") } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/backend/IParamsBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/backend/IParamsBackendService.kt index 6810c5d249..514cc798bc 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/backend/IParamsBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/backend/IParamsBackendService.kt @@ -14,7 +14,10 @@ interface IParamsBackendService { * * @return The configuration parameters. */ - suspend fun fetchParams(appId: String, subscriptionId: String?): ParamsObject + suspend fun fetchParams( + appId: String, + subscriptionId: String?, + ): ParamsObject } class ParamsObject( diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/backend/impl/ParamsBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/backend/impl/ParamsBackendService.kt index 271cf62a29..d563bca9cf 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/backend/impl/ParamsBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/backend/impl/ParamsBackendService.kt @@ -20,8 +20,10 @@ import org.json.JSONObject internal class ParamsBackendService( private val _http: IHttpClient, ) : IParamsBackendService { - - override suspend fun fetchParams(appId: String, subscriptionId: String?): ParamsObject { + override suspend fun fetchParams( + appId: String, + subscriptionId: String?, + ): ParamsObject { Logging.log(LogLevel.DEBUG, "ParamsBackendService.fetchParams(appId: $appId, subscriptionId: $subscriptionId)") var paramsUrl = "apps/$appId/android_params.js" @@ -46,17 +48,19 @@ internal class ParamsBackendService( // Process FCM params var fcmParams: FCMParamsObject? = null responseJson.expandJSONObject("fcm") { - fcmParams = FCMParamsObject( - apiKey = it.safeString("api_key"), - appId = it.safeString("app_id"), - projectId = it.safeString("project_id"), - ) + fcmParams = + FCMParamsObject( + apiKey = it.safeString("api_key"), + appId = it.safeString("app_id"), + projectId = it.safeString("project_id"), + ) } return ParamsObject( googleProjectNumber = responseJson.safeString("android_sender_id"), enterprise = responseJson.safeBool("enterp"), - useIdentityVerification = responseJson.safeBool("require_ident_auth"), // TODO: New + // TODO: New + useIdentityVerification = responseJson.safeBool("require_ident_auth"), notificationChannels = responseJson.optJSONArray("chnl_lst"), firebaseAnalytics = responseJson.safeBool("fba"), restoreTTLFilter = responseJson.safeBool("restore_ttl_filter"), @@ -66,7 +70,8 @@ internal class ParamsBackendService( unsubscribeWhenNotificationsDisabled = responseJson.safeBool("unsubscribe_on_notifications_disabled"), locationShared = responseJson.safeBool("location_shared"), requiresUserPrivacyConsent = responseJson.safeBool("requires_user_privacy_consent"), - opRepoExecutionInterval = responseJson.safeLong("oprepo_execution_interval"), // TODO: New + // TODO: New + opRepoExecutionInterval = responseJson.safeLong("oprepo_execution_interval"), influenceParams = influenceParams ?: InfluenceParamsObject(), fcmParams = fcmParams ?: FCMParamsObject(), ) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/IBackgroundService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/IBackgroundService.kt index 739422f0c5..70ccbc4cb2 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/IBackgroundService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/IBackgroundService.kt @@ -9,7 +9,6 @@ import androidx.annotation.WorkerThread * service's [scheduleBackgroundRunIn] will be analyzed to determine when [backgroundRun] should be called. */ interface IBackgroundService { - /** * When this background service should be run, in milliseconds. If null, this service does not * need to be run in the background. diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/impl/BackgroundManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/impl/BackgroundManager.kt index d230e100c2..4cc37d3132 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/impl/BackgroundManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/impl/BackgroundManager.kt @@ -65,11 +65,10 @@ internal class BackgroundManager( private val _time: ITime, private val _backgroundServices: List<(IBackgroundService)>, ) : IApplicationLifecycleHandler, IBackgroundManager, IStartableService { - override var needsJobReschedule = false - private val _lock = Any() - private var _nextScheduledSyncTimeMs = 0L + private val lock = Any() + private var nextScheduledSyncTimeMs = 0L private var backgroundSyncJob: Job? = null @SuppressLint("NewApi") // can suppress because we are only retrieving the class, not necessarily using it @@ -107,26 +106,28 @@ internal class BackgroundManager( } private fun cancelSyncTask() { - synchronized(_lock) { - _nextScheduledSyncTimeMs = 0L + synchronized(lock) { + nextScheduledSyncTimeMs = 0L cancelBackgroundSyncTask() } } // Entry point from SyncJobService and SyncService when the job is kicked off - override suspend fun runBackgroundServices() = coroutineScope { - Logging.debug("OSBackground sync, calling initWithContext") + override suspend fun runBackgroundServices() = + coroutineScope { + Logging.debug("OSBackground sync, calling initWithContext") - backgroundSyncJob = launch(Dispatchers.Unconfined) { - synchronized(_lock) { _nextScheduledSyncTimeMs = 0L } + backgroundSyncJob = + launch(Dispatchers.Unconfined) { + synchronized(lock) { nextScheduledSyncTimeMs = 0L } - for (backgroundService in _backgroundServices) { - backgroundService.backgroundRun() - } + for (backgroundService in _backgroundServices) { + backgroundService.backgroundRun() + } - scheduleBackground() + scheduleBackground() + } } - } override fun cancelRunBackgroundServices(): Boolean { if (backgroundSyncJob == null) return false @@ -137,21 +138,21 @@ internal class BackgroundManager( private fun scheduleSyncTask(delayMs: Long) { var delayMs = delayMs - synchronized(_lock) { - if (_nextScheduledSyncTimeMs != 0L && - _time.currentTimeMillis + delayMs > _nextScheduledSyncTimeMs + synchronized(lock) { + if (nextScheduledSyncTimeMs != 0L && + _time.currentTimeMillis + delayMs > nextScheduledSyncTimeMs ) { - Logging.debug("OSSyncService scheduleSyncTask already update scheduled nextScheduledSyncTimeMs: $_nextScheduledSyncTimeMs") + Logging.debug("OSSyncService scheduleSyncTask already update scheduled nextScheduledSyncTimeMs: $nextScheduledSyncTimeMs") return } if (delayMs < 5000) delayMs = 5000 scheduleBackgroundSyncTask(delayMs) - _nextScheduledSyncTimeMs = _time.currentTimeMillis + delayMs + nextScheduledSyncTimeMs = _time.currentTimeMillis + delayMs } } private fun scheduleBackgroundSyncTask(delayMs: Long) { - synchronized(_lock) { + synchronized(lock) { if (useJob()) { scheduleSyncServiceAsJob(delayMs) } else { @@ -219,7 +220,7 @@ internal class BackgroundManager( private fun cancelBackgroundSyncTask() { Logging.debug(this.javaClass.simpleName + " cancel background sync") - synchronized(_lock) { + synchronized(lock) { if (useJob()) { val jobScheduler = _applicationService.appContext.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler jobScheduler.cancel(SYNC_TASK_ID) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/config/ConfigModel.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/config/ConfigModel.kt index 44c3e321cb..22b3297931 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/config/ConfigModel.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/config/ConfigModel.kt @@ -10,42 +10,54 @@ class ConfigModel : Model() { */ var isInitializedWithRemote: Boolean get() = getBooleanProperty(::isInitializedWithRemote.name) { false } - set(value) { setBooleanProperty(::isInitializedWithRemote.name, value) } + set(value) { + setBooleanProperty(::isInitializedWithRemote.name, value) + } /** * The current OneSignal application ID provided to the SDK. */ var appId: String get() = getStringProperty(::appId.name) - set(value) { setStringProperty(::appId.name, value) } + set(value) { + setStringProperty(::appId.name, value) + } /** * This device's push subscription ID. */ var pushSubscriptionId: String? get() = getOptStringProperty(::pushSubscriptionId.name) - set(value) { setOptStringProperty(::pushSubscriptionId.name, value) } + set(value) { + setOptStringProperty(::pushSubscriptionId.name, value) + } /** * The API URL String. */ var apiUrl: String get() = getStringProperty(::apiUrl.name) { "https://api.onesignal.com/" } - set(value) { setStringProperty(::apiUrl.name, value) } + set(value) { + setStringProperty(::apiUrl.name, value) + } /** * Whether the SDK requires privacy consent to send data to backend. */ var consentRequired: Boolean? get() = getOptBooleanProperty(::consentRequired.name) - set(value) { setOptBooleanProperty(::consentRequired.name, value) } + set(value) { + setOptBooleanProperty(::consentRequired.name, value) + } /** * Whether the SDK has been given consent to privacy. */ var consentGiven: Boolean? get() = getOptBooleanProperty(::consentGiven.name) - set(value) { setOptBooleanProperty(::consentGiven.name, value) } + set(value) { + setOptBooleanProperty(::consentGiven.name, value) + } /** * Whether location is shared. @@ -59,42 +71,54 @@ class ConfigModel : Model() { */ var disableGMSMissingPrompt: Boolean get() = getBooleanProperty(::disableGMSMissingPrompt.name) { false } - set(value) { setBooleanProperty(::disableGMSMissingPrompt.name, value) } + set(value) { + setBooleanProperty(::disableGMSMissingPrompt.name, value) + } /** * Whether to disable the "GMS is missing" prompt to the user. */ var userRejectedGMSUpdate: Boolean get() = getBooleanProperty(::userRejectedGMSUpdate.name) { false } - set(value) { setBooleanProperty(::userRejectedGMSUpdate.name, value) } + set(value) { + setBooleanProperty(::userRejectedGMSUpdate.name, value) + } /** * Whether to automatically unsubscribe from OneSignal when notifications have been disabled. */ var unsubscribeWhenNotificationsDisabled: Boolean get() = getBooleanProperty(::unsubscribeWhenNotificationsDisabled.name) { false } - set(value) { setBooleanProperty(::unsubscribeWhenNotificationsDisabled.name, value) } + set(value) { + setBooleanProperty(::unsubscribeWhenNotificationsDisabled.name, value) + } /** * The timeout in milliseconds for an HTTP connection. */ var httpTimeout: Int get() = getIntProperty(::httpTimeout.name) { 120000 } - set(value) { setIntProperty(::httpTimeout.name, value) } + set(value) { + setIntProperty(::httpTimeout.name, value) + } /** * The timeout in milliseconds for an HTTP connection GET request. */ var httpGetTimeout: Int get() = getIntProperty(::httpGetTimeout.name) { 60000 } - set(value) { setIntProperty(::httpGetTimeout.name, value) } + set(value) { + setIntProperty(::httpGetTimeout.name, value) + } /** * Maximum time in milliseconds a user can spend out of focus before a new session is created. */ var sessionFocusTimeout: Long get() = getLongProperty(::sessionFocusTimeout.name) { 30000 } - set(value) { setLongProperty(::sessionFocusTimeout.name, value) } + set(value) { + setLongProperty(::sessionFocusTimeout.name, value) + } /** * The minimum number of milliseconds required to pass before executing another operation on @@ -102,7 +126,9 @@ class ConfigModel : Model() { */ var opRepoExecutionInterval: Long get() = getLongProperty(::opRepoExecutionInterval.name) { 5000 } - set(value) { setLongProperty(::opRepoExecutionInterval.name, value) } + set(value) { + setLongProperty(::opRepoExecutionInterval.name, value) + } /** * The number of milliseconds to delay after the operation repo processing has been woken. This @@ -111,70 +137,90 @@ class ConfigModel : Model() { */ var opRepoPostWakeDelay: Long get() = getLongProperty(::opRepoPostWakeDelay.name) { 200 } - set(value) { setLongProperty(::opRepoPostWakeDelay.name, value) } + set(value) { + setLongProperty(::opRepoPostWakeDelay.name, value) + } /** * The minimum number of milliseconds required to pass to allow the fetching of IAM to occur. */ var fetchIAMMinInterval: Long get() = getLongProperty(::fetchIAMMinInterval.name) { 30000 } - set(value) { setLongProperty(::fetchIAMMinInterval.name, value) } + set(value) { + setLongProperty(::fetchIAMMinInterval.name, value) + } /** * The google project number for GMS devices. */ var googleProjectNumber: String? get() = getOptStringProperty(::googleProjectNumber.name) - set(value) { setOptStringProperty(::googleProjectNumber.name, value) } + set(value) { + setOptStringProperty(::googleProjectNumber.name, value) + } /** * Whether the current application is an enterprise-level */ var enterprise: Boolean get() = getBooleanProperty(::enterprise.name) { false } - set(value) { setBooleanProperty(::enterprise.name, value) } + set(value) { + setBooleanProperty(::enterprise.name, value) + } /** * Whether SMS auth hash should be used. */ var useIdentityVerification: Boolean get() = getBooleanProperty(::useIdentityVerification.name) { false } - set(value) { setBooleanProperty(::useIdentityVerification.name, value) } + set(value) { + setBooleanProperty(::useIdentityVerification.name, value) + } /** * The notification channel information as a [JSONArray] */ var notificationChannels: JSONArray? get() = JSONArray(getOptStringProperty(::notificationChannels.name) { null } ?: "[]") - set(value) { setOptStringProperty(::notificationChannels.name, value?.toString()) } + set(value) { + setOptStringProperty(::notificationChannels.name, value?.toString()) + } /** * Whether firebase analytics should be used */ var firebaseAnalytics: Boolean get() = getBooleanProperty(::firebaseAnalytics.name) { false } - set(value) { setBooleanProperty(::firebaseAnalytics.name, value) } + set(value) { + setBooleanProperty(::firebaseAnalytics.name, value) + } /** * Whether to honor TTL for notifications */ var restoreTTLFilter: Boolean get() = getBooleanProperty(::restoreTTLFilter.name) { true } - set(value) { setBooleanProperty(::restoreTTLFilter.name, value) } + set(value) { + setBooleanProperty(::restoreTTLFilter.name, value) + } /** * Whether to track notification receive receipts */ var receiveReceiptEnabled: Boolean get() = getBooleanProperty(::receiveReceiptEnabled.name) { false } - set(value) { setBooleanProperty(::receiveReceiptEnabled.name, value) } + set(value) { + setBooleanProperty(::receiveReceiptEnabled.name, value) + } /** * Whether to clear group on summary clicks */ var clearGroupOnSummaryClick: Boolean get() = getBooleanProperty(::clearGroupOnSummaryClick.name) { true } - set(value) { setBooleanProperty(::clearGroupOnSummaryClick.name, value) } + set(value) { + setBooleanProperty(::clearGroupOnSummaryClick.name, value) + } /** * The outcomes parameters @@ -188,7 +234,10 @@ class ConfigModel : Model() { val fcmParams: FCMConfigModel get() = getAnyProperty(::fcmParams.name) { FCMConfigModel(this, ::fcmParams.name) } as FCMConfigModel - override fun createModelForProperty(property: String, jsonObject: JSONObject): Model? { + override fun createModelForProperty( + property: String, + jsonObject: JSONObject, + ): Model? { if (property == ::influenceParams.name) { val model = InfluenceConfigModel(this, ::influenceParams.name) model.initializeFromJson(jsonObject) @@ -214,49 +263,63 @@ class InfluenceConfigModel(parentModel: Model, parentProperty: String) : Model(p */ var indirectNotificationAttributionWindow: Int get() = getIntProperty(::indirectNotificationAttributionWindow.name) { DEFAULT_INDIRECT_ATTRIBUTION_WINDOW } - set(value) { setIntProperty(::indirectNotificationAttributionWindow.name, value) } + set(value) { + setIntProperty(::indirectNotificationAttributionWindow.name, value) + } /** * The maximum number of push notifications that can influence at one time. */ var notificationLimit: Int get() = getIntProperty(::notificationLimit.name) { DEFAULT_NOTIFICATION_LIMIT } - set(value) { setIntProperty(::notificationLimit.name, value) } + set(value) { + setIntProperty(::notificationLimit.name, value) + } /** * The number of minutes an IAM can be considered to influence a user. */ var indirectIAMAttributionWindow: Int get() = getIntProperty(::indirectIAMAttributionWindow.name) { DEFAULT_INDIRECT_ATTRIBUTION_WINDOW } - set(value) { setIntProperty(::indirectIAMAttributionWindow.name, value) } + set(value) { + setIntProperty(::indirectIAMAttributionWindow.name, value) + } /** * The maximum number of IAMs that can influence at one time. */ var iamLimit: Int get() = getIntProperty(::iamLimit.name) { DEFAULT_NOTIFICATION_LIMIT } - set(value) { setIntProperty(::iamLimit.name, value) } + set(value) { + setIntProperty(::iamLimit.name, value) + } /** * Whether DIRECT influences are enabled. */ var isDirectEnabled: Boolean get() = getBooleanProperty(::isDirectEnabled.name) { false } - set(value) { setBooleanProperty(::isDirectEnabled.name, value) } + set(value) { + setBooleanProperty(::isDirectEnabled.name, value) + } /** * Whether INDIRECT influences are enabled. */ var isIndirectEnabled: Boolean get() = getBooleanProperty(::isIndirectEnabled.name) { false } - set(value) { setBooleanProperty(::isIndirectEnabled.name, value) } + set(value) { + setBooleanProperty(::isIndirectEnabled.name, value) + } /** * Whether UNATTRIBUTED influences are enabled. */ var isUnattributedEnabled: Boolean get() = getBooleanProperty(::isUnattributedEnabled.name) { false } - set(value) { setBooleanProperty(::isUnattributedEnabled.name, value) } + set(value) { + setBooleanProperty(::isUnattributedEnabled.name, value) + } companion object { const val DEFAULT_INDIRECT_ATTRIBUTION_WINDOW = 24 * 60 @@ -273,19 +336,25 @@ class FCMConfigModel(parentModel: Model, parentProperty: String) : Model(parentM */ var projectId: String? get() = getOptStringProperty(::projectId.name) { null } - set(value) { setOptStringProperty(::projectId.name, value) } + set(value) { + setOptStringProperty(::projectId.name, value) + } /** * The FCM app ID. */ var appId: String? get() = getOptStringProperty(::appId.name) { null } - set(value) { setOptStringProperty(::appId.name, value) } + set(value) { + setOptStringProperty(::appId.name, value) + } /** * The FCM api key. */ var apiKey: String? get() = getOptStringProperty(::apiKey.name) { null } - set(value) { setOptStringProperty(::apiKey.name, value) } + set(value) { + setOptStringProperty(::apiKey.name, value) + } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/config/impl/ConfigModelStoreListener.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/config/impl/ConfigModelStoreListener.kt index 147543dbb8..87d7eae6b0 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/config/impl/ConfigModelStoreListener.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/config/impl/ConfigModelStoreListener.kt @@ -26,13 +26,15 @@ internal class ConfigModelStoreListener( private val _paramsBackendService: IParamsBackendService, private val _subscriptionManager: ISubscriptionManager, ) : IStartableService, ISingletonModelStoreChangeHandler { - override fun start() { _configModelStore.subscribe(this) fetchParams() } - override fun onModelUpdated(args: ModelChangedArgs, tag: String) { + override fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) { if (args.property != ConfigModel::appId.name) { return } @@ -40,7 +42,10 @@ internal class ConfigModelStoreListener( fetchParams() } - override fun onModelReplaced(model: ConfigModel, tag: String) { + override fun onModelReplaced( + model: ConfigModel, + tag: String, + ) { if (tag != ModelChangeTags.NORMAL) { return } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/IDatabase.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/IDatabase.kt index 9a6945cf5a..ef206d73da 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/IDatabase.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/IDatabase.kt @@ -8,7 +8,6 @@ import android.content.ContentValues * caller to offload data operations to a non-main thread. */ interface IDatabase { - /** * Query for the underlying data. * @@ -47,7 +46,11 @@ interface IDatabase { * * @see [https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert(java.lang.String,%20java.lang.String,%20android.content.ContentValues)] */ - fun insert(table: String, nullColumnHack: String?, values: ContentValues?) + fun insert( + table: String, + nullColumnHack: String?, + values: ContentValues?, + ) /** * Insert a new record into the database as specified. If the insert fails, it will throw an exception. @@ -58,7 +61,11 @@ interface IDatabase { * * @see [https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert(java.lang.String,%20java.lang.String,%20android.content.ContentValues)] */ - fun insertOrThrow(table: String, nullColumnHack: String?, values: ContentValues?) + fun insertOrThrow( + table: String, + nullColumnHack: String?, + values: ContentValues?, + ) /** * Update one or more records into the database as specified. @@ -73,7 +80,12 @@ interface IDatabase { * * @return The number of records that were updated. */ - fun update(table: String, values: ContentValues, whereClause: String?, whereArgs: Array?): Int + fun update( + table: String, + values: ContentValues, + whereClause: String?, + whereArgs: Array?, + ): Int /** * Delete one or more records from the database as specified. @@ -85,5 +97,9 @@ interface IDatabase { * @param whereArgs The row selection criteria arguments. Provide `null` when there were * no parameters provided in [whereClause]. */ - fun delete(table: String, whereClause: String?, whereArgs: Array?) + fun delete( + table: String, + whereClause: String?, + whereArgs: Array?, + ) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/DatabaseCursor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/DatabaseCursor.kt index 737f36cb4b..719a0c6728 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/DatabaseCursor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/DatabaseCursor.kt @@ -7,11 +7,17 @@ internal class DatabaseCursor( private val _cursor: Cursor, ) : ICursor { override val count: Int get() = _cursor.count + override fun moveToFirst(): Boolean = _cursor.moveToFirst() + override fun moveToNext(): Boolean = _cursor.moveToNext() + override fun getString(column: String): String = _cursor.getString(_cursor.getColumnIndex(column)) + override fun getFloat(column: String): Float = _cursor.getFloat(_cursor.getColumnIndex(column)) + override fun getLong(column: String): Long = _cursor.getLong(_cursor.getColumnIndex(column)) + override fun getInt(column: String): Int = _cursor.getInt(_cursor.getColumnIndex(column)) override fun getOptString(column: String): String? { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/DatabaseProvider.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/DatabaseProvider.kt index 372f1a28b6..d60391cc05 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/DatabaseProvider.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/DatabaseProvider.kt @@ -8,20 +8,19 @@ import com.onesignal.session.internal.outcomes.impl.OutcomeTableProvider internal class DatabaseProvider( private val _application: IApplicationService, ) : IDatabaseProvider { - - private val _lock = Any() - private var _osDatabase: OSDatabase? = null + private val lock = Any() + private var osDatabase: OSDatabase? = null override val os: IDatabase get() { - if (_osDatabase == null) { - synchronized(_lock) { - if (_osDatabase == null) { - _osDatabase = OSDatabase(OutcomeTableProvider(), _application.appContext) + if (osDatabase == null) { + synchronized(lock) { + if (osDatabase == null) { + osDatabase = OSDatabase(OutcomeTableProvider(), _application.appContext) } } } - return _osDatabase!! + return osDatabase!! } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/OSDatabase.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/OSDatabase.kt index 19013624a8..08e8639306 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/OSDatabase.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/database/impl/OSDatabase.kt @@ -23,9 +23,8 @@ import com.onesignal.session.internal.outcomes.impl.OutcomesDbContract.SQL_CREAT internal open class OSDatabase( private val _outcomeTableProvider: OutcomeTableProvider, context: Context?, - version: Int = dbVersion, + version: Int = DB_VERSION, ) : SQLiteOpenHelper(context, DATABASE_NAME, null, version), IDatabase { - /** * Should be used in the event that we don't want to retry getting the a [SQLiteDatabase] instance * Replaced all [SQLiteOpenHelper.getReadableDatabase] with [SQLiteOpenHelper.getWritableDatabase] @@ -90,26 +89,28 @@ internal open class OSDatabase( val cursor: Cursor synchronized(LOCK) { if (limit == null) { - cursor = getSQLiteDatabaseWithRetries().query( - table, - columns, - whereClause, - whereArgs, - groupBy, - having, - orderBy, - ) + cursor = + getSQLiteDatabaseWithRetries().query( + table, + columns, + whereClause, + whereArgs, + groupBy, + having, + orderBy, + ) } else { - cursor = getSQLiteDatabaseWithRetries().query( - table, - columns, - whereClause, - whereArgs, - groupBy, - having, - orderBy, - limit, - ) + cursor = + getSQLiteDatabaseWithRetries().query( + table, + columns, + whereClause, + whereArgs, + groupBy, + having, + orderBy, + limit, + ) } } @@ -119,7 +120,11 @@ internal open class OSDatabase( } } - override fun insert(table: String, nullColumnHack: String?, values: ContentValues?) { + override fun insert( + table: String, + nullColumnHack: String?, + values: ContentValues?, + ) { synchronized(LOCK) { val writableDb = getSQLiteDatabaseWithRetries() try { @@ -149,7 +154,11 @@ internal open class OSDatabase( } @Throws(SQLException::class) - override fun insertOrThrow(table: String, nullColumnHack: String?, values: ContentValues?) { + override fun insertOrThrow( + table: String, + nullColumnHack: String?, + values: ContentValues?, + ) { synchronized(LOCK) { val writableDb = getSQLiteDatabaseWithRetries() try { @@ -215,7 +224,11 @@ internal open class OSDatabase( return result } - override fun delete(table: String, whereClause: String?, whereArgs: Array?) { + override fun delete( + table: String, + whereClause: String?, + whereArgs: Array?, + ) { synchronized(LOCK) { val writableDb = getSQLiteDatabaseWithRetries() try { @@ -254,7 +267,11 @@ internal open class OSDatabase( } } - override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + override fun onUpgrade( + db: SQLiteDatabase, + oldVersion: Int, + newVersion: Int, + ) { Logging.debug("OneSignal Database onUpgrade from: $oldVersion to: $newVersion") try { @@ -267,7 +284,11 @@ internal open class OSDatabase( } @Synchronized - private fun internalOnUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + private fun internalOnUpgrade( + db: SQLiteDatabase, + oldVersion: Int, + newVersion: Int, + ) { if (oldVersion < 2 && newVersion >= 2) upgradeToV2(db) if (oldVersion < 3 && newVersion >= 3) upgradeToV3(db) if (oldVersion < 4 && newVersion >= 4) upgradeToV4(db) @@ -329,7 +350,10 @@ internal open class OSDatabase( safeExecSQL(db, SQL_CREATE_IN_APP_MESSAGE_ENTRIES) } - private fun safeExecSQL(db: SQLiteDatabase, sql: String) { + private fun safeExecSQL( + db: SQLiteDatabase, + sql: String, + ) { try { db.execSQL(sql) } catch (e: SQLiteException) { @@ -347,7 +371,11 @@ internal open class OSDatabase( _outcomeTableProvider.upgradeOutcomeTableRevision3To4(db) } - override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + override fun onDowngrade( + db: SQLiteDatabase, + oldVersion: Int, + newVersion: Int, + ) { Logging.warn("SDK version rolled back! Clearing $DATABASE_NAME as it could be in an unexpected state.") db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null).use { @@ -362,7 +390,7 @@ internal open class OSDatabase( } companion object { - private const val dbVersion = 9 + private const val DB_VERSION = 9 private val LOCK = Any() private const val DATABASE_NAME = "OneSignal.db" private const val INTEGER_PRIMARY_KEY_TYPE = " INTEGER PRIMARY KEY" @@ -398,14 +426,15 @@ internal open class OSDatabase( OneSignalDbContract.InAppMessageTable.COLUMN_DISPLAYED_IN_SESSION + INT_TYPE + COMMA_SEP + OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS + TEXT_TYPE + ");" - private val SQL_INDEX_ENTRIES = arrayOf( - OneSignalDbContract.NotificationTable.INDEX_CREATE_NOTIFICATION_ID, - OneSignalDbContract.NotificationTable.INDEX_CREATE_ANDROID_NOTIFICATION_ID, - OneSignalDbContract.NotificationTable.INDEX_CREATE_GROUP_ID, - OneSignalDbContract.NotificationTable.INDEX_CREATE_COLLAPSE_ID, - OneSignalDbContract.NotificationTable.INDEX_CREATE_CREATED_TIME, - OneSignalDbContract.NotificationTable.INDEX_CREATE_EXPIRE_TIME, - ) + private val SQL_INDEX_ENTRIES = + arrayOf( + OneSignalDbContract.NotificationTable.INDEX_CREATE_NOTIFICATION_ID, + OneSignalDbContract.NotificationTable.INDEX_CREATE_ANDROID_NOTIFICATION_ID, + OneSignalDbContract.NotificationTable.INDEX_CREATE_GROUP_ID, + OneSignalDbContract.NotificationTable.INDEX_CREATE_COLLAPSE_ID, + OneSignalDbContract.NotificationTable.INDEX_CREATE_CREATED_TIME, + OneSignalDbContract.NotificationTable.INDEX_CREATE_EXPIRE_TIME, + ) const val DEFAULT_TTL_IF_NOT_IN_PAYLOAD = 259_200 } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/device/impl/DeviceService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/device/impl/DeviceService.kt index e9f15aaf8c..07d9141824 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/device/impl/DeviceService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/device/impl/DeviceService.kt @@ -134,7 +134,11 @@ internal class DeviceService(private val _applicationService: IApplicationServic return try { val clazz = Class.forName("com.huawei.hms.api.HuaweiApiAvailability") val newInstanceMethod = clazz.getMethod("getInstance") - val isHuaweiMobileServicesAvailableMethod = clazz.getMethod("isHuaweiMobileServicesAvailable", android.content.Context::class.java) + val isHuaweiMobileServicesAvailableMethod = + clazz.getMethod( + "isHuaweiMobileServicesAvailable", + android.content.Context::class.java, + ) val availabilityInstance = newInstanceMethod.invoke(null) val result = isHuaweiMobileServicesAvailableMethod.invoke(availabilityInstance, _applicationService.appContext) as Int diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/HttpResponse.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/HttpResponse.kt index ca85b7199a..ccb2f955b1 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/HttpResponse.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/HttpResponse.kt @@ -10,18 +10,15 @@ class HttpResponse( * The status code of the response ([HttpURLConnection.HTTP_OK] as an example). */ val statusCode: Int, - /** * The optional response payload. */ val payload: String?, - /** * When non-null, the throwable that was thrown during processing. */ val throwable: Throwable? = null, ) { - /** * Whether the response is a successful one. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/IHttpClient.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/IHttpClient.kt index 4f528a1bb6..7232b43a34 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/IHttpClient.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/IHttpClient.kt @@ -15,7 +15,10 @@ interface IHttpClient { * * @return The response returned. */ - suspend fun post(url: String, body: JSONObject): HttpResponse + suspend fun post( + url: String, + body: JSONObject, + ): HttpResponse /** * Make a GET request to the provided [url]. @@ -28,7 +31,10 @@ interface IHttpClient { * * @return The response returned. */ - suspend fun get(url: String, cacheKey: String? = null): HttpResponse + suspend fun get( + url: String, + cacheKey: String? = null, + ): HttpResponse /** * Make a PUT request to the provided [url] with the provided [body]. @@ -38,7 +44,10 @@ interface IHttpClient { * * @return The response returned. */ - suspend fun put(url: String, body: JSONObject): HttpResponse + suspend fun put( + url: String, + body: JSONObject, + ): HttpResponse /** * Make a PATCH request to the provided [url] with the provided [body]. @@ -48,7 +57,10 @@ interface IHttpClient { * * @return The response returned. */ - suspend fun patch(url: String, body: JSONObject): HttpResponse + suspend fun patch( + url: String, + body: JSONObject, + ): HttpResponse /** * Make a DELETE request to the provided [url]. diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/impl/HttpClient.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/impl/HttpClient.kt index 163aa3845e..952f843542 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/impl/HttpClient.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/impl/HttpClient.kt @@ -30,19 +30,31 @@ internal class HttpClient( private val _prefs: IPreferencesService, private val _configModelStore: ConfigModelStore, ) : IHttpClient { - override suspend fun post(url: String, body: JSONObject): HttpResponse { + override suspend fun post( + url: String, + body: JSONObject, + ): HttpResponse { return makeRequest(url, "POST", body, _configModelStore.model.httpTimeout, null) } - override suspend fun get(url: String, cacheKey: String?): HttpResponse { + override suspend fun get( + url: String, + cacheKey: String?, + ): HttpResponse { return makeRequest(url, null, null, _configModelStore.model.httpGetTimeout, cacheKey) } - override suspend fun put(url: String, body: JSONObject): HttpResponse { + override suspend fun put( + url: String, + body: JSONObject, + ): HttpResponse { return makeRequest(url, "PUT", body, _configModelStore.model.httpTimeout, null) } - override suspend fun patch(url: String, body: JSONObject): HttpResponse { + override suspend fun patch( + url: String, + body: JSONObject, + ): HttpResponse { return makeRequest(url, "PATCH", body, _configModelStore.model.httpTimeout, null) } @@ -59,7 +71,9 @@ internal class HttpClient( ): HttpResponse { // If privacy consent is required but not yet given, any non-GET request should be blocked. if (method != null && _configModelStore.model.consentRequired == true && _configModelStore.model.consentGiven != true) { - Logging.warn("$method `$url` was called before the user provided privacy consent. Your application is set to require the user's privacy consent before the OneSignal SDK can be initialized. Please ensure the user has provided consent before calling this method. You can check the latest OneSignal consent status by calling OneSignal.privacyConsent") + Logging.warn( + "$method `$url` was called before the user provided privacy consent. Your application is set to require the user's privacy consent before the OneSignal SDK can be initialized. Please ensure the user has provided consent before calling this method. You can check the latest OneSignal consent status by calling OneSignal.privacyConsent", + ) return HttpResponse(0, null, null) } @@ -85,138 +99,151 @@ internal class HttpClient( ): HttpResponse { var retVal: HttpResponse? = null - val job = GlobalScope.launch(Dispatchers.IO) { - var httpResponse = -1 - var con: HttpURLConnection? = null - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - TrafficStats.setThreadStatsTag(THREAD_ID) - } + val job = + GlobalScope.launch(Dispatchers.IO) { + var httpResponse = -1 + var con: HttpURLConnection? = null - try { - con = _connectionFactory.newHttpURLConnection(url) - - // https://github.com/OneSignal/OneSignal-Android-SDK/issues/1465 - // Android 4.4 and older devices fail to register to onesignal.com to due it's TLS1.2+ requirement - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1 && con is HttpsURLConnection) { - val conHttps = con - conHttps.sslSocketFactory = - TLS12SocketFactory( - conHttps.sslSocketFactory, - ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + TrafficStats.setThreadStatsTag(THREAD_ID) } - con.useCaches = false - con.connectTimeout = timeout - con.readTimeout = timeout - con.setRequestProperty("SDK-Version", "onesignal/android/" + OneSignalUtils.sdkVersion) - - if (OneSignalWrapper.sdkType != null && OneSignalWrapper.sdkVersion != null) { - con.setRequestProperty("SDK-Wrapper", "onesignal/${OneSignalWrapper.sdkType}/${OneSignalWrapper.sdkVersion}") - } + try { + con = _connectionFactory.newHttpURLConnection(url) + + // https://github.com/OneSignal/OneSignal-Android-SDK/issues/1465 + // Android 4.4 and older devices fail to register to onesignal.com to due it's TLS1.2+ requirement + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1 && con is HttpsURLConnection) { + val conHttps = con + conHttps.sslSocketFactory = + TLS12SocketFactory( + conHttps.sslSocketFactory, + ) + } - con.setRequestProperty("Accept", OS_ACCEPT_HEADER) + con.useCaches = false + con.connectTimeout = timeout + con.readTimeout = timeout + con.setRequestProperty("SDK-Version", "onesignal/android/" + OneSignalUtils.SDK_VERSION) - val subscriptionId = _configModelStore.model.pushSubscriptionId - if (subscriptionId != null && subscriptionId.isNotEmpty()) { - con.setRequestProperty("OneSignal-Subscription-Id", subscriptionId) - } + if (OneSignalWrapper.sdkType != null && OneSignalWrapper.sdkVersion != null) { + con.setRequestProperty("SDK-Wrapper", "onesignal/${OneSignalWrapper.sdkType}/${OneSignalWrapper.sdkVersion}") + } - if (jsonBody != null) { - con.doInput = true - } + con.setRequestProperty("Accept", OS_ACCEPT_HEADER) - if (method != null) { - con.setRequestProperty("Content-Type", "application/json; charset=UTF-8") - con.requestMethod = method - con.doOutput = true - } + val subscriptionId = _configModelStore.model.pushSubscriptionId + if (subscriptionId != null && subscriptionId.isNotEmpty()) { + con.setRequestProperty("OneSignal-Subscription-Id", subscriptionId) + } - if (jsonBody != null) { - val strJsonBody = JSONUtils.toUnescapedEUIDString(jsonBody) - Logging.debug("HttpClient: ${method ?: "GET"} $url - $strJsonBody") + if (jsonBody != null) { + con.doInput = true + } - val sendBytes = strJsonBody.toByteArray(charset("UTF-8")) - con.setFixedLengthStreamingMode(sendBytes.size) - val outputStream = con.outputStream - outputStream.write(sendBytes) - } else { - Logging.debug("HttpClient: ${method ?: "GET"} $url") - } + if (method != null) { + con.setRequestProperty("Content-Type", "application/json; charset=UTF-8") + con.requestMethod = method + con.doOutput = true + } - if (cacheKey != null) { - val eTag = _prefs.getString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_ETAG_PREFIX + cacheKey) + if (jsonBody != null) { + val strJsonBody = JSONUtils.toUnescapedEUIDString(jsonBody) + Logging.debug("HttpClient: ${method ?: "GET"} $url - $strJsonBody") - if (eTag != null) { - con.setRequestProperty("if-none-match", eTag) - Logging.debug("HttpClient: Adding header if-none-match: $eTag") + val sendBytes = strJsonBody.toByteArray(charset("UTF-8")) + con.setFixedLengthStreamingMode(sendBytes.size) + val outputStream = con.outputStream + outputStream.write(sendBytes) + } else { + Logging.debug("HttpClient: ${method ?: "GET"} $url") } - } - - // Network request is made from getResponseCode() - httpResponse = con.responseCode - when (httpResponse) { - HttpURLConnection.HTTP_NOT_MODIFIED -> { - val cachedResponse = _prefs.getString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_HTTP_CACHE_PREFIX + cacheKey) - Logging.debug("HttpClient: ${method ?: "GET"} $url - Using Cached response due to 304: " + cachedResponse) + if (cacheKey != null) { + val eTag = _prefs.getString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_ETAG_PREFIX + cacheKey) - // TODO: SHOULD RETURN OK INSTEAD OF NOT_MODIFIED TO MAKE TRANSPARENT? - retVal = HttpResponse(httpResponse, cachedResponse) - } - HttpURLConnection.HTTP_ACCEPTED, HttpURLConnection.HTTP_CREATED, HttpURLConnection.HTTP_OK -> { - val inputStream = con.inputStream - val scanner = Scanner(inputStream, "UTF-8") - val json = if (scanner.useDelimiter("\\A").hasNext()) scanner.next() else "" - scanner.close() - Logging.debug("HttpClient: ${method ?: "GET"} $url - STATUS: $httpResponse JSON: " + json) - - if (cacheKey != null) { - val eTag = con.getHeaderField("etag") - if (eTag != null) { - Logging.debug("HttpClient: Response has etag of $eTag so caching the response.") - - _prefs.saveString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_ETAG_PREFIX + cacheKey, eTag) - _prefs.saveString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_HTTP_CACHE_PREFIX + cacheKey, json) - } + if (eTag != null) { + con.setRequestProperty("if-none-match", eTag) + Logging.debug("HttpClient: Adding header if-none-match: $eTag") } - - retVal = HttpResponse(httpResponse, json) } - else -> { - Logging.debug("HttpClient: ${method ?: "GET"} $url - FAILED STATUS: $httpResponse") - var inputStream = con.errorStream - if (inputStream == null) { - inputStream = con.inputStream - } + // Network request is made from getResponseCode() + httpResponse = con.responseCode + + when (httpResponse) { + HttpURLConnection.HTTP_NOT_MODIFIED -> { + val cachedResponse = + _prefs.getString( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_HTTP_CACHE_PREFIX + cacheKey, + ) + Logging.debug("HttpClient: ${method ?: "GET"} $url - Using Cached response due to 304: " + cachedResponse) - var jsonResponse: String? = null - if (inputStream != null) { + // TODO: SHOULD RETURN OK INSTEAD OF NOT_MODIFIED TO MAKE TRANSPARENT? + retVal = HttpResponse(httpResponse, cachedResponse) + } + HttpURLConnection.HTTP_ACCEPTED, HttpURLConnection.HTTP_CREATED, HttpURLConnection.HTTP_OK -> { + val inputStream = con.inputStream val scanner = Scanner(inputStream, "UTF-8") - jsonResponse = - if (scanner.useDelimiter("\\A").hasNext()) scanner.next() else "" + val json = if (scanner.useDelimiter("\\A").hasNext()) scanner.next() else "" scanner.close() - Logging.warn("HttpClient: $method RECEIVED JSON: $jsonResponse") - } else { - Logging.warn("HttpClient: $method HTTP Code: $httpResponse No response body!") + Logging.debug("HttpClient: ${method ?: "GET"} $url - STATUS: $httpResponse JSON: " + json) + + if (cacheKey != null) { + val eTag = con.getHeaderField("etag") + if (eTag != null) { + Logging.debug("HttpClient: Response has etag of $eTag so caching the response.") + + _prefs.saveString( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_ETAG_PREFIX + cacheKey, + eTag, + ) + _prefs.saveString( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_HTTP_CACHE_PREFIX + cacheKey, + json, + ) + } + } + + retVal = HttpResponse(httpResponse, json) } + else -> { + Logging.debug("HttpClient: ${method ?: "GET"} $url - FAILED STATUS: $httpResponse") - retVal = HttpResponse(httpResponse, jsonResponse) + var inputStream = con.errorStream + if (inputStream == null) { + inputStream = con.inputStream + } + + var jsonResponse: String? = null + if (inputStream != null) { + val scanner = Scanner(inputStream, "UTF-8") + jsonResponse = + if (scanner.useDelimiter("\\A").hasNext()) scanner.next() else "" + scanner.close() + Logging.warn("HttpClient: $method RECEIVED JSON: $jsonResponse") + } else { + Logging.warn("HttpClient: $method HTTP Code: $httpResponse No response body!") + } + + retVal = HttpResponse(httpResponse, jsonResponse) + } + } + } catch (t: Throwable) { + if (t is ConnectException || t is UnknownHostException) { + Logging.info("HttpClient: Could not send last request, device is offline. Throwable: " + t.javaClass.name) + } else { + Logging.warn("HttpClient: $method Error thrown from network stack. ", t) } - } - } catch (t: Throwable) { - if (t is ConnectException || t is UnknownHostException) { - Logging.info("HttpClient: Could not send last request, device is offline. Throwable: " + t.javaClass.name) - } else { - Logging.warn("HttpClient: $method Error thrown from network stack. ", t) - } - retVal = HttpResponse(httpResponse, null, t) - } finally { - con?.disconnect() + retVal = HttpResponse(httpResponse, null, t) + } finally { + con?.disconnect() + } } - } job.join() return retVal!! diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/impl/TLS12SocketFactory.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/impl/TLS12SocketFactory.kt index c67647e9cc..97383fc5c8 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/impl/TLS12SocketFactory.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/impl/TLS12SocketFactory.kt @@ -21,12 +21,20 @@ internal class TLS12SocketFactory(var sslSocketFactory: SSLSocketFactory) : SSLS } @Throws(IOException::class) - override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket { + override fun createSocket( + s: Socket, + host: String, + port: Int, + autoClose: Boolean, + ): Socket { return enableTLS(sslSocketFactory.createSocket(s, host, port, autoClose)) } @Throws(IOException::class) - override fun createSocket(host: String, port: Int): Socket { + override fun createSocket( + host: String, + port: Int, + ): Socket { return enableTLS(sslSocketFactory.createSocket(host, port)) } @@ -41,7 +49,10 @@ internal class TLS12SocketFactory(var sslSocketFactory: SSLSocketFactory) : SSLS } @Throws(IOException::class) - override fun createSocket(host: InetAddress, port: Int): Socket { + override fun createSocket( + host: InetAddress, + port: Int, + ): Socket { return enableTLS(sslSocketFactory.createSocket(host, port)) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/language/impl/LanguageContext.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/language/impl/LanguageContext.kt index 918f3957a4..a04f0be525 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/language/impl/LanguageContext.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/language/impl/LanguageContext.kt @@ -6,10 +6,11 @@ import com.onesignal.user.internal.properties.PropertiesModelStore internal class LanguageContext( private val _propertiesModelStore: PropertiesModelStore, ) : ILanguageContext { - - private var _deviceLanguageProvider = LanguageProviderDevice() + private var deviceLanguageProvider = LanguageProviderDevice() override var language: String - get() = _propertiesModelStore.model.language ?: _deviceLanguageProvider.language - set(value) { _propertiesModelStore.model.language = value } + get() = _propertiesModelStore.model.language ?: deviceLanguageProvider.language + set(value) { + _propertiesModelStore.model.language = value + } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationExecutor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationExecutor.kt index e27c49421e..590d24e0c5 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationExecutor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationExecutor.kt @@ -8,7 +8,6 @@ package com.onesignal.core.internal.operations * to execute a group of operations in batch. */ interface IOperationExecutor { - /** * The list of operations that this executor can handle execution. */ @@ -29,13 +28,11 @@ class ExecutionResponse( * The result of the execution */ val result: ExecutionResult, - /** * The map of id translations that should be applied to any outstanding operations. * Within the map the key is the local Id, the value is the remote Id. */ val idTranslations: Map? = null, - /** * When specified, any operations that should be prepended to the operation repo. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationRepo.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationRepo.kt index 66560eb1f6..9c28d1e81f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationRepo.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationRepo.kt @@ -13,7 +13,10 @@ interface IOperationRepo { * @param operation The operation that should be executed. * @param flush Whether to force-flush the operation queue. */ - fun enqueue(operation: Operation, flush: Boolean = false) + fun enqueue( + operation: Operation, + flush: Boolean = false, + ) /** * Enqueue an operation onto the operation repo and "wait" until the operation @@ -24,5 +27,8 @@ interface IOperationRepo { * * @return true if the operation executed successfully, false otherwise. */ - suspend fun enqueueAndWait(operation: Operation, flush: Boolean = false): Boolean + suspend fun enqueueAndWait( + operation: Operation, + flush: Boolean = false, + ): Boolean } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/Operation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/Operation.kt index c03aded4c5..42fdd62374 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/Operation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/Operation.kt @@ -12,7 +12,9 @@ import com.onesignal.common.modeling.Model abstract class Operation(name: String) : Model() { var name: String get() = getStringProperty(::name.name) - private set(value) { setStringProperty(::name.name, value) } + private set(value) { + setStringProperty(::name.name, value) + } init { this.name = name diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationModelStore.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationModelStore.kt index 4577ad7b0f..ec90751823 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationModelStore.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationModelStore.kt @@ -8,8 +8,8 @@ import com.onesignal.user.internal.operations.CreateSubscriptionOperation import com.onesignal.user.internal.operations.DeleteAliasOperation import com.onesignal.user.internal.operations.DeleteSubscriptionOperation import com.onesignal.user.internal.operations.DeleteTagOperation -import com.onesignal.user.internal.operations.LoginUserOperation import com.onesignal.user.internal.operations.LoginUserFromSubscriptionOperation +import com.onesignal.user.internal.operations.LoginUserOperation import com.onesignal.user.internal.operations.RefreshUserOperation import com.onesignal.user.internal.operations.SetAliasOperation import com.onesignal.user.internal.operations.SetPropertyOperation @@ -28,7 +28,6 @@ import com.onesignal.user.internal.operations.impl.executors.UpdateUserOperation import org.json.JSONObject internal class OperationModelStore(prefs: IPreferencesService) : ModelStore("operations", prefs) { - init { load() } @@ -45,24 +44,25 @@ internal class OperationModelStore(prefs: IPreferencesService) : ModelStore SetAliasOperation() - IdentityOperationExecutor.DELETE_ALIAS -> DeleteAliasOperation() - SubscriptionOperationExecutor.CREATE_SUBSCRIPTION -> CreateSubscriptionOperation() - SubscriptionOperationExecutor.UPDATE_SUBSCRIPTION -> UpdateSubscriptionOperation() - SubscriptionOperationExecutor.DELETE_SUBSCRIPTION -> DeleteSubscriptionOperation() - SubscriptionOperationExecutor.TRANSFER_SUBSCRIPTION -> TransferSubscriptionOperation() - LoginUserOperationExecutor.LOGIN_USER -> LoginUserOperation() - LoginUserFromSubscriptionOperationExecutor.LOGIN_USER_FROM_SUBSCRIPTION_USER -> LoginUserFromSubscriptionOperation() - RefreshUserOperationExecutor.REFRESH_USER -> RefreshUserOperation() - UpdateUserOperationExecutor.SET_TAG -> SetTagOperation() - UpdateUserOperationExecutor.DELETE_TAG -> DeleteTagOperation() - UpdateUserOperationExecutor.SET_PROPERTY -> SetPropertyOperation() - UpdateUserOperationExecutor.TRACK_SESSION_START -> TrackSessionStartOperation() - UpdateUserOperationExecutor.TRACK_SESSION_END -> TrackSessionEndOperation() - UpdateUserOperationExecutor.TRACK_PURCHASE -> TrackPurchaseOperation() - else -> throw Exception("Unrecognized operation: $operationName") - } + val operation = + when (val operationName = jsonObject.getString(Operation::name.name)) { + IdentityOperationExecutor.SET_ALIAS -> SetAliasOperation() + IdentityOperationExecutor.DELETE_ALIAS -> DeleteAliasOperation() + SubscriptionOperationExecutor.CREATE_SUBSCRIPTION -> CreateSubscriptionOperation() + SubscriptionOperationExecutor.UPDATE_SUBSCRIPTION -> UpdateSubscriptionOperation() + SubscriptionOperationExecutor.DELETE_SUBSCRIPTION -> DeleteSubscriptionOperation() + SubscriptionOperationExecutor.TRANSFER_SUBSCRIPTION -> TransferSubscriptionOperation() + LoginUserOperationExecutor.LOGIN_USER -> LoginUserOperation() + LoginUserFromSubscriptionOperationExecutor.LOGIN_USER_FROM_SUBSCRIPTION_USER -> LoginUserFromSubscriptionOperation() + RefreshUserOperationExecutor.REFRESH_USER -> RefreshUserOperation() + UpdateUserOperationExecutor.SET_TAG -> SetTagOperation() + UpdateUserOperationExecutor.DELETE_TAG -> DeleteTagOperation() + UpdateUserOperationExecutor.SET_PROPERTY -> SetPropertyOperation() + UpdateUserOperationExecutor.TRACK_SESSION_START -> TrackSessionStartOperation() + UpdateUserOperationExecutor.TRACK_SESSION_END -> TrackSessionEndOperation() + UpdateUserOperationExecutor.TRACK_PURCHASE -> TrackPurchaseOperation() + else -> throw Exception("Unrecognized operation: $operationName") + } // populate the operation with the data. operation.initializeFromJson(jsonObject) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt index 937fc037ea..cb478cd0fb 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt @@ -22,15 +22,14 @@ internal class OperationRepo( private val _configModelStore: ConfigModelStore, private val _time: ITime, ) : IOperationRepo, IStartableService { - private class OperationQueueItem( val operation: Operation, val waiter: WaiterWithValue? = null, ) - private val _executorsMap: Map - private val _queue = mutableListOf() - private val _waiter = WaiterWithValue() + private val executorsMap: Map + private val queue = mutableListOf() + private val waiter = WaiterWithValue() init { val executorsMap: MutableMap = mutableMapOf() @@ -40,7 +39,7 @@ internal class OperationRepo( executorsMap[operation] = executor } } - _executorsMap = executorsMap + this.executorsMap = executorsMap for (operation in _operationModelStore.list()) { internalEnqueue(OperationQueueItem(operation), flush = false, addToStore = false) @@ -53,14 +52,20 @@ internal class OperationRepo( } } - override fun enqueue(operation: Operation, flush: Boolean) { + override fun enqueue( + operation: Operation, + flush: Boolean, + ) { Logging.log(LogLevel.DEBUG, "OperationRepo.enqueue(operation: $operation, flush: $flush)") operation.id = UUID.randomUUID().toString() internalEnqueue(OperationQueueItem(operation), flush, true) } - override suspend fun enqueueAndWait(operation: Operation, flush: Boolean): Boolean { + override suspend fun enqueueAndWait( + operation: Operation, + flush: Boolean, + ): Boolean { Logging.log(LogLevel.DEBUG, "OperationRepo.enqueueAndWait(operation: $operation, force: $flush)") operation.id = UUID.randomUUID().toString() @@ -69,15 +74,19 @@ internal class OperationRepo( return waiter.waitForWake() } - private fun internalEnqueue(queueItem: OperationQueueItem, flush: Boolean, addToStore: Boolean) { - synchronized(_queue) { - _queue.add(queueItem) + private fun internalEnqueue( + queueItem: OperationQueueItem, + flush: Boolean, + addToStore: Boolean, + ) { + synchronized(queue) { + queue.add(queueItem) if (addToStore) { _operationModelStore.add(queueItem.operation) } } - _waiter.wake(flush) + waiter.wake(flush) } /** @@ -93,11 +102,11 @@ internal class OperationRepo( try { var ops: List? = null - synchronized(_queue) { - val startingOp = _queue.firstOrNull { it.operation.canStartExecute } + synchronized(queue) { + val startingOp = queue.firstOrNull { it.operation.canStartExecute } if (startingOp != null) { - _queue.remove(startingOp) + queue.remove(startingOp) ops = getGroupableOperations(startingOp) } } @@ -105,7 +114,7 @@ internal class OperationRepo( // if the queue is empty at this point, we are no longer in force flush mode. We // check this now so if the execution is unsuccessful with retry, we don't find ourselves // continuously retrying without delaying. - if (_queue.isEmpty()) { + if (queue.isEmpty()) { force = false } @@ -123,7 +132,7 @@ internal class OperationRepo( if (delay > 0) { withTimeoutOrNull(delay) { // wait to be woken up for the next pass - force = _waiter.waitForWake() + force = waiter.waitForWake() } // This secondary delay allows for any subsequent operations (beyond the first one @@ -142,8 +151,9 @@ internal class OperationRepo( private suspend fun executeOperations(ops: List) { try { val startingOp = ops.first() - val executor = _executorsMap[startingOp.operation.name] - ?: throw Exception("Could not find executor for operation ${startingOp.operation.name}") + val executor = + executorsMap[startingOp.operation.name] + ?: throw Exception("Could not find executor for operation ${startingOp.operation.name}") val operations = ops.map { it.operation } val response = executor.execute(operations) @@ -154,8 +164,8 @@ internal class OperationRepo( // We also run through the ops just executed in case they are re-added to the queue. if (response.idTranslations != null) { ops.forEach { it.operation.translateIds(response.idTranslations) } - synchronized(_queue) { - _queue.forEach { it.operation.translateIds(response.idTranslations) } + synchronized(queue) { + queue.forEach { it.operation.translateIds(response.idTranslations) } } } @@ -179,14 +189,14 @@ internal class OperationRepo( // add back all but the starting op to the front of the queue to be re-executed _operationModelStore.remove(startingOp.operation.id) startingOp.waiter?.wake(true) - synchronized(_queue) { - ops.filter { it != startingOp }.reversed().forEach { _queue.add(0, it) } + synchronized(queue) { + ops.filter { it != startingOp }.reversed().forEach { queue.add(0, it) } } } ExecutionResult.FAIL_RETRY -> { // add back all operations to the front of the queue to be re-executed. - synchronized(_queue) { - ops.reversed().forEach { _queue.add(0, it) } + synchronized(queue) { + ops.reversed().forEach { queue.add(0, it) } } } } @@ -194,11 +204,11 @@ internal class OperationRepo( // if there are operations provided on the result, we need to enqueue them at the // beginning of the queue. if (response.operations != null) { - synchronized(_queue) { + synchronized(queue) { for (op in response.operations.reversed()) { op.id = UUID.randomUUID().toString() val queueItem = OperationQueueItem(op) - _queue.add(0, queueItem) + queue.add(0, queueItem) _operationModelStore.add(0, queueItem.operation) } } @@ -230,13 +240,13 @@ internal class OperationRepo( val startingKey = if (startingOp.operation.groupComparisonType == GroupComparisonType.CREATE) startingOp.operation.createComparisonKey else startingOp.operation.modifyComparisonKey - if (_queue.isNotEmpty()) { - for (item in _queue.toList()) { + if (queue.isNotEmpty()) { + for (item in queue.toList()) { val itemKey = if (startingOp.operation.groupComparisonType == GroupComparisonType.CREATE) item.operation.createComparisonKey else item.operation.modifyComparisonKey if (itemKey == startingKey) { - _queue.remove(item) + queue.remove(item) ops.add(item) } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/listeners/ModelStoreListener.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/listeners/ModelStoreListener.kt index 8e31d18ec0..e61df542aa 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/listeners/ModelStoreListener.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/listeners/ModelStoreListener.kt @@ -19,7 +19,6 @@ internal abstract class ModelStoreListener( private val store: IModelStore, private val opRepo: IOperationRepo, ) : IModelStoreChangeHandler, IBootstrapService, Closeable where TModel : Model { - override fun bootstrap() { store.subscribe(this) } @@ -28,7 +27,10 @@ internal abstract class ModelStoreListener( store.unsubscribe(this) } - override fun onModelAdded(model: TModel, tag: String) { + override fun onModelAdded( + model: TModel, + tag: String, + ) { if (tag != ModelChangeTags.NORMAL) { return } @@ -39,7 +41,10 @@ internal abstract class ModelStoreListener( } } - override fun onModelUpdated(args: ModelChangedArgs, tag: String) { + override fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) { if (tag != ModelChangeTags.NORMAL) { return } @@ -50,7 +55,10 @@ internal abstract class ModelStoreListener( } } - override fun onModelRemoved(model: TModel, tag: String) { + override fun onModelRemoved( + model: TModel, + tag: String, + ) { if (tag != ModelChangeTags.NORMAL) { return } @@ -80,5 +88,11 @@ internal abstract class ModelStoreListener( * * @return The operation to enqueue when the model has been updated, or null if no operation should be enqueued. */ - abstract fun getUpdateOperation(model: TModel, path: String, property: String, oldValue: Any?, newValue: Any?): Operation? + abstract fun getUpdateOperation( + model: TModel, + path: String, + property: String, + oldValue: Any?, + newValue: Any?, + ): Operation? } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/listeners/SingletonModelStoreListener.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/listeners/SingletonModelStoreListener.kt index 3a351dc619..26261d8db2 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/listeners/SingletonModelStoreListener.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/listeners/SingletonModelStoreListener.kt @@ -21,7 +21,6 @@ internal abstract class SingletonModelStoreListener( private val store: ISingletonModelStore, private val opRepo: IOperationRepo, ) : ISingletonModelStoreChangeHandler, IBootstrapService, Closeable where TModel : Model { - override fun bootstrap() { store.subscribe(this) } @@ -30,7 +29,10 @@ internal abstract class SingletonModelStoreListener( store.unsubscribe(this) } - override fun onModelReplaced(model: TModel, tag: String) { + override fun onModelReplaced( + model: TModel, + tag: String, + ) { if (tag != ModelChangeTags.NORMAL) { return } @@ -41,7 +43,10 @@ internal abstract class SingletonModelStoreListener( } } - override fun onModelUpdated(args: ModelChangedArgs, tag: String) { + override fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) { if (tag != ModelChangeTags.NORMAL) { return } @@ -64,5 +69,11 @@ internal abstract class SingletonModelStoreListener( * * @return The operation to enqueue when the model has been updated, or null if no operation should be enqueued. */ - abstract fun getUpdateOperation(model: TModel, path: String, property: String, oldValue: Any?, newValue: Any?): Operation? + abstract fun getUpdateOperation( + model: TModel, + path: String, + property: String, + oldValue: Any?, + newValue: Any?, + ): Operation? } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/AlertDialogPrepromptForAndroidSettings.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/AlertDialogPrepromptForAndroidSettings.kt index a85941858d..9e0d3af08b 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/AlertDialogPrepromptForAndroidSettings.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/AlertDialogPrepromptForAndroidSettings.kt @@ -35,9 +35,9 @@ import com.onesignal.core.R * A singleton helper which will display the fallback-to-settings alert dialog. */ object AlertDialogPrepromptForAndroidSettings { - interface Callback { fun onAccept() + fun onDecline() } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/IRequestPermissionService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/IRequestPermissionService.kt index 5d451307b2..b53748d6cd 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/IRequestPermissionService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/IRequestPermissionService.kt @@ -6,6 +6,7 @@ package com.onesignal.core.internal.permissions interface IRequestPermissionService { interface PermissionCallback { fun onAccept() + fun onReject(fallbackToSettings: Boolean) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/impl/RequestPermissionService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/impl/RequestPermissionService.kt index 59e3f3c73a..9131725281 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/impl/RequestPermissionService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/permissions/impl/RequestPermissionService.kt @@ -11,7 +11,6 @@ import com.onesignal.core.internal.permissions.IRequestPermissionService internal class RequestPermissionService( private val _application: IApplicationService, ) : Activity(), IRequestPermissionService { - var waiting = false var fallbackToSettings = false var shouldShowRequestPermissionRationaleBeforeRequest = false @@ -45,26 +44,28 @@ internal class RequestPermissionService( // current activity is changed. We keep trying to add the permission prompt whenever // an activity becomes available, until our permission activity is the one that's // available. - _application.addActivityLifecycleHandler(object : IActivityLifecycleHandler { - override fun onActivityAvailable(activity: Activity) { - if (activity.javaClass == PermissionsActivity::class.java) { - _application.removeActivityLifecycleHandler(this) - } else { - val intent = Intent(activity, PermissionsActivity::class.java) - intent.flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT - intent.putExtra(PermissionsActivity.INTENT_EXTRA_PERMISSION_TYPE, permissionRequestType) - .putExtra(PermissionsActivity.INTENT_EXTRA_ANDROID_PERMISSION_STRING, androidPermissionString) - .putExtra(PermissionsActivity.INTENT_EXTRA_CALLBACK_CLASS, callbackClass.name) - activity.startActivity(intent) - activity.overridePendingTransition( - R.anim.onesignal_fade_in, - R.anim.onesignal_fade_out, - ) + _application.addActivityLifecycleHandler( + object : IActivityLifecycleHandler { + override fun onActivityAvailable(activity: Activity) { + if (activity.javaClass == PermissionsActivity::class.java) { + _application.removeActivityLifecycleHandler(this) + } else { + val intent = Intent(activity, PermissionsActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT + intent.putExtra(PermissionsActivity.INTENT_EXTRA_PERMISSION_TYPE, permissionRequestType) + .putExtra(PermissionsActivity.INTENT_EXTRA_ANDROID_PERMISSION_STRING, androidPermissionString) + .putExtra(PermissionsActivity.INTENT_EXTRA_CALLBACK_CLASS, callbackClass.name) + activity.startActivity(intent) + activity.overridePendingTransition( + R.anim.onesignal_fade_in, + R.anim.onesignal_fade_out, + ) + } } - } - override fun onActivityStopped(activity: Activity) { - } - }) + override fun onActivityStopped(activity: Activity) { + } + }, + ) } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/preferences/IPreferencesService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/preferences/IPreferencesService.kt index 475dc43058..e53714c15c 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/preferences/IPreferencesService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/preferences/IPreferencesService.kt @@ -16,7 +16,11 @@ interface IPreferencesService { * * @return the value in the preference store, or [defValue] if not previously saved. */ - fun getString(store: String, key: String, defValue: String? = null): String? + fun getString( + store: String, + key: String, + defValue: String? = null, + ): String? /** * Retrieve a [Boolean] value identified by the [store] and [key] provided. @@ -27,7 +31,11 @@ interface IPreferencesService { * * @return the value in the preference store, or [defValue] if not previously saved. */ - fun getBool(store: String, key: String, defValue: Boolean? = null): Boolean? + fun getBool( + store: String, + key: String, + defValue: Boolean? = null, + ): Boolean? /** * Retrieve a [Int] value identified by the [store] and [key] provided. @@ -38,7 +46,11 @@ interface IPreferencesService { * * @return the value in the preference store, or [defValue] if not previously saved. */ - fun getInt(store: String, key: String, defValue: Int? = null): Int? + fun getInt( + store: String, + key: String, + defValue: Int? = null, + ): Int? /** * Retrieve a [Long] value identified by the [store] and [key] provided. @@ -49,7 +61,11 @@ interface IPreferencesService { * * @return the value in the preference store, or [defValue] if not previously saved. */ - fun getLong(store: String, key: String, defValue: Long? = null): Long? + fun getLong( + store: String, + key: String, + defValue: Long? = null, + ): Long? /** * Retrieve a [Set] of [String] value identified by the [store] and [key] provided. @@ -60,7 +76,11 @@ interface IPreferencesService { * * @return the value in the preference store, or [defValue] if not previously saved. */ - fun getStringSet(store: String, key: String, defValue: Set? = null): Set? + fun getStringSet( + store: String, + key: String, + defValue: Set? = null, + ): Set? /** * Save a [String] value identified by the [store] and [key] provided. @@ -69,7 +89,11 @@ interface IPreferencesService { * @param key The key to retrieve. * @param value The value to save. */ - fun saveString(store: String, key: String, value: String?) + fun saveString( + store: String, + key: String, + value: String?, + ) /** * Save a [Boolean] value identified by the [store] and [key] provided. @@ -78,7 +102,11 @@ interface IPreferencesService { * @param key The key to retrieve. * @param value The value to save. */ - fun saveBool(store: String, key: String, value: Boolean?) + fun saveBool( + store: String, + key: String, + value: Boolean?, + ) /** * Save a [Int] value identified by the [store] and [key] provided. @@ -87,7 +115,11 @@ interface IPreferencesService { * @param key The key to retrieve. * @param value The value to save. */ - fun saveInt(store: String, key: String, value: Int?) + fun saveInt( + store: String, + key: String, + value: Int?, + ) /** * Save a [Long] value identified by the [store] and [key] provided. @@ -96,7 +128,11 @@ interface IPreferencesService { * @param key The key to retrieve. * @param value The value to save. */ - fun saveLong(store: String, key: String, value: Long?) + fun saveLong( + store: String, + key: String, + value: Long?, + ) /** * Save a [Set] of [String] value identified by the [store] and [key] provided. @@ -105,7 +141,11 @@ interface IPreferencesService { * @param key The key to retrieve. * @param value The value to save. */ - fun saveStringSet(store: String, key: String, value: Set?) + fun saveStringSet( + store: String, + key: String, + value: Set?, + ) } object PreferenceStores { @@ -122,6 +162,7 @@ object PreferenceStores { object PreferencePlayerPurchasesKeys { // Player Purchase Keys + /** * (String) The purchase tokens that have been tracked. */ @@ -135,6 +176,7 @@ object PreferencePlayerPurchasesKeys { object PreferenceOneSignalKeys { // Legacy + /** * (String) The legacy player ID from SDKs prior to 5. */ @@ -146,12 +188,14 @@ object PreferenceOneSignalKeys { const val PREFS_LEGACY_USER_SYNCVALUES = "ONESIGNAL_USERSTATE_SYNCVALYES_CURRENT_STATE" // Location + /** * (Long) The last time the device location was captured, in Unix time milliseconds. */ const val PREFS_OS_LAST_LOCATION_TIME = "OS_LAST_LOCATION_TIME" // Permissions + /** * (Boolean) A prefix key for the permission state. When true, the user has rejected this * permission too many times and will not be prompted again. @@ -159,6 +203,7 @@ object PreferenceOneSignalKeys { const val PREFS_OS_USER_RESOLVED_PERMISSION_PREFIX = "USER_RESOLVED_PERMISSION_" // HTTP + /** * (String) A prefix key for retrieving the ETAG for a given HTTP GET cache key. The cache * key should be appended to this prefix. @@ -172,12 +217,14 @@ object PreferenceOneSignalKeys { const val PREFS_OS_HTTP_CACHE_PREFIX = "PREFS_OS_HTTP_CACHE_PREFIX_" // Outcomes + /** * (String Set) The set of unattributed outcome events that have occurred to ensure uniqueness when requested. */ const val PREFS_OS_UNATTRIBUTED_UNIQUE_OUTCOME_EVENTS_SENT = "PREFS_OS_UNATTRIBUTED_UNIQUE_OUTCOME_EVENTS_SENT" // In-App Messaging + /** * (String) The serialized IAMs TODO: This isn't currently used, determine if actually needed for cold start IAM fetch delay */ @@ -209,6 +256,7 @@ object PreferenceOneSignalKeys { const val PREFS_OS_IAM_LAST_DISMISSED_TIME = "PREFS_OS_IAM_LAST_DISMISSED_TIME" // Models + /** * (String) A prefix key for retrieving a specific model store contents. The name of the model * store should be appended to this prefix. diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/preferences/impl/PreferencesService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/preferences/impl/PreferencesService.kt index f66d602ab9..e0d4f34f19 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/preferences/impl/PreferencesService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/preferences/impl/PreferencesService.kt @@ -20,37 +20,109 @@ internal class PreferencesService( private val _applicationService: IApplicationService, private val _time: ITime, ) : IPreferencesService, IStartableService { - private val _prefsToApply: Map> = mapOf( - PreferenceStores.ONESIGNAL to mutableMapOf(), - PreferenceStores.PLAYER_PURCHASES to mutableMapOf(), - ) - private var _queueJob: Deferred? = null + private val prefsToApply: Map> = + mapOf( + PreferenceStores.ONESIGNAL to mutableMapOf(), + PreferenceStores.PLAYER_PURCHASES to mutableMapOf(), + ) + private var queueJob: Deferred? = null - private val _waiter = Waiter() + private val waiter = Waiter() override fun start() { // fire up an async job that will run "forever" so we don't hold up the other startable services. - _queueJob = doWorkAsync() + queueJob = doWorkAsync() } - override fun getString(store: String, key: String, defValue: String?): String? = get(store, key, String::class.java, defValue) as String? - override fun getBool(store: String, key: String, defValue: Boolean?): Boolean? = get(store, key, Boolean::class.java, defValue) as Boolean? - override fun getInt(store: String, key: String, defValue: Int?): Int? = get(store, key, Int::class.java, defValue) as Int? - override fun getLong(store: String, key: String, defValue: Long?): Long? = get(store, key, Long::class.java, defValue) as Long? - override fun getStringSet(store: String, key: String, defValue: Set?): Set? = get(store, key, Set::class.java, defValue) as Set? - - override fun saveString(store: String, key: String, value: String?) = save(store, key, value) - override fun saveBool(store: String, key: String, value: Boolean?) = save(store, key, value) - override fun saveInt(store: String, key: String, value: Int?) = save(store, key, value) - override fun saveLong(store: String, key: String, value: Long?) = save(store, key, value) - override fun saveStringSet(store: String, key: String, value: Set?) = save(store, key, value) - - private fun get(store: String, key: String, type: Class<*>, defValue: Any?): Any? { - if (!_prefsToApply.containsKey(store)) { + override fun getString( + store: String, + key: String, + defValue: String?, + ): String? = + get( + store, + key, + String::class.java, + defValue, + ) as String? + + override fun getBool( + store: String, + key: String, + defValue: Boolean?, + ): Boolean? = + get( + store, + key, + Boolean::class.java, + defValue, + ) as Boolean? + + override fun getInt( + store: String, + key: String, + defValue: Int?, + ): Int? = get(store, key, Int::class.java, defValue) as Int? + + override fun getLong( + store: String, + key: String, + defValue: Long?, + ): Long? = get(store, key, Long::class.java, defValue) as Long? + + override fun getStringSet( + store: String, + key: String, + defValue: Set?, + ): Set? = + get( + store, + key, + Set::class.java, + defValue, + ) as Set? + + override fun saveString( + store: String, + key: String, + value: String?, + ) = save(store, key, value) + + override fun saveBool( + store: String, + key: String, + value: Boolean?, + ) = save(store, key, value) + + override fun saveInt( + store: String, + key: String, + value: Int?, + ) = save(store, key, value) + + override fun saveLong( + store: String, + key: String, + value: Long?, + ) = save(store, key, value) + + override fun saveStringSet( + store: String, + key: String, + value: Set?, + ) = save(store, key, value) + + private fun get( + store: String, + key: String, + type: Class<*>, + defValue: Any?, + ): Any? { + if (!prefsToApply.containsKey(store)) { throw Exception("Store not found: $store") } - val storeMap = _prefsToApply[store]!! + val storeMap = prefsToApply[store]!! synchronized(storeMap) { val cachedValue = storeMap[key] @@ -85,72 +157,77 @@ internal class PreferencesService( } } - private fun save(store: String, key: String, value: Any?) { - if (!_prefsToApply.containsKey(store)) { + private fun save( + store: String, + key: String, + value: Any?, + ) { + if (!prefsToApply.containsKey(store)) { throw Exception("Store not found: $store") } - val storeMap = _prefsToApply[store]!! + val storeMap = prefsToApply[store]!! synchronized(storeMap) { storeMap[key] = value } - _waiter.wake() + waiter.wake() } - private fun doWorkAsync() = GlobalScope.async(Dispatchers.IO) { - var lastSyncTime = _time.currentTimeMillis - - while (true) { - try { - // go through all outstanding items to process - for (storeKey in _prefsToApply.keys) { - val storeMap = _prefsToApply[storeKey]!! - val prefsToWrite = getSharedPrefsByName(storeKey) - - if (prefsToWrite == null) { - // the assumption here is there is no context yet, but will be. So ensure - // we wake up to try again and persist the preference. - _waiter.wake() - continue - } + private fun doWorkAsync() = + GlobalScope.async(Dispatchers.IO) { + var lastSyncTime = _time.currentTimeMillis + + while (true) { + try { + // go through all outstanding items to process + for (storeKey in prefsToApply.keys) { + val storeMap = prefsToApply[storeKey]!! + val prefsToWrite = getSharedPrefsByName(storeKey) + + if (prefsToWrite == null) { + // the assumption here is there is no context yet, but will be. So ensure + // we wake up to try again and persist the preference. + waiter.wake() + continue + } - val editor = prefsToWrite.edit() - - synchronized(storeMap) { - for (key in storeMap.keys) { - when (val value = storeMap[key]) { - is String -> editor.putString(key, value as String?) - is Boolean -> editor.putBoolean(key, (value as Boolean?)!!) - is Int -> editor.putInt(key, (value as Int?)!!) - is Long -> editor.putLong(key, (value as Long?)!!) - is Set<*> -> editor.putStringSet(key, value as Set?) - null -> editor.remove(key) + val editor = prefsToWrite.edit() + + synchronized(storeMap) { + for (key in storeMap.keys) { + when (val value = storeMap[key]) { + is String -> editor.putString(key, value as String?) + is Boolean -> editor.putBoolean(key, (value as Boolean?)!!) + is Int -> editor.putInt(key, (value as Int?)!!) + is Long -> editor.putLong(key, (value as Long?)!!) + is Set<*> -> editor.putStringSet(key, value as Set?) + null -> editor.remove(key) + } } + storeMap.clear() } - storeMap.clear() + editor.apply() } - editor.apply() - } - // potentially delay to prevent this from constant IO if a bunch of - // preferences are set sequentially. - val newTime = _time.currentTimeMillis + // potentially delay to prevent this from constant IO if a bunch of + // preferences are set sequentially. + val newTime = _time.currentTimeMillis - val delay = lastSyncTime - newTime + WRITE_CALL_DELAY_TO_BUFFER_MS - lastSyncTime = newTime + val delay = lastSyncTime - newTime + WRITE_CALL_DELAY_TO_BUFFER_MS + lastSyncTime = newTime - if (delay > 0) { - delay(delay) - } + if (delay > 0) { + delay(delay) + } - // wait to be woken up for the next pass - _waiter.waitForWake() - } catch (e: Throwable) { - Logging.log(LogLevel.ERROR, "Error with Preference work loop", e) + // wait to be woken up for the next pass + waiter.waitForWake() + } catch (e: Throwable) { + Logging.log(LogLevel.ERROR, "Error with Preference work loop", e) + } } } - } @Synchronized private fun getSharedPrefsByName(store: String): SharedPreferences? { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackAmazonPurchase.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackAmazonPurchase.kt index 7afb2e8ca0..1b58f81852 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackAmazonPurchase.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackAmazonPurchase.kt @@ -149,6 +149,7 @@ internal class TrackAmazonPurchase( var orgPurchasingListener: PurchasingListener? = null private var lastRequestId: RequestId? = null private var currentMarket: String? = null + private fun marketToCurrencyCode(market: String?): String { when (market) { "US" -> return "USD" @@ -185,7 +186,15 @@ internal class TrackAmazonPurchase( purchasesToReport.add(PurchaseInfo(sku, iso, price)) } - _operationRepo.enqueue(TrackPurchaseOperation(_configModelStore.model.appId, _identityModelStore.model.onesignalId, false, amountSpent, purchasesToReport)) + _operationRepo.enqueue( + TrackPurchaseOperation( + _configModelStore.model.appId, + _identityModelStore.model.onesignalId, + false, + amountSpent, + purchasesToReport, + ), + ) } else -> { } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackGooglePurchase.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackGooglePurchase.kt index 1c24d27112..8a6f5b4a2e 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackGooglePurchase.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackGooglePurchase.kt @@ -75,7 +75,12 @@ internal class TrackGooglePurchase( } try { - val purchaseTokensString = _prefs.getString(PreferenceStores.PLAYER_PURCHASES, PreferencePlayerPurchasesKeys.PREFS_PURCHASE_TOKENS, "[]") + val purchaseTokensString = + _prefs.getString( + PreferenceStores.PLAYER_PURCHASES, + PreferencePlayerPurchasesKeys.PREFS_PURCHASE_TOKENS, + "[]", + ) val jsonPurchaseTokens = JSONArray(purchaseTokensString) for (i in 0 until jsonPurchaseTokens.length()) @@ -101,25 +106,29 @@ internal class TrackGooglePurchase( private fun trackIAP() { if (mServiceConn == null) { - val serviceConn = object : ServiceConnection { - override fun onServiceDisconnected(name: ComponentName) { - iapEnabled = -99 - mIInAppBillingService = null - } + val serviceConn = + object : ServiceConnection { + override fun onServiceDisconnected(name: ComponentName) { + iapEnabled = -99 + mIInAppBillingService = null + } - override fun onServiceConnected(name: ComponentName, service: IBinder) { - try { - val stubClass = - Class.forName("com.android.vending.billing.IInAppBillingService\$Stub") - val asInterfaceMethod = getAsInterfaceMethod(stubClass) - asInterfaceMethod!!.isAccessible = true - mIInAppBillingService = asInterfaceMethod.invoke(null, service) - queryBoughtItems() - } catch (t: Throwable) { - t.printStackTrace() + override fun onServiceConnected( + name: ComponentName, + service: IBinder, + ) { + try { + val stubClass = + Class.forName("com.android.vending.billing.IInAppBillingService\$Stub") + val asInterfaceMethod = getAsInterfaceMethod(stubClass) + asInterfaceMethod!!.isAccessible = true + mIInAppBillingService = asInterfaceMethod.invoke(null, service) + queryBoughtItems() + } catch (t: Throwable) { + t.printStackTrace() + } } } - } mServiceConn = serviceConn val serviceIntent = Intent("com.android.vending.billing.InAppBillingService.BIND") serviceIntent.setPackage("com.android.vending") @@ -135,16 +144,17 @@ internal class TrackGooglePurchase( isWaitingForPurchasesRequest = true try { if (getPurchasesMethod == null) { - getPurchasesMethod = getGetPurchasesMethod(IInAppBillingServiceClass) + getPurchasesMethod = getGetPurchasesMethod(iInAppBillingServiceClass) getPurchasesMethod!!.isAccessible = true } - val ownedItems = getPurchasesMethod!!.invoke( - mIInAppBillingService, - 3, - _applicationService.appContext.packageName, - "inapp", - null, - ) as Bundle + val ownedItems = + getPurchasesMethod!!.invoke( + mIInAppBillingService, + 3, + _applicationService.appContext.packageName, + "inapp", + null, + ) as Bundle if (ownedItems.getInt("RESPONSE_CODE") == 0) { val skusToAdd = ArrayList() val newPurchaseTokens = ArrayList() @@ -155,7 +165,8 @@ internal class TrackGooglePurchase( val sku = ownedSkus!![i] val itemPurchased = JSONObject(purchaseData) val purchaseToken = itemPurchased.getString("purchaseToken") - if (!purchaseTokens.contains(purchaseToken) && !newPurchaseTokens.contains( + if (!purchaseTokens.contains(purchaseToken) && + !newPurchaseTokens.contains( purchaseToken, ) ) { @@ -182,31 +193,35 @@ internal class TrackGooglePurchase( }.start() } - private fun sendPurchases(skusToAdd: ArrayList, newPurchaseTokens: ArrayList) { + private fun sendPurchases( + skusToAdd: ArrayList, + newPurchaseTokens: ArrayList, + ) { try { if (getSkuDetailsMethod == null) { - getSkuDetailsMethod = getGetSkuDetailsMethod(IInAppBillingServiceClass) + getSkuDetailsMethod = getGetSkuDetailsMethod(iInAppBillingServiceClass) getSkuDetailsMethod!!.isAccessible = true } val querySkus = Bundle() querySkus.putStringArrayList("ITEM_ID_LIST", skusToAdd) - val skuDetails = getSkuDetailsMethod!!.invoke( - mIInAppBillingService, - 3, - _applicationService.appContext.packageName, - "inapp", - querySkus, - ) as Bundle + val skuDetails = + getSkuDetailsMethod!!.invoke( + mIInAppBillingService, + 3, + _applicationService.appContext.packageName, + "inapp", + querySkus, + ) as Bundle val response = skuDetails.getInt("RESPONSE_CODE") if (response == 0) { val responseList = skuDetails.getStringArrayList("DETAILS_LIST") val currentSkus: MutableMap = mutableMapOf() for (thisResponse in responseList!!) { - val `object` = JSONObject(thisResponse) - val sku = `object`.getString("productId") - val iso = `object`.getString("price_currency_code") - var price = BigDecimal(`object`.getString("price_amount_micros")) + val responseObject = JSONObject(thisResponse) + val sku = responseObject.getString("productId") + val iso = responseObject.getString("price_currency_code") + var price = BigDecimal(responseObject.getString("price_amount_micros")) price = price.divide(BigDecimal(1000000)) currentSkus[sku] = PurchaseInfo(sku, iso, price) @@ -220,9 +235,21 @@ internal class TrackGooglePurchase( // New purchases to report. If successful then mark them as tracked. if (purchasesToReport.isNotEmpty()) { - _operationRepo.enqueue(TrackPurchaseOperation(_configModelStore.model.appId, _identityModelStore.model.onesignalId, newAsExisting, BigDecimal(0), purchasesToReport)) + _operationRepo.enqueue( + TrackPurchaseOperation( + _configModelStore.model.appId, + _identityModelStore.model.onesignalId, + newAsExisting, + BigDecimal(0), + purchasesToReport, + ), + ) purchaseTokens.addAll(newPurchaseTokens) - _prefs.saveString(PreferenceStores.PLAYER_PURCHASES, PreferencePlayerPurchasesKeys.PREFS_PURCHASE_TOKENS, purchaseTokens.toString()) + _prefs.saveString( + PreferenceStores.PLAYER_PURCHASES, + PreferencePlayerPurchasesKeys.PREFS_PURCHASE_TOKENS, + purchaseTokens.toString(), + ) _prefs.saveBool(PreferenceStores.PLAYER_PURCHASES, PreferencePlayerPurchasesKeys.PREFS_EXISTING_PURCHASES, true) newAsExisting = false isWaitingForPurchasesRequest = false @@ -235,7 +262,8 @@ internal class TrackGooglePurchase( companion object { private var iapEnabled = -99 - private var IInAppBillingServiceClass: Class<*>? = null + private var iInAppBillingServiceClass: Class<*>? = null + fun canTrack(context: Context): Boolean { if (iapEnabled == -99) { iapEnabled = @@ -243,7 +271,7 @@ internal class TrackGooglePurchase( } try { if (iapEnabled == PackageManager.PERMISSION_GRANTED) { - IInAppBillingServiceClass = + iInAppBillingServiceClass = Class.forName("com.android.vending.billing.IInAppBillingService") } } catch (t: Throwable) { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/startup/IStartableService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/startup/IStartableService.kt index 650e7449af..e2576f6625 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/startup/IStartableService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/startup/IStartableService.kt @@ -20,7 +20,6 @@ import com.onesignal.core.internal.config.ConfigModelStore * in the system. */ interface IStartableService { - /** * Called when the service is to be started. The appId and appContext have already been * established. diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/services/SyncService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/services/SyncService.kt index 1ebe0299e8..c051f7d79f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/services/SyncService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/services/SyncService.kt @@ -35,7 +35,11 @@ import com.onesignal.core.internal.background.IBackgroundManager import com.onesignal.debug.internal.logging.Logging class SyncService : Service() { - override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { + override fun onStartCommand( + intent: Intent, + flags: Int, + startId: Int, + ): Int { if (!OneSignal.initWithContext(this)) { return START_STICKY } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/debug/internal/DebugManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/debug/internal/DebugManager.kt index 9f792eff20..1067f0f7dc 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/debug/internal/DebugManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/debug/internal/DebugManager.kt @@ -7,11 +7,15 @@ import com.onesignal.debug.internal.logging.Logging internal class DebugManager() : IDebugManager { override var logLevel: LogLevel get() = Logging.logLevel - set(value) { Logging.logLevel = value } + set(value) { + Logging.logLevel = value + } override var alertLevel: LogLevel get() = Logging.visualLogLevel - set(value) { Logging.visualLogLevel = value } + set(value) { + Logging.visualLogLevel = value + } init { logLevel = LogLevel.WARN diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/debug/internal/logging/Logging.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/debug/internal/logging/Logging.kt index d453f99d31..1e085543ee 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/debug/internal/logging/Logging.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/debug/internal/logging/Logging.kt @@ -24,42 +24,67 @@ object Logging { } @JvmStatic - fun verbose(message: String, throwable: Throwable? = null) { + fun verbose( + message: String, + throwable: Throwable? = null, + ) { log(LogLevel.VERBOSE, message, throwable) } @JvmStatic - fun debug(message: String, throwable: Throwable? = null) { + fun debug( + message: String, + throwable: Throwable? = null, + ) { log(LogLevel.DEBUG, message, throwable) } @JvmStatic - fun info(message: String, throwable: Throwable? = null) { + fun info( + message: String, + throwable: Throwable? = null, + ) { log(LogLevel.INFO, message, throwable) } @JvmStatic - fun warn(message: String, throwable: Throwable? = null) { + fun warn( + message: String, + throwable: Throwable? = null, + ) { log(LogLevel.WARN, message, throwable) } @JvmStatic - fun error(message: String, throwable: Throwable? = null) { + fun error( + message: String, + throwable: Throwable? = null, + ) { log(LogLevel.ERROR, message, throwable) } @JvmStatic - fun fatal(message: String, throwable: Throwable? = null) { + fun fatal( + message: String, + throwable: Throwable? = null, + ) { log(LogLevel.FATAL, message, throwable) } @JvmStatic - fun log(level: LogLevel, message: String) { + fun log( + level: LogLevel, + message: String, + ) { log(level, message, null) } @JvmStatic - fun log(level: LogLevel, message: String, throwable: Throwable?) { + fun log( + level: LogLevel, + message: String, + throwable: Throwable?, + ) { val fullMessage = "[${Thread.currentThread().name}] $message" if (level.compareTo(logLevel) < 1) { when (level) { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageDidDismissEvent.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageDidDismissEvent.kt index 9b5884bd67..b4b6af255f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageDidDismissEvent.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageDidDismissEvent.kt @@ -5,7 +5,6 @@ package com.onesignal.inAppMessages * to the In App Message that has been dismissed. */ interface IInAppMessageDidDismissEvent { - /** * The In App Message that has been dismissed. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageDidDisplayEvent.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageDidDisplayEvent.kt index 8a4b3e1992..65d008fed1 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageDidDisplayEvent.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageDidDisplayEvent.kt @@ -5,7 +5,6 @@ package com.onesignal.inAppMessages * to the In App Message that has been displayed. */ interface IInAppMessageDidDisplayEvent { - /** * The In App Message that has been displayed. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageWillDismissEvent.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageWillDismissEvent.kt index f8fcf4d7aa..069187e8cc 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageWillDismissEvent.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageWillDismissEvent.kt @@ -5,7 +5,6 @@ package com.onesignal.inAppMessages * to the In App Message to be dismissed. */ interface IInAppMessageWillDismissEvent { - /** * The In App Message that is to be dismissed. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageWillDisplayEvent.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageWillDisplayEvent.kt index bec4ede80b..f575d41207 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageWillDisplayEvent.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessageWillDisplayEvent.kt @@ -5,7 +5,6 @@ package com.onesignal.inAppMessages * to the In App Message to be displayed. */ interface IInAppMessageWillDisplayEvent { - /** * The In App Message that is to be displayed. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessagesManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessagesManager.kt index f6da26a9b4..f338495726 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessagesManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/IInAppMessagesManager.kt @@ -7,7 +7,6 @@ package com.onesignal.inAppMessages * blanket disable IAMs, set [paused] to `true` on startup. */ interface IInAppMessagesManager { - /** * Whether the In-app messaging is currently paused. When set to `true` no IAM * will be presented to the user regardless of whether they qualify for them. When @@ -27,7 +26,10 @@ interface IInAppMessagesManager { * @param key The key of the trigger that is to be set. * @param value The value of the trigger. */ - fun addTrigger(key: String, value: String) + fun addTrigger( + key: String, + value: String, + ) /** * Add multiple triggers for the current user. Triggers are currently explicitly used to determine diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/InAppMessageActionUrlType.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/InAppMessageActionUrlType.kt index f6adc2e837..e315065fc8 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/InAppMessageActionUrlType.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/InAppMessageActionUrlType.kt @@ -7,7 +7,6 @@ package com.onesignal.inAppMessages enum class InAppMessageActionUrlType( private val text: String, ) { - /** * Opens in an in-app webview */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/internal/MisconfiguredIAMManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/internal/MisconfiguredIAMManager.kt index 80fc3fe597..dbb124db43 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/internal/MisconfiguredIAMManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/inAppMessages/internal/MisconfiguredIAMManager.kt @@ -13,17 +13,31 @@ internal class MisconfiguredIAMManager : IInAppMessagesManager { get() = throw EXCEPTION set(value) = throw EXCEPTION - override fun addTrigger(key: String, value: String) = throw EXCEPTION + override fun addTrigger( + key: String, + value: String, + ) = throw EXCEPTION + override fun addTriggers(triggers: Map) = throw EXCEPTION + override fun removeTrigger(key: String) = throw EXCEPTION + override fun removeTriggers(keys: Collection) = throw EXCEPTION + override fun clearTriggers() = throw EXCEPTION + override fun addLifecycleListener(listener: IInAppMessageLifecycleListener) = throw EXCEPTION + override fun removeLifecycleListener(listener: IInAppMessageLifecycleListener) = throw EXCEPTION + override fun addClickListener(listener: IInAppMessageClickListener) = throw EXCEPTION + override fun removeClickListener(listener: IInAppMessageClickListener) = throw EXCEPTION companion object { - private val EXCEPTION: Throwable get() = Exception("Must include gradle module com.onesignal:InAppMessages in order to use this functionality!") + private val EXCEPTION: Throwable get() = + Exception( + "Must include gradle module com.onesignal:InAppMessages in order to use this functionality!", + ) } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt index 0b7cec5a31..b19dce209f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt @@ -4,7 +4,6 @@ import android.content.Context import com.onesignal.IOneSignal import com.onesignal.common.IDManager import com.onesignal.common.OneSignalUtils -import com.onesignal.common.exceptions.BackendException import com.onesignal.common.modeling.ModelChangeTags import com.onesignal.common.modules.IModule import com.onesignal.common.safeString @@ -51,65 +50,94 @@ import com.onesignal.user.internal.subscriptions.SubscriptionType import org.json.JSONObject internal class OneSignalImp : IOneSignal, IServiceProvider { - override val sdkVersion: String = OneSignalUtils.sdkVersion + override val sdkVersion: String = OneSignalUtils.SDK_VERSION override var isInitialized: Boolean = false override var consentRequired: Boolean - get() = _configModel?.consentRequired ?: (_consentRequired == true) + get() = configModel?.consentRequired ?: (_consentRequired == true) set(value) { _consentRequired = value - _configModel?.consentRequired = value + configModel?.consentRequired = value } override var consentGiven: Boolean - get() = _configModel?.consentGiven ?: (_consentGiven == true) + get() = configModel?.consentGiven ?: (_consentGiven == true) set(value) { _consentGiven = value - _configModel?.consentGiven = value + configModel?.consentGiven = value } override var disableGMSMissingPrompt: Boolean - get() = _configModel?.disableGMSMissingPrompt ?: (_disableGMSMissingPrompt == true) + get() = configModel?.disableGMSMissingPrompt ?: (_disableGMSMissingPrompt == true) set(value) { _disableGMSMissingPrompt = value - _configModel?.disableGMSMissingPrompt = value + configModel?.disableGMSMissingPrompt = value } // we hardcode the DebugManager implementation so it can be used prior to calling `initWithContext` - override val Debug: IDebugManager = DebugManager() - override val Session: ISessionManager get() = if (isInitialized) _session!! else throw Exception("Must call 'initWithContext' before use") - override val Notifications: INotificationsManager get() = if (isInitialized) _notifications!! else throw Exception("Must call 'initWithContext' before use") - override val Location: ILocationManager get() = if (isInitialized) _location!! else throw Exception("Must call 'initWithContext' before use") - override val InAppMessages: IInAppMessagesManager get() = if (isInitialized) _iam!! else throw Exception("Must call 'initWithContext' before use") - override val User: IUserManager get() = if (isInitialized) _user!! else throw Exception("Must call 'initWithContext' before use") + override val debug: IDebugManager = DebugManager() + override val session: ISessionManager get() = + if (isInitialized) { + _session!! + } else { + throw Exception( + "Must call 'initWithContext' before use", + ) + } + override val notifications: INotificationsManager get() = + if (isInitialized) { + _notifications!! + } else { + throw Exception( + "Must call 'initWithContext' before use", + ) + } + override val location: ILocationManager get() = + if (isInitialized) { + _location!! + } else { + throw Exception( + "Must call 'initWithContext' before use", + ) + } + override val inAppMessages: IInAppMessagesManager get() = + if (isInitialized) { + iam!! + } else { + throw Exception( + "Must call 'initWithContext' before use", + ) + } + override val user: IUserManager get() = if (isInitialized) _user!! else throw Exception("Must call 'initWithContext' before use") // Services required by this class private var _user: IUserManager? = null private var _session: ISessionManager? = null - private var _iam: IInAppMessagesManager? = null + private var iam: IInAppMessagesManager? = null private var _location: ILocationManager? = null private var _notifications: INotificationsManager? = null - private var _operationRepo: IOperationRepo? = null - private var _identityModelStore: IdentityModelStore? = null - private var _propertiesModelStore: PropertiesModelStore? = null - private var _subscriptionModelStore: SubscriptionModelStore? = null - private var _startupService: StartupService? = null - private var _preferencesService: IPreferencesService? = null + private var operationRepo: IOperationRepo? = null + private var identityModelStore: IdentityModelStore? = null + private var propertiesModelStore: PropertiesModelStore? = null + private var subscriptionModelStore: SubscriptionModelStore? = null + private var startupService: StartupService? = null + private var preferencesService: IPreferencesService? = null // Other State - private val _services: ServiceProvider - private var _configModel: ConfigModel? = null - private var _sessionModel: SessionModel? = null + private val services: ServiceProvider + private var configModel: ConfigModel? = null + private var sessionModel: SessionModel? = null private var _consentRequired: Boolean? = null private var _consentGiven: Boolean? = null private var _disableGMSMissingPrompt: Boolean? = null - private val _loginLock: Any = Any() + private val loginLock: Any = Any() - private val _listOfModules = listOf( - "com.onesignal.notifications.NotificationsModule", - "com.onesignal.inAppMessages.InAppMessagesModule", - "com.onesignal.location.LocationModule", - ) + private val listOfModules = + listOf( + "com.onesignal.notifications.NotificationsModule", + "com.onesignal.inAppMessages.InAppMessagesModule", + "com.onesignal.location.LocationModule", + ) init { val serviceBuilder = ServiceBuilder() @@ -119,7 +147,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { modules.add(CoreModule()) modules.add(SessionModule()) modules.add(UserModule()) - for (moduleClassName in _listOfModules) { + for (moduleClassName in listOfModules) { try { val moduleClass = Class.forName(moduleClassName) val moduleInstance = moduleClass.newInstance() as IModule @@ -133,10 +161,13 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { module.register(serviceBuilder) } - _services = serviceBuilder.build() + services = serviceBuilder.build() } - override fun initWithContext(context: Context, appId: String?): Boolean { + override fun initWithContext( + context: Context, + appId: String?, + ): Boolean { Logging.log(LogLevel.DEBUG, "initWithContext(context: $context, appId: $appId)") // do not do this again if already initialized @@ -147,20 +178,20 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { // start the application service. This is called explicitly first because we want // to make sure it has the context provided on input, for all other startable services // to depend on if needed. - val applicationService = _services.getService() + val applicationService = services.getService() (applicationService as ApplicationService).start(context) // Give the logging singleton access to the application service to support visual logging. Logging.applicationService = applicationService // get the current config model, if there is one - _configModel = _services.getService().model - _sessionModel = _services.getService().model + configModel = services.getService().model + sessionModel = services.getService().model // initWithContext is called by our internal services/receivers/activites but they do not provide // an appId (they don't know it). If the app has never called the external initWithContext // prior to our services/receivers/activities we will blow up, as no appId has been established. - if (appId == null && !_configModel!!.hasProperty(ConfigModel::appId.name)) { + if (appId == null && !configModel!!.hasProperty(ConfigModel::appId.name)) { Logging.warn("initWithContext called without providing appId, and no appId has been established!") return false } @@ -168,55 +199,65 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { var forceCreateUser = false // if the app id was specified as input, update the config model with it if (appId != null) { - if (!_configModel!!.hasProperty(ConfigModel::appId.name) || _configModel!!.appId != appId) { + if (!configModel!!.hasProperty(ConfigModel::appId.name) || configModel!!.appId != appId) { forceCreateUser = true } - _configModel!!.appId = appId + configModel!!.appId = appId } // if requires privacy consent was set prior to init, set it in the model now if (_consentRequired != null) { - _configModel!!.consentRequired = _consentRequired!! + configModel!!.consentRequired = _consentRequired!! } // if privacy consent was set prior to init, set it in the model now if (_consentGiven != null) { - _configModel!!.consentGiven = _consentGiven!! + configModel!!.consentGiven = _consentGiven!! } if (_disableGMSMissingPrompt != null) { - _configModel!!.disableGMSMissingPrompt = _disableGMSMissingPrompt!! + configModel!!.disableGMSMissingPrompt = _disableGMSMissingPrompt!! } // "Inject" the services required by this main class - _location = _services.getService() - _user = _services.getService() - _session = _services.getService() - _iam = _services.getService() - _notifications = _services.getService() - _operationRepo = _services.getService() - _propertiesModelStore = _services.getService() - _identityModelStore = _services.getService() - _subscriptionModelStore = _services.getService() - _preferencesService = _services.getService() + _location = services.getService() + _user = services.getService() + _session = services.getService() + iam = services.getService() + _notifications = services.getService() + operationRepo = services.getService() + propertiesModelStore = services.getService() + identityModelStore = services.getService() + subscriptionModelStore = services.getService() + preferencesService = services.getService() // Instantiate and call the IStartableServices - _startupService = _services.getService() - _startupService!!.bootstrap() + startupService = services.getService() + startupService!!.bootstrap() - if (forceCreateUser || !_identityModelStore!!.model.hasProperty(IdentityConstants.ONESIGNAL_ID)) { - val legacyPlayerId = _preferencesService!!.getString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_LEGACY_PLAYER_ID) + if (forceCreateUser || !identityModelStore!!.model.hasProperty(IdentityConstants.ONESIGNAL_ID)) { + val legacyPlayerId = preferencesService!!.getString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_LEGACY_PLAYER_ID) if (legacyPlayerId == null) { Logging.debug("initWithContext: creating new device-scoped user") createAndSwitchToNewUser() - _operationRepo!!.enqueue(LoginUserOperation(_configModel!!.appId, _identityModelStore!!.model.onesignalId, _identityModelStore!!.model.externalId)) + operationRepo!!.enqueue( + LoginUserOperation( + configModel!!.appId, + identityModelStore!!.model.onesignalId, + identityModelStore!!.model.externalId, + ), + ) } else { Logging.debug("initWithContext: creating user linked to subscription $legacyPlayerId") // Converting a 4.x SDK to the 5.x SDK. We pull the legacy user sync values to create the subscription model, then enqueue // a specialized `LoginUserFromSubscriptionOperation`, which will drive fetching/refreshing of the local user // based on the subscription ID we do have. - val legacyUserSyncString = _preferencesService!!.getString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_LEGACY_USER_SYNCVALUES) + val legacyUserSyncString = + preferencesService!!.getString( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_LEGACY_USER_SYNCVALUES, + ) var suppressBackendOperation = false if (legacyUserSyncString != null) { @@ -229,29 +270,34 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { pushSubscriptionModel.optedIn = notificationTypes != SubscriptionStatus.NO_PERMISSION.value && notificationTypes != SubscriptionStatus.UNSUBSCRIBE.value pushSubscriptionModel.address = legacyUserSyncJSON.safeString("identifier") ?: "" pushSubscriptionModel.status = SubscriptionStatus.fromInt(notificationTypes) ?: SubscriptionStatus.NO_PERMISSION - _configModel!!.pushSubscriptionId = legacyPlayerId - _subscriptionModelStore!!.add(pushSubscriptionModel, ModelChangeTags.NO_PROPOGATE) + configModel!!.pushSubscriptionId = legacyPlayerId + subscriptionModelStore!!.add(pushSubscriptionModel, ModelChangeTags.NO_PROPOGATE) suppressBackendOperation = true } createAndSwitchToNewUser(suppressBackendOperation = suppressBackendOperation) - _operationRepo!!.enqueue(LoginUserFromSubscriptionOperation(_configModel!!.appId, _identityModelStore!!.model.onesignalId, legacyPlayerId)) - _preferencesService!!.saveString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_LEGACY_PLAYER_ID, null) + operationRepo!!.enqueue( + LoginUserFromSubscriptionOperation(configModel!!.appId, identityModelStore!!.model.onesignalId, legacyPlayerId), + ) + preferencesService!!.saveString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_LEGACY_PLAYER_ID, null) } } else { - Logging.debug("initWithContext: using cached user ${_identityModelStore!!.model.onesignalId}") - _operationRepo!!.enqueue(RefreshUserOperation(_configModel!!.appId, _identityModelStore!!.model.onesignalId)) + Logging.debug("initWithContext: using cached user ${identityModelStore!!.model.onesignalId}") + operationRepo!!.enqueue(RefreshUserOperation(configModel!!.appId, identityModelStore!!.model.onesignalId)) } - _startupService!!.start() + startupService!!.start() isInitialized = true return true } - override fun login(externalId: String, jwtBearerToken: String?) { + override fun login( + externalId: String, + jwtBearerToken: String?, + ) { Logging.log(LogLevel.DEBUG, "login(externalId: $externalId, jwtBearerToken: $jwtBearerToken)") if (!isInitialized) { @@ -263,17 +309,17 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { var newIdentityOneSignalId: String = "" // only allow one login/logout at a time - synchronized(_loginLock) { - currentIdentityExternalId = _identityModelStore!!.model.externalId - currentIdentityOneSignalId = _identityModelStore!!.model.onesignalId + synchronized(loginLock) { + currentIdentityExternalId = identityModelStore!!.model.externalId + currentIdentityOneSignalId = identityModelStore!!.model.onesignalId if (currentIdentityExternalId == externalId) { // login is for same user that is already logged in, fetch (refresh) // the current user. - _operationRepo!!.enqueue( + operationRepo!!.enqueue( RefreshUserOperation( - _configModel!!.appId, - _identityModelStore!!.model.onesignalId, + configModel!!.appId, + identityModelStore!!.model.onesignalId, ), true, ) @@ -285,7 +331,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { identityModel.externalId = externalId } - newIdentityOneSignalId = _identityModelStore!!.model.onesignalId + newIdentityOneSignalId = identityModelStore!!.model.onesignalId } // on a background thread enqueue the login/fetch of the new user @@ -296,15 +342,16 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { // time if network conditions prevent the operation to succeed. This allows us to // provide a callback to the caller when we can absolutely say the user is logged // in, so they may take action on their own backend. - val result = _operationRepo!!.enqueueAndWait( - LoginUserOperation( - _configModel!!.appId, - newIdentityOneSignalId, - externalId, - if (currentIdentityExternalId == null) currentIdentityOneSignalId else null, - ), - true, - ) + val result = + operationRepo!!.enqueueAndWait( + LoginUserOperation( + configModel!!.appId, + newIdentityOneSignalId, + externalId, + if (currentIdentityExternalId == null) currentIdentityOneSignalId else null, + ), + true, + ) if (!result) { Logging.log(LogLevel.ERROR, "Could not login user") @@ -313,12 +360,12 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { // This is a separate enqueue operation to ensure any outstanding operations that happened // after the createAndSwitchToNewUser have been executed, and the retrieval will be the // most up to date reflection of the user. - _operationRepo!!.enqueueAndWait( - RefreshUserOperation( - _configModel!!.appId, - _identityModelStore!!.model.onesignalId, - ), - true, + operationRepo!!.enqueueAndWait( + RefreshUserOperation( + configModel!!.appId, + identityModelStore!!.model.onesignalId, + ), + true, ) } } @@ -333,17 +380,17 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { } // only allow one login/logout at a time - synchronized(_loginLock) { - if (_identityModelStore!!.model.externalId == null) { + synchronized(loginLock) { + if (identityModelStore!!.model.externalId == null) { return } createAndSwitchToNewUser() - _operationRepo!!.enqueue( + operationRepo!!.enqueue( LoginUserOperation( - _configModel!!.appId, - _identityModelStore!!.model.onesignalId, - _identityModelStore!!.model.externalId, + configModel!!.appId, + identityModelStore!!.model.onesignalId, + identityModelStore!!.model.externalId, ), ) @@ -351,7 +398,12 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { } } - private fun createAndSwitchToNewUser(suppressBackendOperation: Boolean = false, modify: ((identityModel: IdentityModel, propertiesModel: PropertiesModel) -> Unit)? = null) { + private fun createAndSwitchToNewUser( + suppressBackendOperation: Boolean = false, + modify: ( + (identityModel: IdentityModel, propertiesModel: PropertiesModel) -> Unit + )? = null, + ) { Logging.debug("createAndSwitchToNewUser()") // create a new identity and properties model locally @@ -375,7 +427,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { // will be automatically transferred over to this new user being created. If there is no // current push subscription we do a "normal" replace which will drive adding a CreateSubscriptionOperation // to the queue. - val currentPushSubscription = _subscriptionModelStore!!.list().firstOrNull { it.id == _configModel!!.pushSubscriptionId } + val currentPushSubscription = subscriptionModelStore!!.list().firstOrNull { it.id == configModel!!.pushSubscriptionId } val newPushSubscription = SubscriptionModel() newPushSubscription.id = currentPushSubscription?.id ?: IDManager.createLocalId() @@ -385,7 +437,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { newPushSubscription.status = currentPushSubscription?.status ?: SubscriptionStatus.NO_PERMISSION // ensure we always know this devices push subscription ID - _configModel!!.pushSubscriptionId = newPushSubscription.id + configModel!!.pushSubscriptionId = newPushSubscription.id subscriptions.add(newPushSubscription) @@ -393,22 +445,25 @@ internal class OneSignalImp : IOneSignal, IServiceProvider { // first as a `NO_PROPOGATE` change because we don't want to drive deleting the cleared subscriptions // on the backend. Once cleared we can then setup the new identity/properties model, and add // the new user's subscriptions as a `NORMAL` change, which will drive changes to the backend. - _subscriptionModelStore!!.clear(ModelChangeTags.NO_PROPOGATE) - _identityModelStore!!.replace(identityModel) - _propertiesModelStore!!.replace(propertiesModel) + subscriptionModelStore!!.clear(ModelChangeTags.NO_PROPOGATE) + identityModelStore!!.replace(identityModel) + propertiesModelStore!!.replace(propertiesModel) if (suppressBackendOperation) { - _subscriptionModelStore!!.replaceAll(subscriptions, ModelChangeTags.NO_PROPOGATE) + subscriptionModelStore!!.replaceAll(subscriptions, ModelChangeTags.NO_PROPOGATE) } else if (currentPushSubscription != null) { - _operationRepo!!.enqueue(TransferSubscriptionOperation(_configModel!!.appId, currentPushSubscription.id, sdkId)) - _subscriptionModelStore!!.replaceAll(subscriptions, ModelChangeTags.NO_PROPOGATE) + operationRepo!!.enqueue(TransferSubscriptionOperation(configModel!!.appId, currentPushSubscription.id, sdkId)) + subscriptionModelStore!!.replaceAll(subscriptions, ModelChangeTags.NO_PROPOGATE) } else { - _subscriptionModelStore!!.replaceAll(subscriptions) + subscriptionModelStore!!.replaceAll(subscriptions) } } - override fun hasService(c: Class): Boolean = _services.hasService(c) - override fun getService(c: Class): T = _services.getService(c) - override fun getServiceOrNull(c: Class): T? = _services.getServiceOrNull(c) - override fun getAllServices(c: Class): List = _services.getAllServices(c) + override fun hasService(c: Class): Boolean = services.hasService(c) + + override fun getService(c: Class): T = services.getService(c) + + override fun getServiceOrNull(c: Class): T? = services.getServiceOrNull(c) + + override fun getAllServices(c: Class): List = services.getAllServices(c) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/location/ILocationManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/location/ILocationManager.kt index 9e0f531142..10bf245de8 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/location/ILocationManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/location/ILocationManager.kt @@ -4,7 +4,6 @@ package com.onesignal.location * The entry point to the location SDK for OneSignal. */ interface ILocationManager { - /** * Whether location is currently shared with OneSignal. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/BackgroundImageLayout.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/BackgroundImageLayout.kt index 8b410eb7fc..22114d6ee7 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/BackgroundImageLayout.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/BackgroundImageLayout.kt @@ -9,12 +9,10 @@ class BackgroundImageLayout( * The asset file, android resource name, or URL to remote image. */ val image: String? = null, - /** * The title text color. */ val titleTextColor: String? = null, - /** * The body text color. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationLifecycleListener.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationLifecycleListener.kt index 5f08d74713..a79b8a1664 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationLifecycleListener.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationLifecycleListener.kt @@ -8,7 +8,6 @@ package com.onesignal.notifications * @see [Foreground Notification Received Event | OneSignal Docs](https://documentation.onesignal.com/docs/sdk-notification-event-handlers#foreground-notification-received-event) */ interface INotificationLifecycleListener { - /** * Called when a notification is to be displayed to the user. This callback * gives the implementor the ability to prevent the notification from displaying to the diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationServiceExtension.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationServiceExtension.kt index 90863d56b1..70c2a769f5 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationServiceExtension.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationServiceExtension.kt @@ -13,7 +13,6 @@ package com.onesignal.notifications * @see [Android Notification Service Extension | OneSignal Docs](https://documentation.onesignal.com/docs/service-extensions#android-notification-service-extension) */ interface INotificationServiceExtension { - /** * Called when a notification has been received by the device. This method * gives the implementor the ability to modify or prevent the notification from displaying to the diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationWillDisplayEvent.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationWillDisplayEvent.kt index 4f88407b6f..eac2486463 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationWillDisplayEvent.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/INotificationWillDisplayEvent.kt @@ -25,7 +25,6 @@ package com.onesignal.notifications * ``` */ interface INotificationWillDisplayEvent { - /** * The notification that has been received. It is an [IDisplayableNotification] to * allow the user to call [IDisplayableNotification.display] in the event they also diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/IPermissionObserver.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/IPermissionObserver.kt index 06b49b22f4..2a8065ef57 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/IPermissionObserver.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/IPermissionObserver.kt @@ -5,7 +5,6 @@ package com.onesignal.notifications * in order to receive control when the push permission state has changed on the current device. */ interface IPermissionObserver { - /** * Called when the permission state has changed. * diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/internal/MisconfiguredNotificationsManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/internal/MisconfiguredNotificationsManager.kt index e595667cdc..a82296a432 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/internal/MisconfiguredNotificationsManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/notifications/internal/MisconfiguredNotificationsManager.kt @@ -16,14 +16,23 @@ internal class MisconfiguredNotificationsManager : INotificationsManager { get() = throw EXCEPTION override suspend fun requestPermission(fallbackToSettings: Boolean): Boolean = throw EXCEPTION + override fun removeNotification(id: Int) = throw EXCEPTION + override fun removeGroupedNotifications(group: String) = throw EXCEPTION + override fun clearAllNotifications() = throw EXCEPTION + override fun addPermissionObserver(observer: IPermissionObserver) = throw EXCEPTION + override fun removePermissionObserver(observer: IPermissionObserver) = throw EXCEPTION + override fun addForegroundLifecycleListener(listener: INotificationLifecycleListener) = throw EXCEPTION + override fun removeForegroundLifecycleListener(listener: INotificationLifecycleListener) = throw EXCEPTION + override fun addClickListener(listener: INotificationClickListener) = throw EXCEPTION + override fun removeClickListener(listener: INotificationClickListener) = throw EXCEPTION companion object { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/ISessionManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/ISessionManager.kt index cbc43e76f1..05edbe1c8c 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/ISessionManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/ISessionManager.kt @@ -33,5 +33,8 @@ interface ISessionManager { * * @return this user manager to allow for chaining of calls. */ - fun addOutcomeWithValue(name: String, value: Float) + fun addOutcomeWithValue( + name: String, + value: Float, + ) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/SessionManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/SessionManager.kt index d21976bd01..081729903f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/SessionManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/SessionManager.kt @@ -9,7 +9,6 @@ import com.onesignal.session.internal.outcomes.IOutcomeEventsController internal open class SessionManager( private val _outcomeController: IOutcomeEventsController, ) : ISessionManager { - override fun addOutcome(name: String) { Logging.log(LogLevel.DEBUG, "sendOutcome(name: $name)") @@ -26,7 +25,10 @@ internal open class SessionManager( } } - override fun addOutcomeWithValue(name: String, value: Float) { + override fun addOutcomeWithValue( + name: String, + value: Float, + ) { Logging.log(LogLevel.DEBUG, "sendOutcomeWithValue(name: $name, value: $value)") suspendifyOnThread { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/IInfluenceManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/IInfluenceManager.kt index 9f31540ec8..0a3aa9504a 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/IInfluenceManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/IInfluenceManager.kt @@ -1,7 +1,6 @@ package com.onesignal.session.internal.influence interface IInfluenceManager { - /** * The influences being tracked. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/Influence.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/Influence.kt index cbada69ed2..df04d3cbe6 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/Influence.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/Influence.kt @@ -38,18 +38,20 @@ class Influence { val directId: String? get() = ids?.let { if (it.length() > 0) it.getString(0) else null } - fun copy() = Influence( - influenceChannel = this@Influence.influenceChannel, - influenceType = this@Influence.influenceType, - ids = this@Influence.ids, - ) + fun copy() = + Influence( + influenceChannel = this@Influence.influenceChannel, + influenceType = this@Influence.influenceType, + ids = this@Influence.ids, + ) @Throws(JSONException::class) - fun toJSONString() = JSONObject() - .put(INFLUENCE_CHANNEL, influenceChannel.toString()) - .put(INFLUENCE_TYPE, influenceType.toString()) - .put(INFLUENCE_IDS, if (ids != null) ids.toString() else "") - .toString() + fun toJSONString() = + JSONObject() + .put(INFLUENCE_CHANNEL, influenceChannel.toString()) + .put(INFLUENCE_TYPE, influenceType.toString()) + .put(INFLUENCE_IDS, if (ids != null) ids.toString() else "") + .toString() override fun toString(): String { return "SessionInfluence{" + diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/InfluenceChannel.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/InfluenceChannel.kt index 97a69b4bdc..300af7d0bd 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/InfluenceChannel.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/InfluenceChannel.kt @@ -11,8 +11,9 @@ enum class InfluenceChannel(private val nameValue: String) { companion object { @JvmStatic - fun fromString(value: String?) = value?.let { - values().findLast { it.equalsName(value) } - } ?: NOTIFICATION + fun fromString(value: String?) = + value?.let { + values().findLast { it.equalsName(value) } + } ?: NOTIFICATION } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/InfluenceType.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/InfluenceType.kt index 3fe7c51606..4b20f06f83 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/InfluenceType.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/InfluenceType.kt @@ -19,8 +19,9 @@ enum class InfluenceType { companion object { @JvmStatic - fun fromString(value: String?) = value?.let { - values().findLast { it.name.equals(value, ignoreCase = true) } - } ?: UNATTRIBUTED + fun fromString(value: String?) = + value?.let { + values().findLast { it.name.equals(value, ignoreCase = true) } + } ?: UNATTRIBUTED } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/ChannelTracker.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/ChannelTracker.kt index 8a80165b36..52ef327de8 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/ChannelTracker.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/ChannelTracker.kt @@ -10,159 +10,162 @@ import org.json.JSONObject internal abstract class ChannelTracker internal constructor(protected var dataRepository: InfluenceDataRepository, private var timeProvider: ITime) : IChannelTracker { - override var influenceType: InfluenceType? = null - override var indirectIds: JSONArray? = null - override var directId: String? = null - - @get:Throws(JSONException::class) - abstract val lastChannelObjects: JSONArray - abstract val channelLimit: Int - abstract val indirectAttributionWindow: Int - abstract fun getLastChannelObjectsReceivedByNewId(id: String?): JSONArray - abstract fun saveChannelObjects(channelObjects: JSONArray) - abstract fun initInfluencedTypeFromCache() - - private val isDirectSessionEnabled: Boolean - get() = dataRepository.isDirectInfluenceEnabled - - private val isIndirectSessionEnabled: Boolean - get() = dataRepository.isIndirectInfluenceEnabled - - private val isUnattributedSessionEnabled: Boolean - get() = dataRepository.isUnattributedInfluenceEnabled - - /** - * Get the current session based on state + if outcomes features are enabled. - */ - override val currentSessionInfluence: Influence - get() { - val sessionInfluence = Influence(channelType, InfluenceType.DISABLED, null) - // Channel weren't init yet because application is starting - if (influenceType == null) initInfluencedTypeFromCache() - - val currentInfluenceType = influenceType ?: InfluenceType.DISABLED - - if (currentInfluenceType.isDirect()) { - if (isDirectSessionEnabled) { - sessionInfluence.apply { - ids = JSONArray().put(this@ChannelTracker.directId) - influenceType = InfluenceType.DIRECT + override var influenceType: InfluenceType? = null + override var indirectIds: JSONArray? = null + override var directId: String? = null + + @get:Throws(JSONException::class) + abstract val lastChannelObjects: JSONArray + abstract val channelLimit: Int + abstract val indirectAttributionWindow: Int + + abstract fun getLastChannelObjectsReceivedByNewId(id: String?): JSONArray + + abstract fun saveChannelObjects(channelObjects: JSONArray) + + abstract fun initInfluencedTypeFromCache() + + private val isDirectSessionEnabled: Boolean + get() = dataRepository.isDirectInfluenceEnabled + + private val isIndirectSessionEnabled: Boolean + get() = dataRepository.isIndirectInfluenceEnabled + + private val isUnattributedSessionEnabled: Boolean + get() = dataRepository.isUnattributedInfluenceEnabled + + /** + * Get the current session based on state + if outcomes features are enabled. + */ + override val currentSessionInfluence: Influence + get() { + val sessionInfluence = Influence(channelType, InfluenceType.DISABLED, null) + // Channel weren't init yet because application is starting + if (influenceType == null) initInfluencedTypeFromCache() + + val currentInfluenceType = influenceType ?: InfluenceType.DISABLED + + if (currentInfluenceType.isDirect()) { + if (isDirectSessionEnabled) { + sessionInfluence.apply { + ids = JSONArray().put(this@ChannelTracker.directId) + influenceType = InfluenceType.DIRECT + } } - } - } else if (currentInfluenceType.isIndirect()) { - if (isIndirectSessionEnabled) { + } else if (currentInfluenceType.isIndirect()) { + if (isIndirectSessionEnabled) { + sessionInfluence.apply { + ids = this@ChannelTracker.indirectIds + influenceType = InfluenceType.INDIRECT + } + } + } else if (isUnattributedSessionEnabled) { sessionInfluence.apply { - ids = this@ChannelTracker.indirectIds - influenceType = InfluenceType.INDIRECT + influenceType = InfluenceType.UNATTRIBUTED } } - } else if (isUnattributedSessionEnabled) { - sessionInfluence.apply { - influenceType = InfluenceType.UNATTRIBUTED - } - } - return sessionInfluence - } + return sessionInfluence + } - /** - * Get all received ids that may influence actions - * @return ids that happen between attribution window - */ - override val lastReceivedIds: JSONArray - get() { - val ids = JSONArray() - try { - val lastChannelObjectReceived = lastChannelObjects - Logging.debug("ChannelTracker.getLastReceivedIds: lastChannelObjectReceived: $lastChannelObjectReceived") - val attributionWindow = indirectAttributionWindow * 60 * 1000L - val currentTime = timeProvider.currentTimeMillis - for (i in 0 until lastChannelObjectReceived.length()) { - val jsonObject = lastChannelObjectReceived.getJSONObject(i) - val time = jsonObject.getLong(InfluenceConstants.TIME) - val difference = currentTime - time - if (difference <= attributionWindow) { - val id = jsonObject.getString(idTag) - ids.put(id) + /** + * Get all received ids that may influence actions + * @return ids that happen between attribution window + */ + override val lastReceivedIds: JSONArray + get() { + val ids = JSONArray() + try { + val lastChannelObjectReceived = lastChannelObjects + Logging.debug("ChannelTracker.getLastReceivedIds: lastChannelObjectReceived: $lastChannelObjectReceived") + val attributionWindow = indirectAttributionWindow * 60 * 1000L + val currentTime = timeProvider.currentTimeMillis + for (i in 0 until lastChannelObjectReceived.length()) { + val jsonObject = lastChannelObjectReceived.getJSONObject(i) + val time = jsonObject.getLong(InfluenceConstants.TIME) + val difference = currentTime - time + if (difference <= attributionWindow) { + val id = jsonObject.getString(idTag) + ids.put(id) + } } + } catch (exception: JSONException) { + Logging.error("ChannelTracker.getLastReceivedIds: Generating tracker getLastReceivedIds JSONObject ", exception) } - } catch (exception: JSONException) { - Logging.error("ChannelTracker.getLastReceivedIds: Generating tracker getLastReceivedIds JSONObject ", exception) + return ids } - return ids + + override fun resetAndInitInfluence() { + directId = null + indirectIds = lastReceivedIds + influenceType = if (indirectIds?.length() ?: 0 > 0) InfluenceType.INDIRECT else InfluenceType.UNATTRIBUTED + cacheState() + Logging.debug("ChannelTracker.resetAndInitInfluence: $idTag finish with influenceType: $influenceType") } - override fun resetAndInitInfluence() { - directId = null - indirectIds = lastReceivedIds - influenceType = if (indirectIds?.length() ?: 0 > 0) InfluenceType.INDIRECT else InfluenceType.UNATTRIBUTED - cacheState() - Logging.debug("ChannelTracker.resetAndInitInfluence: $idTag finish with influenceType: $influenceType") - } + /** + * Save state of last ids received + */ + override fun saveLastId(id: String?) { + Logging.debug("ChannelTracker.saveLastId(id: $id): idTag=$idTag") + if (id == null || id.isEmpty()) return + + val lastChannelObjectsReceived = getLastChannelObjectsReceivedByNewId(id) + Logging.debug("ChannelTracker.saveLastId: for $idTag saveLastId with lastChannelObjectsReceived: $lastChannelObjectsReceived") - /** - * Save state of last ids received - */ - override fun saveLastId(id: String?) { - Logging.debug("ChannelTracker.saveLastId(id: $id): idTag=$idTag") - if (id == null || id.isEmpty()) return - - val lastChannelObjectsReceived = getLastChannelObjectsReceivedByNewId(id) - Logging.debug("ChannelTracker.saveLastId: for $idTag saveLastId with lastChannelObjectsReceived: $lastChannelObjectsReceived") - - try { - timeProvider.run { - JSONObject() - .put(idTag, id) - .put(InfluenceConstants.TIME, currentTimeMillis) - }.also { newInfluenceId -> - lastChannelObjectsReceived.put(newInfluenceId) + try { + timeProvider.run { + JSONObject() + .put(idTag, id) + .put(InfluenceConstants.TIME, currentTimeMillis) + }.also { newInfluenceId -> + lastChannelObjectsReceived.put(newInfluenceId) + } + } catch (exception: JSONException) { + Logging.error("ChannelTracker.saveLastId: Generating tracker newInfluenceId JSONObject ", exception) + // We don't have new data, stop logic + return } - } catch (exception: JSONException) { - Logging.error("ChannelTracker.saveLastId: Generating tracker newInfluenceId JSONObject ", exception) - // We don't have new data, stop logic - return - } - var channelObjectToSave = lastChannelObjectsReceived - // Only save the last ids without surpassing the limit - // Always keep the max quantity of ids possible - // If the attribution window increases, old ids might influence - if (lastChannelObjectsReceived.length() > channelLimit) { - val lengthDifference = lastChannelObjectsReceived.length() - channelLimit - // If min sdk is greater than KITKAT we can refactor this logic to removeObject from JSONArray - channelObjectToSave = JSONArray() - for (i in lengthDifference until lastChannelObjectsReceived.length()) { - try { - channelObjectToSave.put(lastChannelObjectsReceived[i]) - } catch (exception: JSONException) { - Logging.error("ChannelTracker.saveLastId: Generating tracker lastChannelObjectsReceived get JSONObject ", exception) + var channelObjectToSave = lastChannelObjectsReceived + // Only save the last ids without surpassing the limit + // Always keep the max quantity of ids possible + // If the attribution window increases, old ids might influence + if (lastChannelObjectsReceived.length() > channelLimit) { + val lengthDifference = lastChannelObjectsReceived.length() - channelLimit + // If min sdk is greater than KITKAT we can refactor this logic to removeObject from JSONArray + channelObjectToSave = JSONArray() + for (i in lengthDifference until lastChannelObjectsReceived.length()) { + try { + channelObjectToSave.put(lastChannelObjectsReceived[i]) + } catch (exception: JSONException) { + Logging.error("ChannelTracker.saveLastId: Generating tracker lastChannelObjectsReceived get JSONObject ", exception) + } } } + Logging.debug("ChannelTracker.saveLastId: for $idTag with channelObjectToSave: $channelObjectToSave") + saveChannelObjects(channelObjectToSave) } - Logging.debug("ChannelTracker.saveLastId: for $idTag with channelObjectToSave: $channelObjectToSave") - saveChannelObjects(channelObjectToSave) - } - override fun toString(): String { - return "ChannelTracker{" + - "tag=" + idTag + - ", influenceType=" + influenceType + - ", indirectIds=" + indirectIds + - ", directId=" + directId + - '}' - } + override fun toString(): String { + return "ChannelTracker{" + + "tag=" + idTag + + ", influenceType=" + influenceType + + ", indirectIds=" + indirectIds + + ", directId=" + directId + + '}' + } - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || javaClass != other.javaClass) return false - val tracker = other as ChannelTracker - return influenceType === tracker.influenceType && tracker.idTag == idTag - } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || javaClass != other.javaClass) return false + val tracker = other as ChannelTracker + return influenceType === tracker.influenceType && tracker.idTag == idTag + } - override fun hashCode(): Int { - var result = influenceType.hashCode() - result = 31 * result + idTag.hashCode() - return result + override fun hashCode(): Int { + var result = influenceType.hashCode() + result = 31 * result + idTag.hashCode() + return result + } } -} diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/IChannelTracker.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/IChannelTracker.kt index 4fa63f1b40..2167118815 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/IChannelTracker.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/IChannelTracker.kt @@ -20,6 +20,7 @@ internal interface IChannelTracker { val currentSessionInfluence: Influence fun cacheState() + fun resetAndInitInfluence() /** diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/IInfluenceDataRepository.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/IInfluenceDataRepository.kt index 13a5e76874..eb56f9d9d7 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/IInfluenceDataRepository.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/IInfluenceDataRepository.kt @@ -47,6 +47,8 @@ internal interface IInfluenceDataRepository { * Cache attributed notification opened */ fun cacheNotificationOpenId(id: String?) + fun saveNotifications(notifications: JSONArray) + fun saveIAMs(iams: JSONArray) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InAppMessageTracker.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InAppMessageTracker.kt index 8f32cf2ec6..344b8c8329 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InAppMessageTracker.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InAppMessageTracker.kt @@ -7,7 +7,10 @@ import com.onesignal.session.internal.influence.InfluenceType import org.json.JSONArray import org.json.JSONException -internal class InAppMessageTracker(dataRepository: InfluenceDataRepository, timeProvider: ITime) : ChannelTracker(dataRepository, timeProvider) { +internal class InAppMessageTracker(dataRepository: InfluenceDataRepository, timeProvider: ITime) : ChannelTracker( + dataRepository, + timeProvider, +) { override val idTag: String get() = InfluenceConstants.IAM_ID_TAG @@ -16,12 +19,13 @@ internal class InAppMessageTracker(dataRepository: InfluenceDataRepository, time override fun getLastChannelObjectsReceivedByNewId(id: String?): JSONArray { var lastChannelObjectReceived: JSONArray - lastChannelObjectReceived = try { - lastChannelObjects - } catch (exception: JSONException) { - Logging.error("Generating IAM tracker getLastChannelObjects JSONObject ", exception) - return JSONArray() - } + lastChannelObjectReceived = + try { + lastChannelObjects + } catch (exception: JSONException) { + Logging.error("Generating IAM tracker getLastChannelObjects JSONObject ", exception) + return JSONArray() + } // For IAM we handle redisplay, we need to remove duplicates for new influence Id // If min sdk is greater than KITKAT we can refactor this logic to removeObject from JSONArray try { @@ -54,9 +58,10 @@ internal class InAppMessageTracker(dataRepository: InfluenceDataRepository, time } override fun initInfluencedTypeFromCache() { - influenceType = dataRepository.iamCachedInfluenceType.also { - if (it.isIndirect()) indirectIds = lastReceivedIds - } + influenceType = + dataRepository.iamCachedInfluenceType.also { + if (it.isIndirect()) indirectIds = lastReceivedIds + } Logging.debug("InAppMessageTracker.initInfluencedTypeFromCache: $this") } @@ -65,6 +70,8 @@ internal class InAppMessageTracker(dataRepository: InfluenceDataRepository, time // DIRECT is downgrade to INDIRECT to avoid inconsistency state // where the app might be close before dismissing current displayed IAM val influenceTypeToCache = influenceType ?: InfluenceType.UNATTRIBUTED - dataRepository.cacheIAMInfluenceType(if (influenceTypeToCache === InfluenceType.DIRECT) InfluenceType.INDIRECT else influenceTypeToCache) + dataRepository.cacheIAMInfluenceType( + if (influenceTypeToCache === InfluenceType.DIRECT) InfluenceType.INDIRECT else influenceTypeToCache, + ) } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InfluenceDataRepository.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InfluenceDataRepository.kt index 45f2463b77..473409b323 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InfluenceDataRepository.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InfluenceDataRepository.kt @@ -31,11 +31,12 @@ internal class InfluenceDataRepository( */ override val notificationCachedInfluenceType: InfluenceType get() { - val influenceType = preferences.getString( - PreferenceStores.ONESIGNAL, - InfluenceConstants.PREFS_OS_OUTCOMES_CURRENT_NOTIFICATION_INFLUENCE, - InfluenceType.UNATTRIBUTED.toString(), - ) + val influenceType = + preferences.getString( + PreferenceStores.ONESIGNAL, + InfluenceConstants.PREFS_OS_OUTCOMES_CURRENT_NOTIFICATION_INFLUENCE, + InfluenceType.UNATTRIBUTED.toString(), + ) return InfluenceType.fromString(influenceType) } @@ -56,11 +57,12 @@ internal class InfluenceDataRepository( override val iamCachedInfluenceType: InfluenceType get() { val defaultValue = InfluenceType.UNATTRIBUTED.toString() - val influenceType = preferences.getString( - PreferenceStores.ONESIGNAL, - InfluenceConstants.PREFS_OS_OUTCOMES_CURRENT_IAM_INFLUENCE, - defaultValue, - ) + val influenceType = + preferences.getString( + PreferenceStores.ONESIGNAL, + InfluenceConstants.PREFS_OS_OUTCOMES_CURRENT_IAM_INFLUENCE, + defaultValue, + ) return InfluenceType.fromString(influenceType) } @@ -79,11 +81,12 @@ internal class InfluenceDataRepository( * Get the current cached notification id, null if not direct */ override val cachedNotificationOpenId: String? - get() = preferences.getString( - PreferenceStores.ONESIGNAL, - InfluenceConstants.PREFS_OS_LAST_ATTRIBUTED_NOTIFICATION_OPEN, - null, - ) + get() = + preferences.getString( + PreferenceStores.ONESIGNAL, + InfluenceConstants.PREFS_OS_LAST_ATTRIBUTED_NOTIFICATION_OPEN, + null, + ) override fun saveNotifications(notifications: JSONArray) { preferences.saveString( @@ -104,22 +107,24 @@ internal class InfluenceDataRepository( @get:Throws(JSONException::class) override val lastNotificationsReceivedData: JSONArray get() { - val notificationsReceived = preferences.getString( - PreferenceStores.ONESIGNAL, - InfluenceConstants.PREFS_OS_LAST_NOTIFICATIONS_RECEIVED, - "[]", - ) + val notificationsReceived = + preferences.getString( + PreferenceStores.ONESIGNAL, + InfluenceConstants.PREFS_OS_LAST_NOTIFICATIONS_RECEIVED, + "[]", + ) return notificationsReceived?.let { JSONArray(it) } ?: JSONArray() } @get:Throws(JSONException::class) override val lastIAMsReceivedData: JSONArray get() { - val iamReceived = preferences.getString( - PreferenceStores.ONESIGNAL, - InfluenceConstants.PREFS_OS_LAST_IAMS_RECEIVED, - "[]", - ) + val iamReceived = + preferences.getString( + PreferenceStores.ONESIGNAL, + InfluenceConstants.PREFS_OS_LAST_IAMS_RECEIVED, + "[]", + ) return iamReceived?.let { JSONArray(it) } ?: JSONArray() } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InfluenceManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InfluenceManager.kt index 71677a66b3..53f6a42cd0 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InfluenceManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/InfluenceManager.kt @@ -132,21 +132,27 @@ internal class InfluenceManager( val lastIds = channelTracker.lastReceivedIds Logging.debug("InfluenceManager.restartSessionIfNeeded: lastIds: $lastIds") val influence = channelTracker.currentSessionInfluence - var updated: Boolean = if (lastIds.length() > 0) { - setSessionTracker( - channelTracker, - InfluenceType.INDIRECT, - null, - lastIds, - ) - } else { - setSessionTracker(channelTracker, InfluenceType.UNATTRIBUTED, null, null) - } + var updated: Boolean = + if (lastIds.length() > 0) { + setSessionTracker( + channelTracker, + InfluenceType.INDIRECT, + null, + lastIds, + ) + } else { + setSessionTracker(channelTracker, InfluenceType.UNATTRIBUTED, null, null) + } if (updated) updatedInfluences.add(influence) } } - private fun setSessionTracker(channelTracker: IChannelTracker, influenceType: InfluenceType, directNotificationId: String?, indirectNotificationIds: JSONArray?): Boolean { + private fun setSessionTracker( + channelTracker: IChannelTracker, + influenceType: InfluenceType, + directNotificationId: String?, + indirectNotificationIds: JSONArray?, + ): Boolean { if (!willChangeSessionTracker(channelTracker, influenceType, directNotificationId, indirectNotificationIds)) { return false } @@ -169,7 +175,12 @@ internal class InfluenceManager( return true } - private fun willChangeSessionTracker(channelTracker: IChannelTracker, influenceType: InfluenceType, directNotificationId: String?, indirectNotificationIds: JSONArray?): Boolean { + private fun willChangeSessionTracker( + channelTracker: IChannelTracker, + influenceType: InfluenceType, + directNotificationId: String?, + indirectNotificationIds: JSONArray?, + ): Boolean { if (influenceType != channelTracker.influenceType) { return true } @@ -189,7 +200,10 @@ internal class InfluenceManager( // Allow updating an indirect session to a new indirect when a new notification is received } - private fun attemptSessionUpgrade(entryAction: AppEntryAction, directId: String? = null) { + private fun attemptSessionUpgrade( + entryAction: AppEntryAction, + directId: String? = null, + ) { Logging.debug("InfluenceManager.attemptSessionUpgrade(entryAction: $entryAction, directId: $directId)") val channelTrackerByAction = getChannelByEntryAction(entryAction) val channelTrackersToReset = getChannelsToResetByEntryAction(entryAction) @@ -204,7 +218,9 @@ internal class InfluenceManager( } if (updated) { - Logging.debug("InfluenceManager.attemptSessionUpgrade: channel updated, search for ending direct influences on channels: $channelTrackersToReset") + Logging.debug( + "InfluenceManager.attemptSessionUpgrade: channel updated, search for ending direct influences on channels: $channelTrackersToReset", + ) influencesToEnd.add(lastInfluence!!) // Only one session influence channel can be DIRECT at the same time // Reset other DIRECT channels, they will init an INDIRECT influence diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/NotificationTracker.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/NotificationTracker.kt index c4086045d1..657319db89 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/NotificationTracker.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/influence/impl/NotificationTracker.kt @@ -7,7 +7,10 @@ import com.onesignal.session.internal.influence.InfluenceType import org.json.JSONArray import org.json.JSONException -internal class NotificationTracker(dataRepository: InfluenceDataRepository, timeProvider: ITime) : ChannelTracker(dataRepository, timeProvider) { +internal class NotificationTracker(dataRepository: InfluenceDataRepository, timeProvider: ITime) : ChannelTracker( + dataRepository, + timeProvider, +) { override fun getLastChannelObjectsReceivedByNewId(id: String?): JSONArray { return try { lastChannelObjects @@ -37,13 +40,14 @@ internal class NotificationTracker(dataRepository: InfluenceDataRepository, time } override fun initInfluencedTypeFromCache() { - influenceType = dataRepository.notificationCachedInfluenceType.also { - if (it.isIndirect()) { - indirectIds = lastReceivedIds - } else if (it.isDirect()) { - directId = dataRepository.cachedNotificationOpenId + influenceType = + dataRepository.notificationCachedInfluenceType.also { + if (it.isIndirect()) { + indirectIds = lastReceivedIds + } else if (it.isDirect()) { + directId = dataRepository.cachedNotificationOpenId + } } - } Logging.debug("NotificationTracker.initInfluencedTypeFromCache: $this") } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/IOutcomeEventsController.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/IOutcomeEventsController.kt index 3896951620..8a501a2d4b 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/IOutcomeEventsController.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/IOutcomeEventsController.kt @@ -22,5 +22,8 @@ interface IOutcomeEventsController { /** * Send an outcome event with value to the backend. */ - suspend fun sendOutcomeEventWithValue(name: String, weight: Float): IOutcomeEvent? + suspend fun sendOutcomeEventWithValue( + name: String, + weight: Float, + ): IOutcomeEvent? } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/CachedUniqueOutcome.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/CachedUniqueOutcome.kt index 783ef2da88..e653443ab4 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/CachedUniqueOutcome.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/CachedUniqueOutcome.kt @@ -11,7 +11,6 @@ internal class CachedUniqueOutcome( * The ID of the influence this outcome is associated to. */ val influenceId: String, - /** * The channel this outcome is associated to. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/IOutcomeEventsBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/IOutcomeEventsBackendService.kt index 2afbecbe21..71b000c8c9 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/IOutcomeEventsBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/IOutcomeEventsBackendService.kt @@ -6,7 +6,6 @@ import com.onesignal.common.exceptions.BackendException * The backend service for outcomes. */ internal interface IOutcomeEventsBackendService { - /** * Send an outcome event to the backend. * @@ -19,5 +18,12 @@ internal interface IOutcomeEventsBackendService { * @param direct Whether this outcome event is direct. `true` if it is, `false` if it isn't, `null` if should not be specified. * @param event The outcome event to send up. */ - suspend fun sendOutcomeEvent(appId: String, userId: String, subscriptionId: String, deviceType: String, direct: Boolean?, event: OutcomeEvent) + suspend fun sendOutcomeEvent( + appId: String, + userId: String, + subscriptionId: String, + deviceType: String, + direct: Boolean?, + event: OutcomeEvent, + ) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventParams.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventParams.kt index 91c914dd68..d5a16e32a8 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventParams.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventParams.kt @@ -5,15 +5,20 @@ import org.json.JSONObject internal class OutcomeEventParams constructor( val outcomeId: String, - val outcomeSource: OutcomeSource?, // This field is optional - var weight: Float, // This field is optional. - var sessionTime: Long, // This field is optional - var timestamp: Long, // This should start out as zero + // This field is optional + val outcomeSource: OutcomeSource?, + // This field is optional + var weight: Float, + // This field is optional + var sessionTime: Long, + // This should start out as zero + var timestamp: Long, ) { @Throws(JSONException::class) fun toJSONObject(): JSONObject { - val json = JSONObject() - .put(OutcomeConstants.OUTCOME_ID, outcomeId) + val json = + JSONObject() + .put(OutcomeConstants.OUTCOME_ID, outcomeId) outcomeSource?.let { json.put(OutcomeConstants.OUTCOME_SOURCES, it.toJSONObject()) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsBackendService.kt index 7578c1f1df..1fc11044b6 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsBackendService.kt @@ -6,17 +6,24 @@ import org.json.JSONObject internal class OutcomeEventsBackendService(private val _http: IHttpClient) : IOutcomeEventsBackendService { - - override suspend fun sendOutcomeEvent(appId: String, userId: String, subscriptionId: String, deviceType: String, direct: Boolean?, event: OutcomeEvent) { - val jsonObject = JSONObject() - .put("app_id", appId) - .put("onesignal_id", userId) - .put( - "subscription", - JSONObject() - .put("id", subscriptionId) - .put("type", deviceType) - ) + override suspend fun sendOutcomeEvent( + appId: String, + userId: String, + subscriptionId: String, + deviceType: String, + direct: Boolean?, + event: OutcomeEvent, + ) { + val jsonObject = + JSONObject() + .put("app_id", appId) + .put("onesignal_id", userId) + .put( + "subscription", + JSONObject() + .put("id", subscriptionId) + .put("type", deviceType), + ) if (direct != null) { jsonObject.put("direct", direct) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsController.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsController.kt index 1365144b92..20e4802c74 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsController.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsController.kt @@ -54,6 +54,7 @@ internal class OutcomeEventsController( } override fun onSessionActive() { } + override fun onSessionEnded(duration: Long) { } /** @@ -103,7 +104,10 @@ Outcome event was cached and will be reattempted on app cold start""", return sendAndCreateOutcomeEvent(name, 0f, 0, influences) } - override suspend fun sendOutcomeEventWithValue(name: String, weight: Float): OutcomeEvent? { + override suspend fun sendOutcomeEventWithValue( + name: String, + weight: Float, + ): OutcomeEvent? { val influences: List = _influenceManager.influences return sendAndCreateOutcomeEvent(name, weight, 0, influences) } @@ -137,9 +141,9 @@ Outcome event was cached and will be reattempted on app cold start""", if (uniqueInfluences == null) { Logging.debug( """ - Measure endpoint will not send because unique outcome already sent for: - SessionInfluences: $influences - Outcome name: $name + Measure endpoint will not send because unique outcome already sent for: + SessionInfluences: $influences + Outcome name: $name """.trimIndent(), ) @@ -152,9 +156,9 @@ Outcome event was cached and will be reattempted on app cold start""", if (unattributedUniqueOutcomeEventsSentOnSession.contains(name)) { Logging.debug( """ - Measure endpoint will not send because unique outcome already sent for: - Session: ${InfluenceType.UNATTRIBUTED} - Outcome name: $name + Measure endpoint will not send because unique outcome already sent for: + Session: ${InfluenceType.UNATTRIBUTED} + Outcome name: $name """.trimIndent(), ) @@ -169,7 +173,8 @@ Outcome event was cached and will be reattempted on app cold start""", private suspend fun sendAndCreateOutcomeEvent( name: String, weight: Float, - sessionTime: Long, // Note: this is optional + // Note: this is optional + sessionTime: Long, influences: List, ): OutcomeEvent? { val timestampSeconds: Long = _time.currentTimeMillis / 1000 @@ -178,17 +183,23 @@ Outcome event was cached and will be reattempted on app cold start""", var unattributed = false for (influence in influences) { when (influence.influenceType) { - InfluenceType.DIRECT -> directSourceBody = setSourceChannelIds( - influence, - directSourceBody ?: OutcomeSourceBody(), - ) - InfluenceType.INDIRECT -> indirectSourceBody = setSourceChannelIds( - influence, - indirectSourceBody ?: OutcomeSourceBody(), - ) + InfluenceType.DIRECT -> + directSourceBody = + setSourceChannelIds( + influence, + directSourceBody ?: OutcomeSourceBody(), + ) + InfluenceType.INDIRECT -> + indirectSourceBody = + setSourceChannelIds( + influence, + indirectSourceBody ?: OutcomeSourceBody(), + ) InfluenceType.UNATTRIBUTED -> unattributed = true InfluenceType.DISABLED -> { - Logging.verbose("OutcomeEventsController.sendAndCreateOutcomeEvent: Outcomes disabled for channel: " + influence.influenceChannel) + Logging.verbose( + "OutcomeEventsController.sendAndCreateOutcomeEvent: Outcomes disabled for channel: " + influence.influenceChannel, + ) } } } @@ -238,7 +249,9 @@ Outcome event was cached and will be reattempted on app cold start""", val availableInfluences: MutableList = influences.toMutableList() for (influence in influences) { if (influence.influenceType.isDisabled()) { - Logging.debug("OutcomeEventsController.removeDisabledInfluences: Outcomes disabled for channel: " + influence.influenceChannel.toString()) + Logging.debug( + "OutcomeEventsController.removeDisabledInfluences: Outcomes disabled for channel: " + influence.influenceChannel.toString(), + ) availableInfluences.remove(influence) } } @@ -274,7 +287,10 @@ Outcome event was cached and will be reattempted on app cold start""", /** * Get the unique notifications that have not been cached/sent before with the current unique outcome name */ - private suspend fun getUniqueIds(name: String, influences: List): List? { + private suspend fun getUniqueIds( + name: String, + influences: List, + ): List? { val uniqueInfluences: List = _outcomeEventsCache.getNotCachedUniqueInfluencesForOutcome(name, influences) return uniqueInfluences.ifEmpty { null } @@ -292,12 +308,13 @@ Outcome event was cached and will be reattempted on app cold start""", } val event = OutcomeEvent.fromOutcomeEventParamstoOutcomeEvent(eventParams) - val direct = when (event.session) { - InfluenceType.DIRECT -> true - InfluenceType.INDIRECT -> false - InfluenceType.UNATTRIBUTED -> null - else -> null - } + val direct = + when (event.session) { + InfluenceType.DIRECT -> true + InfluenceType.INDIRECT -> false + InfluenceType.UNATTRIBUTED -> null + else -> null + } _outcomeEventsBackend.sendOutcomeEvent(appId, _identityModelStore.model.onesignalId, subscriptionId, deviceType, direct, event) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsPreferences.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsPreferences.kt index 2f04135c29..0e18baf589 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsPreferences.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsPreferences.kt @@ -7,17 +7,18 @@ import com.onesignal.core.internal.preferences.PreferenceStores internal class OutcomeEventsPreferences( private val preferences: IPreferencesService, ) : IOutcomeEventsPreferences { - override var unattributedUniqueOutcomeEventsSentByChannel: Set? - get() = preferences.getStringSet( - PreferenceStores.ONESIGNAL, - PreferenceOneSignalKeys.PREFS_OS_UNATTRIBUTED_UNIQUE_OUTCOME_EVENTS_SENT, - null, - ) + get() = + preferences.getStringSet( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_UNATTRIBUTED_UNIQUE_OUTCOME_EVENTS_SENT, + null, + ) set(value) { preferences.saveStringSet( PreferenceStores.ONESIGNAL, - PreferenceOneSignalKeys.PREFS_OS_UNATTRIBUTED_UNIQUE_OUTCOME_EVENTS_SENT, // Post success, store unattributed unique outcome event names + // Post success, store unattributed unique outcome event names + PreferenceOneSignalKeys.PREFS_OS_UNATTRIBUTED_UNIQUE_OUTCOME_EVENTS_SENT, value, ) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsRepository.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsRepository.kt index d542e870de..c769f7d0ba 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsRepository.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsRepository.kt @@ -17,7 +17,6 @@ import java.util.Locale internal class OutcomeEventsRepository( private val _databaseProvider: IDatabaseProvider, ) : IOutcomeEventsRepository { - /** * Delete event from the DB */ @@ -135,21 +134,22 @@ internal class OutcomeEventsRepository( try { val directSourceBody = OutcomeSourceBody() val indirectSourceBody = OutcomeSourceBody() - val source: OutcomeSource = getNotificationInfluenceSource( - notificationInfluenceType, - directSourceBody, - indirectSourceBody, - notificationIds, - ) - .also { - getIAMInfluenceSource( - iamInfluenceType, - directSourceBody, - indirectSourceBody, - iamIds, - it, - ) - } ?: OutcomeSource(null, null) + val source: OutcomeSource = + getNotificationInfluenceSource( + notificationInfluenceType, + directSourceBody, + indirectSourceBody, + notificationIds, + ) + .also { + getIAMInfluenceSource( + iamInfluenceType, + directSourceBody, + indirectSourceBody, + iamIds, + it, + ) + } ?: OutcomeSource(null, null) OutcomeEventParams(name, source, weight, sessionTime, timestamp).also { events.add(it) } @@ -211,7 +211,11 @@ internal class OutcomeEventsRepository( } } - private fun addIdToListFromChannel(cachedUniqueOutcomes: MutableList, channelIds: JSONArray?, channel: InfluenceChannel) { + private fun addIdToListFromChannel( + cachedUniqueOutcomes: MutableList, + channelIds: JSONArray?, + channel: InfluenceChannel, + ) { channelIds?.let { for (i in 0 until it.length()) { try { @@ -224,7 +228,10 @@ internal class OutcomeEventsRepository( } } - private fun addIdsToListFromSource(cachedUniqueOutcomes: MutableList, sourceBody: OutcomeSourceBody?) { + private fun addIdsToListFromSource( + cachedUniqueOutcomes: MutableList, + sourceBody: OutcomeSourceBody?, + ) { sourceBody?.let { val iamIds = it.inAppMessagesIds val notificationIds = it.notificationIds @@ -268,7 +275,10 @@ internal class OutcomeEventsRepository( /** * Create a JSONArray of not cached notification ids from the unique outcome notifications SQL table */ - override suspend fun getNotCachedUniqueInfluencesForOutcome(name: String, influences: List): List { + override suspend fun getNotCachedUniqueInfluencesForOutcome( + name: String, + influences: List, + ): List { val uniqueInfluences: MutableList = ArrayList() withContext(Dispatchers.IO) { @@ -281,9 +291,10 @@ internal class OutcomeEventsRepository( val channelInfluenceId = influenceIds.getString(i) val channel = influence.influenceChannel val columns = arrayOf() - val where = CachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID + " = ? AND " + - CachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE + " = ? AND " + - CachedUniqueOutcomeTable.COLUMN_NAME_NAME + " = ?" + val where = + CachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID + " = ? AND " + + CachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE + " = ? AND " + + CachedUniqueOutcomeTable.COLUMN_NAME_NAME + " = ?" val args = arrayOf(channelInfluenceId, channel.toString(), name) _databaseProvider.os.query( CachedUniqueOutcomeTable.TABLE_NAME, @@ -321,12 +332,14 @@ internal class OutcomeEventsRepository( val notificationIdColumnName = OneSignalDbContract.NotificationTable.COLUMN_NAME_NOTIFICATION_ID withContext(Dispatchers.IO) { - val whereStr = "NOT EXISTS(" + - "SELECT NULL FROM " + notificationTableName + " n " + - "WHERE" + " n." + notificationIdColumnName + " = " + OutcomesDbContract.CACHE_UNIQUE_OUTCOME_COLUMN_CHANNEL_INFLUENCE_ID + - " AND " + OutcomesDbContract.CACHE_UNIQUE_OUTCOME_COLUMN_CHANNEL_TYPE + " = \"" + InfluenceChannel.NOTIFICATION.toString() - .lowercase(Locale.ROOT) + - "\")" + val whereStr = + "NOT EXISTS(" + + "SELECT NULL FROM " + notificationTableName + " n " + + "WHERE" + " n." + notificationIdColumnName + " = " + OutcomesDbContract.CACHE_UNIQUE_OUTCOME_COLUMN_CHANNEL_INFLUENCE_ID + + " AND " + OutcomesDbContract.CACHE_UNIQUE_OUTCOME_COLUMN_CHANNEL_TYPE + " = \"" + + InfluenceChannel.NOTIFICATION.toString() + .lowercase(Locale.ROOT) + + "\")" _databaseProvider.os.delete( OutcomesDbContract.CACHE_UNIQUE_OUTCOME_TABLE, whereStr, diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeSource.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeSource.kt index c1a4253388..abe9d2286c 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeSource.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeSource.kt @@ -19,13 +19,15 @@ internal class OutcomeSource( return json } - fun setDirectBody(directBody: OutcomeSourceBody?) = this.apply { - this.directBody = directBody - } + fun setDirectBody(directBody: OutcomeSourceBody?) = + this.apply { + this.directBody = directBody + } - fun setIndirectBody(indirectBody: OutcomeSourceBody?) = this.apply { - this.indirectBody = indirectBody - } + fun setIndirectBody(indirectBody: OutcomeSourceBody?) = + this.apply { + this.indirectBody = indirectBody + } override fun toString(): String { return "OutcomeSource{" + diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeSourceBody.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeSourceBody.kt index 0f6e4e0c8d..0d6905d3fb 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeSourceBody.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeSourceBody.kt @@ -4,17 +4,19 @@ import org.json.JSONArray import org.json.JSONException import org.json.JSONObject -internal class OutcomeSourceBody @JvmOverloads constructor(var notificationIds: JSONArray? = JSONArray(), var inAppMessagesIds: JSONArray? = JSONArray()) { +internal class OutcomeSourceBody + @JvmOverloads + constructor(var notificationIds: JSONArray? = JSONArray(), var inAppMessagesIds: JSONArray? = JSONArray()) { + @Throws(JSONException::class) + fun toJSONObject(): JSONObject = + JSONObject() + .put(OutcomeConstants.NOTIFICATION_IDS, notificationIds) + .put(OutcomeConstants.IAM_IDS, inAppMessagesIds) - @Throws(JSONException::class) - fun toJSONObject(): JSONObject = JSONObject() - .put(OutcomeConstants.NOTIFICATION_IDS, notificationIds) - .put(OutcomeConstants.IAM_IDS, inAppMessagesIds) - - override fun toString(): String { - return "OutcomeSourceBody{" + - "notificationIds=" + notificationIds + - ", inAppMessagesIds=" + inAppMessagesIds + - '}' + override fun toString(): String { + return "OutcomeSourceBody{" + + "notificationIds=" + notificationIds + + ", inAppMessagesIds=" + inAppMessagesIds + + '}' + } } -} diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeTableProvider.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeTableProvider.kt index 6413e5ed0c..63ee0ff79b 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeTableProvider.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeTableProvider.kt @@ -12,11 +12,12 @@ internal class OutcomeTableProvider { * On the outcome table this adds the new weight column and drops params column. */ fun upgradeOutcomeTableRevision1To2(db: SQLiteDatabase) { - val commonColumns: String = OutcomeEventsTable.ID.toString() + "," + - OutcomeEventsTable.COLUMN_NAME_SESSION + "," + - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + "," + - OutcomeEventsTable.COLUMN_NAME_NAME + "," + - OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + val commonColumns: String = + OutcomeEventsTable.ID.toString() + "," + + OutcomeEventsTable.COLUMN_NAME_SESSION + "," + + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + "," + + OutcomeEventsTable.COLUMN_NAME_NAME + "," + + OutcomeEventsTable.COLUMN_NAME_TIMESTAMP try { // Since SQLite does not support dropping a column we need to: // 1. Create a temptable @@ -48,11 +49,12 @@ internal class OutcomeTableProvider { * @param db */ fun upgradeOutcomeTableRevision2To3(db: SQLiteDatabase) { - val commonColumns: String = OutcomeEventsTable.ID + "," + - OutcomeEventsTable.COLUMN_NAME_NAME + "," + - OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + "," + - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + "," + - OutcomeEventsTable.COLUMN_NAME_WEIGHT + val commonColumns: String = + OutcomeEventsTable.ID + "," + + OutcomeEventsTable.COLUMN_NAME_NAME + "," + + OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + "," + + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + "," + + OutcomeEventsTable.COLUMN_NAME_WEIGHT val commonColumnsWithSessionColumn = commonColumns + "," + OutcomeEventsTable.COLUMN_NAME_SESSION val commonColumnsWithNewSessionColumn = commonColumns + "," + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE val auxOutcomeTableName: String = OutcomeEventsTable.TABLE_NAME + "_aux" @@ -86,7 +88,9 @@ internal class OutcomeTableProvider { fun upgradeOutcomeTableRevision3To4(db: SQLiteDatabase) { try { db.execSQL("BEGIN TRANSACTION;") - db.execSQL("ALTER TABLE " + OutcomeEventsTable.TABLE_NAME + " ADD COLUMN " + OutcomeEventsTable.COLUMN_NAME_SESSION_TIME + " INTEGER DEFAULT 1;") + db.execSQL( + "ALTER TABLE " + OutcomeEventsTable.TABLE_NAME + " ADD COLUMN " + OutcomeEventsTable.COLUMN_NAME_SESSION_TIME + " INTEGER DEFAULT 1;", + ) // We intentionally choose to default session_time to 1 to address a bug on cached outcomes from v5.0.0-beta's // os__session_duration requests expect a session_time and these will keep failing and caching, so let's just send them with a time of 1 for migrations } catch (e: SQLiteException) { @@ -103,8 +107,9 @@ internal class OutcomeTableProvider { * @param db */ fun upgradeCacheOutcomeTableRevision1To2(db: SQLiteDatabase) { - val commonColumns: String = CachedUniqueOutcomeTable.ID + "," + - CachedUniqueOutcomeTable.COLUMN_NAME_NAME + val commonColumns: String = + CachedUniqueOutcomeTable.ID + "," + + CachedUniqueOutcomeTable.COLUMN_NAME_NAME val commonColumnsWithNotificationIdColumn = commonColumns + "," + CachedUniqueOutcomeTable.COLUMN_NAME_NOTIFICATION_ID val commonColumnsWithNewInfluenceIdColumn = commonColumns + "," + CachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID val oldCacheUniqueOutcomeTable: String = CachedUniqueOutcomeTable.TABLE_NAME_V1 diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomesDbContract.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomesDbContract.kt index 0cd0c0dfb6..6453ff74f1 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomesDbContract.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomesDbContract.kt @@ -49,57 +49,63 @@ internal object OutcomesDbContract { CachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID const val CACHE_UNIQUE_OUTCOME_COLUMN_CHANNEL_TYPE: String = CachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE - const val SQL_CREATE_OUTCOME_ENTRIES_V1 = "CREATE TABLE " + OutcomeEventsTable.TABLE_NAME + " (" + - OutcomeEventsTable.ID + " INTEGER PRIMARY KEY," + - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_NAME + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_SESSION + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_PARAMS + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + " TIMESTAMP" + - ");" - const val SQL_CREATE_OUTCOME_ENTRIES_V2 = "CREATE TABLE " + OutcomeEventsTable.TABLE_NAME + " (" + - OutcomeEventsTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_SESSION + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_NAME + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + TIMESTAMP_TYPE + "," + // "params TEXT" Added in v4, removed in v5. - OutcomeEventsTable.COLUMN_NAME_WEIGHT + FLOAT_TYPE + // New in v5, missing migration added in v6 - ");" - const val SQL_CREATE_OUTCOME_ENTRIES_V3 = "CREATE TABLE " + OutcomeEventsTable.TABLE_NAME + " (" + - OutcomeEventsTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_IAM_IDS + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_NAME + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + TIMESTAMP_TYPE + "," + // "params TEXT" Added in v4, removed in v5. - OutcomeEventsTable.COLUMN_NAME_WEIGHT + FLOAT_TYPE + // New in v5, missing migration added in v6 - ");" + const val SQL_CREATE_OUTCOME_ENTRIES_V1 = + "CREATE TABLE " + OutcomeEventsTable.TABLE_NAME + " (" + + OutcomeEventsTable.ID + " INTEGER PRIMARY KEY," + + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_NAME + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_SESSION + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_PARAMS + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + " TIMESTAMP" + + ");" + const val SQL_CREATE_OUTCOME_ENTRIES_V2 = + "CREATE TABLE " + OutcomeEventsTable.TABLE_NAME + " (" + + OutcomeEventsTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_SESSION + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_NAME + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + TIMESTAMP_TYPE + "," + // "params TEXT" Added in v4, removed in v5. + OutcomeEventsTable.COLUMN_NAME_WEIGHT + FLOAT_TYPE + // New in v5, missing migration added in v6 + ");" + const val SQL_CREATE_OUTCOME_ENTRIES_V3 = + "CREATE TABLE " + OutcomeEventsTable.TABLE_NAME + " (" + + OutcomeEventsTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_IAM_IDS + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_NAME + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + TIMESTAMP_TYPE + "," + // "params TEXT" Added in v4, removed in v5. + OutcomeEventsTable.COLUMN_NAME_WEIGHT + FLOAT_TYPE + // New in v5, missing migration added in v6 + ");" /** * Adds a new column called session_time */ - const val SQL_CREATE_OUTCOME_ENTRIES_V4 = "CREATE TABLE " + OutcomeEventsTable.TABLE_NAME + " (" + - OutcomeEventsTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_IAM_IDS + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_NAME + TEXT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + TIMESTAMP_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_WEIGHT + FLOAT_TYPE + "," + - OutcomeEventsTable.COLUMN_NAME_SESSION_TIME + INT_TYPE + - ");" + const val SQL_CREATE_OUTCOME_ENTRIES_V4 = + "CREATE TABLE " + OutcomeEventsTable.TABLE_NAME + " (" + + OutcomeEventsTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_IAM_IDS + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_NAME + TEXT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_TIMESTAMP + TIMESTAMP_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_WEIGHT + FLOAT_TYPE + "," + + OutcomeEventsTable.COLUMN_NAME_SESSION_TIME + INT_TYPE + + ");" - const val SQL_CREATE_UNIQUE_OUTCOME_ENTRIES_V1 = "CREATE TABLE " + CachedUniqueOutcomeTable.TABLE_NAME_V1 + " (" + - CachedUniqueOutcomeTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + - CachedUniqueOutcomeTable.COLUMN_NAME_NOTIFICATION_ID + TEXT_TYPE + "," + - CachedUniqueOutcomeTable.COLUMN_NAME_NAME + TEXT_TYPE + - ");" - const val SQL_CREATE_UNIQUE_OUTCOME_ENTRIES_V2 = "CREATE TABLE " + CachedUniqueOutcomeTable.TABLE_NAME_V2 + " (" + - CachedUniqueOutcomeTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + - CachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID + TEXT_TYPE + "," + - CachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE + TEXT_TYPE + "," + - CachedUniqueOutcomeTable.COLUMN_NAME_NAME + TEXT_TYPE + - ");" + const val SQL_CREATE_UNIQUE_OUTCOME_ENTRIES_V1 = + "CREATE TABLE " + CachedUniqueOutcomeTable.TABLE_NAME_V1 + " (" + + CachedUniqueOutcomeTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + + CachedUniqueOutcomeTable.COLUMN_NAME_NOTIFICATION_ID + TEXT_TYPE + "," + + CachedUniqueOutcomeTable.COLUMN_NAME_NAME + TEXT_TYPE + + ");" + const val SQL_CREATE_UNIQUE_OUTCOME_ENTRIES_V2 = + "CREATE TABLE " + CachedUniqueOutcomeTable.TABLE_NAME_V2 + " (" + + CachedUniqueOutcomeTable.ID + INTEGER_PRIMARY_KEY_TYPE + "," + + CachedUniqueOutcomeTable.COLUMN_CHANNEL_INFLUENCE_ID + TEXT_TYPE + "," + + CachedUniqueOutcomeTable.COLUMN_CHANNEL_TYPE + TEXT_TYPE + "," + + CachedUniqueOutcomeTable.COLUMN_NAME_NAME + TEXT_TYPE + + ");" } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/ISessionService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/ISessionService.kt index fd679a248e..f936cc4d47 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/ISessionService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/ISessionService.kt @@ -9,7 +9,6 @@ import com.onesignal.common.events.IEventNotifier * @See [ISessionLifecycleHandler] */ interface ISessionService : IEventNotifier { - /** * When the current session was started, in Unix time milliseconds. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/SessionModel.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/SessionModel.kt index cace94907e..439d22fe91 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/SessionModel.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/SessionModel.kt @@ -11,33 +11,43 @@ class SessionModel : Model() { */ var sessionId: String get() = getStringProperty(::sessionId.name) - set(value) { setStringProperty(::sessionId.name, value) } + set(value) { + setStringProperty(::sessionId.name, value) + } /** * Whether the session is valid. */ var isValid: Boolean get() = getBooleanProperty(::isValid.name) { true } - set(value) { setBooleanProperty(::isValid.name, value) } + set(value) { + setBooleanProperty(::isValid.name, value) + } /** * When this session started, in Unix time milliseconds. */ var startTime: Long get() = getLongProperty(::startTime.name) { System.currentTimeMillis() } - set(value) { setLongProperty(::startTime.name, value) } + set(value) { + setLongProperty(::startTime.name, value) + } /** * When this app was last focused, in Unix time milliseconds. */ var focusTime: Long get() = getLongProperty(::focusTime.name) { 0 } - set(value) { setLongProperty(::focusTime.name, value) } + set(value) { + setLongProperty(::focusTime.name, value) + } /** * How long this session has spent as active, in milliseconds. */ var activeDuration: Long get() = getLongProperty(::activeDuration.name) { 0L } - set(value) { setLongProperty(::activeDuration.name, value) } + set(value) { + setLongProperty(::activeDuration.name, value) + } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionListener.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionListener.kt index 9eda7dd100..265be9f82e 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionListener.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionListener.kt @@ -34,7 +34,6 @@ internal class SessionListener( private val _identityModelStore: IdentityModelStore, private val _outcomeEventsController: IOutcomeEventsController, ) : IStartableService, ISessionLifecycleHandler { - override fun start() { _sessionService.subscribe(this) } @@ -48,7 +47,9 @@ internal class SessionListener( override fun onSessionEnded(duration: Long) { val durationInSeconds = duration / 1000 - _operationRepo.enqueue(TrackSessionEndOperation(_configModelStore.model.appId, _identityModelStore.model.onesignalId, durationInSeconds)) + _operationRepo.enqueue( + TrackSessionEndOperation(_configModelStore.model.appId, _identityModelStore.model.onesignalId, durationInSeconds), + ) suspendifyOnThread { _outcomeEventsController.sendSessionEndOutcomeEvent(durationInSeconds) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionService.kt index 0a6ad9f2d9..8f61196fee 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionService.kt @@ -33,57 +33,56 @@ internal class SessionService( private val _sessionModelStore: SessionModelStore, private val _time: ITime, ) : ISessionService, IStartableService, IBackgroundService, IApplicationLifecycleHandler { - override val startTime: Long - get() = _session!!.startTime + get() = session!!.startTime /** * Run in the background when the session would time out, only if a session is currently active. */ override val scheduleBackgroundRunIn: Long? - get() = if (_session!!.isValid) _config!!.sessionFocusTimeout else null + get() = if (session!!.isValid) config!!.sessionFocusTimeout else null - private val _sessionLifeCycleNotifier: EventProducer = EventProducer() - private var _session: SessionModel? = null - private var _config: ConfigModel? = null + private val sessionLifeCycleNotifier: EventProducer = EventProducer() + private var session: SessionModel? = null + private var config: ConfigModel? = null override fun start() { - _session = _sessionModelStore.model - _config = _configModelStore.model + session = _sessionModelStore.model + config = _configModelStore.model _applicationService.addApplicationLifecycleHandler(this) } override suspend fun backgroundRun() { Logging.log(LogLevel.DEBUG, "SessionService.backgroundRun()") - if (!_session!!.isValid) { + if (!session!!.isValid) { return } // end the session - Logging.debug("SessionService: Session ended. activeDuration: ${_session!!.activeDuration}") - _session!!.isValid = false - _sessionLifeCycleNotifier.fire { it.onSessionEnded(_session!!.activeDuration) } + Logging.debug("SessionService: Session ended. activeDuration: ${session!!.activeDuration}") + session!!.isValid = false + sessionLifeCycleNotifier.fire { it.onSessionEnded(session!!.activeDuration) } } override fun onFocus() { Logging.log(LogLevel.DEBUG, "SessionService.onFocus()") - if (!_session!!.isValid) { + if (!session!!.isValid) { // As the old session was made inactive, we need to create a new session - _session!!.sessionId = UUID.randomUUID().toString() - _session!!.startTime = _time.currentTimeMillis - _session!!.focusTime = _session!!.startTime - _session!!.activeDuration = 0L - _session!!.isValid = true - - Logging.debug("SessionService: New session started at ${_session!!.startTime}") - _sessionLifeCycleNotifier.fire { it.onSessionStarted() } + session!!.sessionId = UUID.randomUUID().toString() + session!!.startTime = _time.currentTimeMillis + session!!.focusTime = session!!.startTime + session!!.activeDuration = 0L + session!!.isValid = true + + Logging.debug("SessionService: New session started at ${session!!.startTime}") + sessionLifeCycleNotifier.fire { it.onSessionStarted() } } else { // existing session: just remember the focus time so we can calculate the active time // when onUnfocused is called. - _session!!.focusTime = _time.currentTimeMillis - _sessionLifeCycleNotifier.fire { it.onSessionActive() } + session!!.focusTime = _time.currentTimeMillis + sessionLifeCycleNotifier.fire { it.onSessionActive() } } } @@ -91,12 +90,14 @@ internal class SessionService( Logging.log(LogLevel.DEBUG, "SessionService.onUnfocused()") // capture the amount of time the app was focused - val dt = _time.currentTimeMillis - _session!!.focusTime - _session!!.activeDuration += dt + val dt = _time.currentTimeMillis - session!!.focusTime + session!!.activeDuration += dt } - override fun subscribe(handler: ISessionLifecycleHandler) = _sessionLifeCycleNotifier.subscribe(handler) - override fun unsubscribe(handler: ISessionLifecycleHandler) = _sessionLifeCycleNotifier.unsubscribe(handler) + override fun subscribe(handler: ISessionLifecycleHandler) = sessionLifeCycleNotifier.subscribe(handler) + + override fun unsubscribe(handler: ISessionLifecycleHandler) = sessionLifeCycleNotifier.unsubscribe(handler) + override val hasSubscribers: Boolean - get() = _sessionLifeCycleNotifier.hasSubscribers + get() = sessionLifeCycleNotifier.hasSubscribers } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/IUserManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/IUserManager.kt index b08cb34e8f..e9de656d0d 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/IUserManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/IUserManager.kt @@ -40,7 +40,10 @@ interface IUserManager { * @param id The alias id that should be set against the current user. This must be a unique value * within the alias label across your entire user base so it can uniquely identify this user. */ - fun addAlias(label: String, id: String) + fun addAlias( + label: String, + id: String, + ) /** * Add/set aliases for the current user. If any alias already exists it will be overwritten. @@ -102,7 +105,10 @@ interface IUserManager { * @param key The key of the data tag. * @param value THe new value of the data tag. */ - fun addTag(key: String, value: String) + fun addTag( + key: String, + value: String, + ) /** * Add multiple tags for the current user. Tags are key:value pairs used as building blocks diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/PushSubscription.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/PushSubscription.kt index 24ae03a251..3e5dac63f4 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/PushSubscription.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/PushSubscription.kt @@ -13,7 +13,7 @@ internal open class PushSubscription( ) : Subscription(model), IPushSubscription { val changeHandlersNotifier = EventProducer() var savedState = fetchState() - private set; + private set override val token: String get() = model.address @@ -32,14 +32,15 @@ internal open class PushSubscription( } override fun addObserver(observer: IPushSubscriptionObserver) = changeHandlersNotifier.subscribe(observer) + override fun removeObserver(observer: IPushSubscriptionObserver) = changeHandlersNotifier.unsubscribe(observer) - fun refreshState() : PushSubscriptionState { + fun refreshState(): PushSubscriptionState { savedState = fetchState() return savedState } - private fun fetchState() : PushSubscriptionState { + private fun fetchState(): PushSubscriptionState { return PushSubscriptionState(id, token, optedIn) } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/Subscription.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/Subscription.kt index ace7f0f104..d4c5808827 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/Subscription.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/Subscription.kt @@ -1,10 +1,8 @@ package com.onesignal.user.internal import com.onesignal.common.IDManager -import com.onesignal.common.events.EventProducer import com.onesignal.user.internal.subscriptions.SubscriptionModel import com.onesignal.user.subscriptions.ISubscription -import com.onesignal.user.subscriptions.IPushSubscriptionObserver /** * An abstract subscription represents an open channel between diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/UserManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/UserManager.kt index 28ac15aaa1..dbb8add277 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/UserManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/UserManager.kt @@ -11,8 +11,8 @@ import com.onesignal.user.internal.identity.IdentityModelStore import com.onesignal.user.internal.properties.PropertiesModel import com.onesignal.user.internal.properties.PropertiesModelStore import com.onesignal.user.internal.subscriptions.ISubscriptionManager -import com.onesignal.user.subscriptions.IPushSubscription import com.onesignal.user.internal.subscriptions.SubscriptionList +import com.onesignal.user.subscriptions.IPushSubscription internal open class UserManager( private val _subscriptionManager: ISubscriptionManager, @@ -20,7 +20,6 @@ internal open class UserManager( private val _propertiesModelStore: PropertiesModelStore, private val _languageContext: ILanguageContext, ) : IUserManager { - val externalId: String? get() = _identityModel.externalId @@ -46,7 +45,10 @@ internal open class UserManager( _languageContext.language = value } - override fun addAlias(label: String, id: String) { + override fun addAlias( + label: String, + id: String, + ) { Logging.log(LogLevel.DEBUG, "setAlias(label: $label, id: $id)") if (label.isEmpty()) { @@ -162,7 +164,10 @@ internal open class UserManager( _subscriptionManager.removeSmsSubscription(sms) } - override fun addTag(key: String, value: String) { + override fun addTag( + key: String, + value: String, + ) { Logging.log(LogLevel.DEBUG, "setTag(key: $key, value: $value)") if (key.isEmpty()) { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/IIdentityBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/IIdentityBackendService.kt index f72cad36e0..880599871d 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/IIdentityBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/IIdentityBackendService.kt @@ -13,7 +13,12 @@ interface IIdentityBackendService { * @param aliasValue The identifier within the [aliasLabel] that identifies the user to retrieve. * @param identities The identities that are to be created. */ - suspend fun setAlias(appId: String, aliasLabel: String, aliasValue: String, identities: Map): Map + suspend fun setAlias( + appId: String, + aliasLabel: String, + aliasValue: String, + identities: Map, + ): Map /** * Delete the [aliasLabelToDelete] from the user identified by the [aliasLabel]/[aliasValue] provided. @@ -25,7 +30,12 @@ interface IIdentityBackendService { * @param aliasValue The identifier within the [aliasLabel] that identifies the user to retrieve. * @param aliasLabelToDelete The alias label to delete from the user identified. */ - suspend fun deleteAlias(appId: String, aliasLabel: String, aliasValue: String, aliasLabelToDelete: String) + suspend fun deleteAlias( + appId: String, + aliasLabel: String, + aliasValue: String, + aliasLabelToDelete: String, + ) } internal object IdentityConstants { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/ISubscriptionBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/ISubscriptionBackendService.kt index e99dc3914f..8741b2df65 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/ISubscriptionBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/ISubscriptionBackendService.kt @@ -16,7 +16,12 @@ interface ISubscriptionBackendService { * * @return The ID of the subscription created. Or null if the subscription is already part of the current user. */ - suspend fun createSubscription(appId: String, aliasLabel: String, aliasValue: String, subscription: SubscriptionObject): String? + suspend fun createSubscription( + appId: String, + aliasLabel: String, + aliasValue: String, + subscription: SubscriptionObject, + ): String? /** * Update an existing subscription with the properties provided. @@ -25,7 +30,11 @@ interface ISubscriptionBackendService { * @param subscriptionId The ID of the subscription to update. * @param subscription The subscription updates. Any non-null value will be updated. */ - suspend fun updateSubscription(appId: String, subscriptionId: String, subscription: SubscriptionObject) + suspend fun updateSubscription( + appId: String, + subscriptionId: String, + subscription: SubscriptionObject, + ) /** * Delete an existing subscription. @@ -33,7 +42,10 @@ interface ISubscriptionBackendService { * @param appId The ID of the OneSignal application this subscription exists under. * @param subscriptionId The ID of the subscription to delete. */ - suspend fun deleteSubscription(appId: String, subscriptionId: String) + suspend fun deleteSubscription( + appId: String, + subscriptionId: String, + ) /** * Transfer an existing subscription to the user specified. @@ -43,7 +55,12 @@ interface ISubscriptionBackendService { * @param aliasLabel The alias label of the user to transfer the subscription under. * @param aliasValue The identifier within the [aliasLabel] that identifies the user to transfer under. */ - suspend fun transferSubscription(appId: String, subscriptionId: String, aliasLabel: String, aliasValue: String) + suspend fun transferSubscription( + appId: String, + subscriptionId: String, + aliasLabel: String, + aliasValue: String, + ) /** * Given an existing subscription, retrieve all identities associated to it. @@ -53,5 +70,8 @@ interface ISubscriptionBackendService { * * @return The identities associated to the subscription. */ - suspend fun getIdentityFromSubscription(appId: String, subscriptionId: String): Map + suspend fun getIdentityFromSubscription( + appId: String, + subscriptionId: String, + ): Map } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/IUserBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/IUserBackendService.kt index 84cf15190f..a47018641d 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/IUserBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/IUserBackendService.kt @@ -18,7 +18,12 @@ interface IUserBackendService { * * @return The backend response */ - suspend fun createUser(appId: String, identities: Map, subscriptions: List, properties: Map): CreateUserResponse + suspend fun createUser( + appId: String, + identities: Map, + subscriptions: List, + properties: Map, + ): CreateUserResponse // TODO: Change to send only the push subscription, optimally /** @@ -35,7 +40,14 @@ interface IUserBackendService { * * @return The updated properties for this user. */ - suspend fun updateUser(appId: String, aliasLabel: String, aliasValue: String, properties: PropertiesObject, refreshDeviceMetadata: Boolean, propertyiesDelta: PropertiesDeltasObject) + suspend fun updateUser( + appId: String, + aliasLabel: String, + aliasValue: String, + properties: PropertiesObject, + refreshDeviceMetadata: Boolean, + propertyiesDelta: PropertiesDeltasObject, + ) /** * Retrieve a user from the backend. @@ -48,7 +60,11 @@ interface IUserBackendService { * * @return The backend response */ - suspend fun getUser(appId: String, aliasLabel: String, aliasValue: String): CreateUserResponse + suspend fun getUser( + appId: String, + aliasLabel: String, + aliasValue: String, + ): CreateUserResponse } class CreateUserResponse( @@ -56,12 +72,10 @@ class CreateUserResponse( * The identities for the created user. */ val identities: Map, - /** * The properties for the user. */ val properties: PropertiesObject, - /** * The subscriptions for the user. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/SubscriptionObjectType.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/SubscriptionObjectType.kt index 9242cca5c6..87932eecd1 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/SubscriptionObjectType.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/SubscriptionObjectType.kt @@ -27,6 +27,6 @@ enum class SubscriptionObjectType(val value: String) { } } - fun fromString(type: String): SubscriptionObjectType? = values().firstOrNull() { it.value.equals(type, true) } + fun fromString(type: String): SubscriptionObjectType? = values().firstOrNull { it.value.equals(type, true) } } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/IdentityBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/IdentityBackendService.kt index 1d077d9132..1a90893471 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/IdentityBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/IdentityBackendService.kt @@ -10,9 +10,15 @@ import org.json.JSONObject internal class IdentityBackendService( private val _httpClient: IHttpClient, ) : IIdentityBackendService { - override suspend fun setAlias(appId: String, aliasLabel: String, aliasValue: String, identities: Map): Map { - val requestJSONObject = JSONObject() - .put("identity", JSONObject().putMap(identities)) + override suspend fun setAlias( + appId: String, + aliasLabel: String, + aliasValue: String, + identities: Map, + ): Map { + val requestJSONObject = + JSONObject() + .put("identity", JSONObject().putMap(identities)) val response = _httpClient.patch("apps/$appId/users/by/$aliasLabel/$aliasValue/identity", requestJSONObject) @@ -25,7 +31,12 @@ internal class IdentityBackendService( return responseJSON.getJSONObject("identity").toMap().mapValues { it.value.toString() } } - override suspend fun deleteAlias(appId: String, aliasLabel: String, aliasValue: String, aliasLabelToDelete: String) { + override suspend fun deleteAlias( + appId: String, + aliasLabel: String, + aliasValue: String, + aliasLabelToDelete: String, + ) { val response = _httpClient.delete("apps/$appId/users/by/$aliasLabel/$aliasValue/identity/$aliasLabelToDelete") if (!response.isSuccess) { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/JSONConverter.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/JSONConverter.kt index d66e5a2981..ff3745b32b 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/JSONConverter.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/JSONConverter.kt @@ -23,35 +23,37 @@ object JSONConverter { val respIdentities = jsonObject.safeJSONObject("identity")?.toMap()?.mapValues { it.value.toString() } ?: mapOf() val propertiesJSON = jsonObject.safeJSONObject("properties") - val respProperties = PropertiesObject( - propertiesJSON?.safeJSONObject("tags")?.toMap()?.mapValues { it.value.toString() }, - propertiesJSON?.safeString("language"), - propertiesJSON?.safeString("timezone_id"), - propertiesJSON?.safeString("country"), - propertiesJSON?.safeDouble("lat"), - propertiesJSON?.safeDouble("long"), - ) + val respProperties = + PropertiesObject( + propertiesJSON?.safeJSONObject("tags")?.toMap()?.mapValues { it.value.toString() }, + propertiesJSON?.safeString("language"), + propertiesJSON?.safeString("timezone_id"), + propertiesJSON?.safeString("country"), + propertiesJSON?.safeDouble("lat"), + propertiesJSON?.safeDouble("long"), + ) - val respSubscriptions = jsonObject.expandJSONArray("subscriptions") { - val subscriptionType = SubscriptionObjectType.fromString(it.getString("type")) - if (subscriptionType != null) { - return@expandJSONArray SubscriptionObject( - it.getString("id"), - subscriptionType, - it.safeString("token"), - it.safeBool("enabled"), - it.safeInt("notification_types"), - it.safeString("sdk"), - it.safeString("device_model"), - it.safeString("device_os"), - it.safeBool("rooted"), - it.safeInt("net_type"), - it.safeString("carrier"), - it.safeString("app_version"), - ) + val respSubscriptions = + jsonObject.expandJSONArray("subscriptions") { + val subscriptionType = SubscriptionObjectType.fromString(it.getString("type")) + if (subscriptionType != null) { + return@expandJSONArray SubscriptionObject( + it.getString("id"), + subscriptionType, + it.safeString("token"), + it.safeBool("enabled"), + it.safeInt("notification_types"), + it.safeString("sdk"), + it.safeString("device_model"), + it.safeString("device_os"), + it.safeBool("rooted"), + it.safeInt("net_type"), + it.safeString("carrier"), + it.safeString("app_version"), + ) + } + return@expandJSONArray null } - return@expandJSONArray null - } return CreateUserResponse(respIdentities, respProperties, respSubscriptions) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/SubscriptionBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/SubscriptionBackendService.kt index 104d5007f0..ac48f4fc7d 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/SubscriptionBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/SubscriptionBackendService.kt @@ -11,10 +11,15 @@ import org.json.JSONObject internal class SubscriptionBackendService( private val _httpClient: IHttpClient, ) : ISubscriptionBackendService { - - override suspend fun createSubscription(appId: String, aliasLabel: String, aliasValue: String, subscription: SubscriptionObject): String? { - val requestJSON = JSONObject() - .put("subscription", JSONConverter.convertToJSON(subscription)) + override suspend fun createSubscription( + appId: String, + aliasLabel: String, + aliasValue: String, + subscription: SubscriptionObject, + ): String? { + val requestJSON = + JSONObject() + .put("subscription", JSONConverter.convertToJSON(subscription)) val response = _httpClient.post("apps/$appId/users/by/$aliasLabel/$aliasValue/subscriptions", requestJSON) @@ -31,9 +36,14 @@ internal class SubscriptionBackendService( return subscriptionJSON.getString("id") } - override suspend fun updateSubscription(appId: String, subscriptionId: String, subscription: SubscriptionObject) { - val requestJSON = JSONObject() - .put("subscription", JSONConverter.convertToJSON(subscription)) + override suspend fun updateSubscription( + appId: String, + subscriptionId: String, + subscription: SubscriptionObject, + ) { + val requestJSON = + JSONObject() + .put("subscription", JSONConverter.convertToJSON(subscription)) val response = _httpClient.patch("apps/$appId/subscriptions/$subscriptionId", requestJSON) @@ -42,7 +52,10 @@ internal class SubscriptionBackendService( } } - override suspend fun deleteSubscription(appId: String, subscriptionId: String) { + override suspend fun deleteSubscription( + appId: String, + subscriptionId: String, + ) { val response = _httpClient.delete("apps/$appId/subscriptions/$subscriptionId") if (!response.isSuccess) { @@ -50,9 +63,15 @@ internal class SubscriptionBackendService( } } - override suspend fun transferSubscription(appId: String, subscriptionId: String, aliasLabel: String, aliasValue: String) { - val requestJSON = JSONObject() - .put("identity", JSONObject().put(aliasLabel, aliasValue)) + override suspend fun transferSubscription( + appId: String, + subscriptionId: String, + aliasLabel: String, + aliasValue: String, + ) { + val requestJSON = + JSONObject() + .put("identity", JSONObject().put(aliasLabel, aliasValue)) val response = _httpClient.patch("apps/$appId/subscriptions/$subscriptionId/owner", requestJSON) @@ -61,7 +80,10 @@ internal class SubscriptionBackendService( } } - override suspend fun getIdentityFromSubscription(appId: String, subscriptionId: String): Map { + override suspend fun getIdentityFromSubscription( + appId: String, + subscriptionId: String, + ): Map { val response = _httpClient.get("apps/$appId/subscriptions/$subscriptionId/user/identity") if (!response.isSuccess) { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/UserBackendService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/UserBackendService.kt index b064ce005c..d32fac669e 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/UserBackendService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/UserBackendService.kt @@ -13,8 +13,12 @@ import org.json.JSONObject internal class UserBackendService( private val _httpClient: IHttpClient, ) : IUserBackendService { - - override suspend fun createUser(appId: String, identities: Map, subscriptions: List, properties: Map): CreateUserResponse { + override suspend fun createUser( + appId: String, + identities: Map, + subscriptions: List, + properties: Map, + ): CreateUserResponse { val requestJSON = JSONObject() if (identities.isNotEmpty()) { @@ -39,9 +43,17 @@ internal class UserBackendService( return JSONConverter.convertToCreateUserResponse(JSONObject(response.payload!!)) } - override suspend fun updateUser(appId: String, aliasLabel: String, aliasValue: String, properties: PropertiesObject, refreshDeviceMetadata: Boolean, propertyiesDelta: PropertiesDeltasObject) { - val jsonObject = JSONObject() - .put("refresh_device_metadata", refreshDeviceMetadata) + override suspend fun updateUser( + appId: String, + aliasLabel: String, + aliasValue: String, + properties: PropertiesObject, + refreshDeviceMetadata: Boolean, + propertyiesDelta: PropertiesDeltasObject, + ) { + val jsonObject = + JSONObject() + .put("refresh_device_metadata", refreshDeviceMetadata) if (properties.hasAtLeastOnePropertySet) { jsonObject.put("properties", JSONConverter.convertToJSON(properties)) @@ -58,7 +70,11 @@ internal class UserBackendService( } } - override suspend fun getUser(appId: String, aliasLabel: String, aliasValue: String): CreateUserResponse { + override suspend fun getUser( + appId: String, + aliasLabel: String, + aliasValue: String, + ): CreateUserResponse { val response = _httpClient.get("apps/$appId/users/by/$aliasLabel/$aliasValue") if (!response.isSuccess) { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/builduser/IRebuildUserService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/builduser/IRebuildUserService.kt index a9f321b0ef..90e043441c 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/builduser/IRebuildUserService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/builduser/IRebuildUserService.kt @@ -13,5 +13,8 @@ interface IRebuildUserService { * @return the list of operations if [onesignalId] represents the current * user, null otherwise. */ - fun getRebuildOperationsIfCurrentUser(appId: String, onesignalId: String): List? + fun getRebuildOperationsIfCurrentUser( + appId: String, + onesignalId: String, + ): List? } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/builduser/impl/RebuildUserService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/builduser/impl/RebuildUserService.kt index fba184121e..a9f42bcfe1 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/builduser/impl/RebuildUserService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/builduser/impl/RebuildUserService.kt @@ -19,8 +19,10 @@ class RebuildUserService( private val _subscriptionsModelStore: SubscriptionModelStore, private val _configModelStore: ConfigModelStore, ) : IRebuildUserService { - - override fun getRebuildOperationsIfCurrentUser(appId: String, onesignalId: String): List? { + override fun getRebuildOperationsIfCurrentUser( + appId: String, + onesignalId: String, + ): List? { // make a copy of the current models val identityModel = IdentityModel() identityModel.initializeFromModel(null, _identityModelStore.model) @@ -46,7 +48,17 @@ class RebuildUserService( operations.add(LoginUserOperation(appId, onesignalId, identityModel.externalId)) val pushSubscription = subscriptionModels.firstOrNull { it.id == _configModelStore.model.pushSubscriptionId } if (pushSubscription != null) { - operations.add(CreateSubscriptionOperation(appId, onesignalId, pushSubscription.id, pushSubscription.type, pushSubscription.optedIn, pushSubscription.address, pushSubscription.status)) + operations.add( + CreateSubscriptionOperation( + appId, + onesignalId, + pushSubscription.id, + pushSubscription.type, + pushSubscription.optedIn, + pushSubscription.address, + pushSubscription.status, + ), + ) } operations.add(RefreshUserOperation(appId, onesignalId)) return operations diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/identity/IdentityModel.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/identity/IdentityModel.kt index fb1cca8895..d443fdad60 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/identity/IdentityModel.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/identity/IdentityModel.kt @@ -17,12 +17,16 @@ class IdentityModel : MapModel() { */ var onesignalId: String get() = getStringProperty(IdentityConstants.ONESIGNAL_ID) - set(value) { setStringProperty(IdentityConstants.ONESIGNAL_ID, value) } + set(value) { + setStringProperty(IdentityConstants.ONESIGNAL_ID, value) + } /** * The (developer managed) identifier that uniquely identifies this user. */ var externalId: String? get() = getOptStringProperty(IdentityConstants.EXTERNAL_ID) - set(value) { setOptStringProperty(IdentityConstants.EXTERNAL_ID, value) } + set(value) { + setOptStringProperty(IdentityConstants.EXTERNAL_ID, value) + } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/CreateSubscriptionOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/CreateSubscriptionOperation.kt index fd8954ab13..59c463b7f8 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/CreateSubscriptionOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/CreateSubscriptionOperation.kt @@ -17,7 +17,9 @@ class CreateSubscriptionOperation() : Operation(SubscriptionOperationExecutor.CR */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The user ID this subscription will be associated with. This ID *may* be locally generated @@ -25,7 +27,9 @@ class CreateSubscriptionOperation() : Operation(SubscriptionOperationExecutor.CR */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The local ID of the subscription being created. The subscription model with this ID will have its @@ -33,21 +37,27 @@ class CreateSubscriptionOperation() : Operation(SubscriptionOperationExecutor.CR */ var subscriptionId: String get() = getStringProperty(::subscriptionId.name) - private set(value) { setStringProperty(::subscriptionId.name, value) } + private set(value) { + setStringProperty(::subscriptionId.name, value) + } /** * The type of subscription. */ var type: SubscriptionType get() = getEnumProperty(::type.name) - private set(value) { setEnumProperty(::type.name, value) } + private set(value) { + setEnumProperty(::type.name, value) + } /** * Whether this subscription is currently enabled. */ var enabled: Boolean get() = getBooleanProperty(::enabled.name) - private set(value) { setBooleanProperty(::enabled.name, value) } + private set(value) { + setBooleanProperty(::enabled.name, value) + } /** * The address-specific information for this subscription. Its contents depends on the type @@ -59,14 +69,18 @@ class CreateSubscriptionOperation() : Operation(SubscriptionOperationExecutor.CR */ var address: String get() = getStringProperty(::address.name) - private set(value) { setStringProperty(::address.name, value) } + private set(value) { + setStringProperty(::address.name, value) + } /** * The status of this subscription. */ var status: SubscriptionStatus get() = getEnumProperty(::status.name) - private set(value) { setEnumProperty(::status.name, value) } + private set(value) { + setEnumProperty(::status.name, value) + } override val createComparisonKey: String get() = "$appId.User.$onesignalId" override val modifyComparisonKey: String get() = "$appId.User.$onesignalId.Subscription.$subscriptionId" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteAliasOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteAliasOperation.kt index 8eb614de1d..c2ae81f5bb 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteAliasOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteAliasOperation.kt @@ -14,7 +14,9 @@ class DeleteAliasOperation() : Operation(IdentityOperationExecutor.DELETE_ALIAS) */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The user ID this subscription will be associated with. This ID *may* be locally generated @@ -22,14 +24,18 @@ class DeleteAliasOperation() : Operation(IdentityOperationExecutor.DELETE_ALIAS) */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The alias label to be deleted. */ var label: String get() = getStringProperty(::label.name) - private set(value) { setStringProperty(::label.name, value) } + private set(value) { + setStringProperty(::label.name, value) + } override val createComparisonKey: String get() = "" override val modifyComparisonKey: String get() = "$appId.User.$onesignalId.Alias.$label" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteSubscriptionOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteSubscriptionOperation.kt index 5b06e88998..b7724a7404 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteSubscriptionOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteSubscriptionOperation.kt @@ -14,7 +14,9 @@ class DeleteSubscriptionOperation() : Operation(SubscriptionOperationExecutor.DE */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The user ID this subscription will be associated with. This ID *may* be locally generated @@ -22,7 +24,9 @@ class DeleteSubscriptionOperation() : Operation(SubscriptionOperationExecutor.DE */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The subscription ID that is to be deleted. This ID *may* be locally generated @@ -30,7 +34,9 @@ class DeleteSubscriptionOperation() : Operation(SubscriptionOperationExecutor.DE */ var subscriptionId: String get() = getStringProperty(::subscriptionId.name) - private set(value) { setStringProperty(::subscriptionId.name, value) } + private set(value) { + setStringProperty(::subscriptionId.name, value) + } override val createComparisonKey: String get() = "$appId.User.$onesignalId" override val modifyComparisonKey: String get() = "$appId.User.$onesignalId.Subscription.$subscriptionId" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteTagOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteTagOperation.kt index 9be3fd2b69..9ec0d70a50 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteTagOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/DeleteTagOperation.kt @@ -15,7 +15,9 @@ class DeleteTagOperation() : Operation(UpdateUserOperationExecutor.DELETE_TAG) { */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The user ID this subscription will be associated with. This ID *may* be locally generated @@ -23,14 +25,18 @@ class DeleteTagOperation() : Operation(UpdateUserOperationExecutor.DELETE_TAG) { */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The tag key to delete. */ var key: String get() = getStringProperty(::key.name) - private set(value) { setStringProperty(::key.name, value) } + private set(value) { + setStringProperty(::key.name, value) + } override val createComparisonKey: String get() = "" override val modifyComparisonKey: String get() = createComparisonKey diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/LoginUserFromSubscriptionOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/LoginUserFromSubscriptionOperation.kt index 1945ee87e5..a8aa8af7e4 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/LoginUserFromSubscriptionOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/LoginUserFromSubscriptionOperation.kt @@ -13,7 +13,9 @@ class LoginUserFromSubscriptionOperation() : Operation(LoginUserFromSubscription */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The local OneSignal ID this user was initially logged in under. The user models with this ID @@ -21,14 +23,18 @@ class LoginUserFromSubscriptionOperation() : Operation(LoginUserFromSubscription */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The optional external ID of this newly logged-in user. Must be unique for the [appId]. */ var subscriptionId: String get() = getStringProperty(::subscriptionId.name) - private set(value) { setStringProperty(::subscriptionId.name, value) } + private set(value) { + setStringProperty(::subscriptionId.name, value) + } override val createComparisonKey: String get() = "$appId.Subscription.$subscriptionId.Login" override val modifyComparisonKey: String get() = "$appId.Subscription.$subscriptionId.Login" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/LoginUserOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/LoginUserOperation.kt index c2d647f8aa..67eb10ea9a 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/LoginUserOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/LoginUserOperation.kt @@ -18,7 +18,9 @@ class LoginUserOperation() : Operation(LoginUserOperationExecutor.LOGIN_USER) { */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The local OneSignal ID this user was initially logged in under. The user models with this ID @@ -26,14 +28,18 @@ class LoginUserOperation() : Operation(LoginUserOperationExecutor.LOGIN_USER) { */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The optional external ID of this newly logged-in user. Must be unique for the [appId]. */ var externalId: String? get() = getOptStringProperty(::externalId.name) - private set(value) { setOptStringProperty(::externalId.name, value) } + private set(value) { + setOptStringProperty(::externalId.name, value) + } /** * The user ID of an existing user the [externalId] will be attempted to be associated to first. @@ -42,7 +48,9 @@ class LoginUserOperation() : Operation(LoginUserOperationExecutor.LOGIN_USER) { */ var existingOnesignalId: String? get() = getOptStringProperty(::existingOnesignalId.name) - private set(value) { setOptStringProperty(::existingOnesignalId.name, value) } + private set(value) { + setOptStringProperty(::existingOnesignalId.name, value) + } override val createComparisonKey: String get() = "$appId.User.$onesignalId" override val modifyComparisonKey: String = "" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/RefreshUserOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/RefreshUserOperation.kt index f1227d9284..bba5e1708c 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/RefreshUserOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/RefreshUserOperation.kt @@ -15,7 +15,9 @@ class RefreshUserOperation() : Operation(RefreshUserOperationExecutor.REFRESH_US */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The user ID this subscription will be associated with. This ID *may* be locally generated @@ -23,7 +25,9 @@ class RefreshUserOperation() : Operation(RefreshUserOperationExecutor.REFRESH_US */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } override val createComparisonKey: String get() = "$appId.User.$onesignalId.Refresh" override val modifyComparisonKey: String get() = "$appId.User.$onesignalId.Refresh" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetAliasOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetAliasOperation.kt index 64a5859f0b..206c6d6556 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetAliasOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetAliasOperation.kt @@ -15,7 +15,9 @@ class SetAliasOperation() : Operation(IdentityOperationExecutor.SET_ALIAS) { */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The user ID this subscription will be associated with. This ID *may* be locally generated @@ -23,21 +25,27 @@ class SetAliasOperation() : Operation(IdentityOperationExecutor.SET_ALIAS) { */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The alias label. */ var label: String get() = getStringProperty(::label.name) - private set(value) { setStringProperty(::label.name, value) } + private set(value) { + setStringProperty(::label.name, value) + } /** * The alias value. */ var value: String get() = getStringProperty(::value.name) - private set(value) { setStringProperty(::value.name, value) } + private set(value) { + setStringProperty(::value.name, value) + } override val createComparisonKey: String get() = "" override val modifyComparisonKey: String get() = "$appId.User.$onesignalId.Identity.$label" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetPropertyOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetPropertyOperation.kt index d735e93b33..c441504e3f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetPropertyOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetPropertyOperation.kt @@ -14,7 +14,9 @@ class SetPropertyOperation() : Operation(UpdateUserOperationExecutor.SET_PROPERT */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The OneSignal ID the purchase was captured under. This ID *may* be locally generated @@ -22,21 +24,27 @@ class SetPropertyOperation() : Operation(UpdateUserOperationExecutor.SET_PROPERT */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The property that is to be updated against the user. */ var property: String get() = getStringProperty(::property.name) - private set(value) { setStringProperty(::property.name, value) } + private set(value) { + setStringProperty(::property.name, value) + } /** * The value of that property to update it to. */ var value: Any? get() = getOptAnyProperty(::value.name) - private set(value) { setOptAnyProperty(::value.name, value) } + private set(value) { + setOptAnyProperty(::value.name, value) + } override val createComparisonKey: String get() = "" override val modifyComparisonKey: String get() = createComparisonKey diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetTagOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetTagOperation.kt index 8eca0026e6..733d0efcb1 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetTagOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/SetTagOperation.kt @@ -15,7 +15,9 @@ class SetTagOperation() : Operation(UpdateUserOperationExecutor.SET_TAG) { */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The user ID this subscription will be associated with. This ID *may* be locally generated @@ -23,21 +25,27 @@ class SetTagOperation() : Operation(UpdateUserOperationExecutor.SET_TAG) { */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The tag key. */ var key: String get() = getStringProperty(::key.name) - private set(value) { setStringProperty(::key.name, value) } + private set(value) { + setStringProperty(::key.name, value) + } /** * The new/updated tag value. */ var value: String get() = getStringProperty(::value.name) - private set(value) { setStringProperty(::value.name, value) } + private set(value) { + setStringProperty(::value.name, value) + } override val createComparisonKey: String get() = "" override val modifyComparisonKey: String get() = createComparisonKey diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackPurchaseOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackPurchaseOperation.kt index 235e7fee70..1d7dafbfb1 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackPurchaseOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackPurchaseOperation.kt @@ -18,7 +18,9 @@ class TrackPurchaseOperation() : Operation(UpdateUserOperationExecutor.TRACK_PUR */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The OneSignal ID the purchase was captured under. This ID *may* be locally generated @@ -26,28 +28,36 @@ class TrackPurchaseOperation() : Operation(UpdateUserOperationExecutor.TRACK_PUR */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * Whether to treat new purchases as an existing purchase. */ var treatNewAsExisting: Boolean get() = getBooleanProperty(::treatNewAsExisting.name) - private set(value) { setBooleanProperty(::treatNewAsExisting.name, value) } + private set(value) { + setBooleanProperty(::treatNewAsExisting.name, value) + } /** * The amount spent by the user. */ var amountSpent: BigDecimal get() = getBigDecimalProperty(::amountSpent.name) - private set(value) { setBigDecimalProperty(::amountSpent.name, value) } + private set(value) { + setBigDecimalProperty(::amountSpent.name, value) + } /** * The list of purchases that have been made. */ var purchases: List get() = getListProperty(::purchases.name) - private set(value) { setListProperty(::purchases.name, value) } + private set(value) { + setListProperty(::purchases.name, value) + } override val createComparisonKey: String get() = "" override val modifyComparisonKey: String get() = "$appId.User.$onesignalId" @@ -68,7 +78,10 @@ class TrackPurchaseOperation() : Operation(UpdateUserOperationExecutor.TRACK_PUR } } - override fun createListForProperty(property: String, jsonArray: JSONArray): List<*>? { + override fun createListForProperty( + property: String, + jsonArray: JSONArray, + ): List<*>? { if (property == ::purchases.name) { val listOfPurchases = mutableListOf() for (item in 0 until jsonArray.length()) { @@ -89,15 +102,21 @@ class TrackPurchaseOperation() : Operation(UpdateUserOperationExecutor.TRACK_PUR class PurchaseInfo() : Model() { var sku: String get() = getStringProperty(::sku.name) - private set(value) { setStringProperty(::sku.name, value) } + private set(value) { + setStringProperty(::sku.name, value) + } var iso: String get() = getStringProperty(::iso.name) - private set(value) { setStringProperty(::iso.name, value) } + private set(value) { + setStringProperty(::iso.name, value) + } var amount: BigDecimal get() = getBigDecimalProperty(::amount.name) - private set(value) { setBigDecimalProperty(::amount.name, value) } + private set(value) { + setBigDecimalProperty(::amount.name, value) + } constructor(sku: String, iso: String, amount: BigDecimal) : this() { this.sku = sku diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackSessionEndOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackSessionEndOperation.kt index e08cf5b49c..7b5ef70442 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackSessionEndOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackSessionEndOperation.kt @@ -14,7 +14,9 @@ class TrackSessionEndOperation() : Operation(UpdateUserOperationExecutor.TRACK_S */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The OneSignal ID driving the session. This ID *may* be locally generated @@ -22,14 +24,18 @@ class TrackSessionEndOperation() : Operation(UpdateUserOperationExecutor.TRACK_S */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The amount of active time for the session, in milliseconds. */ var sessionTime: Long get() = getLongProperty(::sessionTime.name) - private set(value) { setLongProperty(::sessionTime.name, value) } + private set(value) { + setLongProperty(::sessionTime.name, value) + } override val createComparisonKey: String get() = "" override val modifyComparisonKey: String get() = "$appId.User.$onesignalId" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackSessionStartOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackSessionStartOperation.kt index db2818fdd6..4512857491 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackSessionStartOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TrackSessionStartOperation.kt @@ -14,7 +14,9 @@ class TrackSessionStartOperation() : Operation(UpdateUserOperationExecutor.TRACK */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The OneSignal ID driving the session. This ID *may* be locally generated @@ -22,7 +24,9 @@ class TrackSessionStartOperation() : Operation(UpdateUserOperationExecutor.TRACK */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } override val createComparisonKey: String get() = "" override val modifyComparisonKey: String get() = "$appId.User.$onesignalId" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TransferSubscriptionOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TransferSubscriptionOperation.kt index a1356eebf4..fce653c323 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TransferSubscriptionOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/TransferSubscriptionOperation.kt @@ -14,7 +14,9 @@ class TransferSubscriptionOperation() : Operation(SubscriptionOperationExecutor. */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The subscription ID that is to be transferred. This ID *may* be locally generated @@ -22,7 +24,9 @@ class TransferSubscriptionOperation() : Operation(SubscriptionOperationExecutor. */ var subscriptionId: String get() = getStringProperty(::subscriptionId.name) - private set(value) { setStringProperty(::subscriptionId.name, value) } + private set(value) { + setStringProperty(::subscriptionId.name, value) + } /** * The user ID this subscription will be transferred to. This ID *may* be locally generated @@ -30,7 +34,9 @@ class TransferSubscriptionOperation() : Operation(SubscriptionOperationExecutor. */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } override val createComparisonKey: String get() = "$appId.User.$onesignalId" override val modifyComparisonKey: String get() = "$appId.Subscription.$subscriptionId.Transfer" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/UpdateSubscriptionOperation.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/UpdateSubscriptionOperation.kt index 0e0a6853d0..38f3fa2108 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/UpdateSubscriptionOperation.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/UpdateSubscriptionOperation.kt @@ -16,7 +16,9 @@ class UpdateSubscriptionOperation() : Operation(SubscriptionOperationExecutor.UP */ var appId: String get() = getStringProperty(::appId.name) - private set(value) { setStringProperty(::appId.name, value) } + private set(value) { + setStringProperty(::appId.name, value) + } /** * The user ID this subscription will be associated with. This ID *may* be locally generated @@ -24,7 +26,9 @@ class UpdateSubscriptionOperation() : Operation(SubscriptionOperationExecutor.UP */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - private set(value) { setStringProperty(::onesignalId.name, value) } + private set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The subscription ID that is to be deleted. This ID *may* be locally generated @@ -32,21 +36,27 @@ class UpdateSubscriptionOperation() : Operation(SubscriptionOperationExecutor.UP */ var subscriptionId: String get() = getStringProperty(::subscriptionId.name) - private set(value) { setStringProperty(::subscriptionId.name, value) } + private set(value) { + setStringProperty(::subscriptionId.name, value) + } /** * The type of subscription. */ var type: SubscriptionType get() = getEnumProperty(::type.name) - private set(value) { setEnumProperty(::type.name, value) } + private set(value) { + setEnumProperty(::type.name, value) + } /** * Whether this subscription is currently enabled. */ var enabled: Boolean get() = getBooleanProperty(::enabled.name) - private set(value) { setBooleanProperty(::enabled.name, value) } + private set(value) { + setBooleanProperty(::enabled.name, value) + } /** * The address-specific information for this subscription. Its contents depends on the type @@ -58,14 +68,18 @@ class UpdateSubscriptionOperation() : Operation(SubscriptionOperationExecutor.UP */ var address: String get() = getStringProperty(::address.name) - private set(value) { setStringProperty(::address.name, value) } + private set(value) { + setStringProperty(::address.name, value) + } /** * The status of this subscription. */ var status: SubscriptionStatus get() = getEnumProperty(::status.name) - private set(value) { setEnumProperty(::status.name, value) } + private set(value) { + setEnumProperty(::status.name, value) + } override val createComparisonKey: String get() = "$appId.User.$onesignalId" override val modifyComparisonKey: String get() = "$appId.User.$onesignalId.Subscription.$subscriptionId" diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/IdentityOperationExecutor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/IdentityOperationExecutor.kt index 5d11f99fde..80b991b441 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/IdentityOperationExecutor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/IdentityOperationExecutor.kt @@ -20,7 +20,6 @@ internal class IdentityOperationExecutor( private val _identityModelStore: IdentityModelStore, private val _buildUserService: IRebuildUserService, ) : IOperationExecutor { - override val operations: List get() = listOf(SET_ALIAS, DELETE_ALIAS) @@ -69,7 +68,12 @@ internal class IdentityOperationExecutor( } } else if (lastOperation is DeleteAliasOperation) { try { - _identityBackend.deleteAlias(lastOperation.appId, IdentityConstants.ONESIGNAL_ID, lastOperation.onesignalId, lastOperation.label) + _identityBackend.deleteAlias( + lastOperation.appId, + IdentityConstants.ONESIGNAL_ID, + lastOperation.onesignalId, + lastOperation.label, + ) // ensure the now deleted alias is not in the model as long as the user is still current. if (_identityModelStore.model.onesignalId == lastOperation.onesignalId) { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserFromSubscriptionOperationExecutor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserFromSubscriptionOperationExecutor.kt index 6e2dfd057f..e60ee5b8dc 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserFromSubscriptionOperationExecutor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserFromSubscriptionOperationExecutor.kt @@ -21,7 +21,6 @@ internal class LoginUserFromSubscriptionOperationExecutor( private val _identityModelStore: IdentityModelStore, private val _propertiesModelStore: PropertiesModelStore, ) : IOperationExecutor { - override val operations: List get() = listOf(LOGIN_USER_FROM_SUBSCRIPTION_USER) @@ -39,10 +38,11 @@ internal class LoginUserFromSubscriptionOperationExecutor( private suspend fun loginUser(loginUserOp: LoginUserFromSubscriptionOperation): ExecutionResponse { try { - val identities = _subscriptionBackend.getIdentityFromSubscription( - loginUserOp.appId, - loginUserOp.subscriptionId, - ) + val identities = + _subscriptionBackend.getIdentityFromSubscription( + loginUserOp.appId, + loginUserOp.subscriptionId, + ) val backendOneSignalId = identities.getOrDefault(IdentityConstants.ONESIGNAL_ID, null) if (backendOneSignalId == null) { @@ -67,7 +67,11 @@ internal class LoginUserFromSubscriptionOperationExecutor( propertiesModel.setStringProperty(PropertiesModel::onesignalId.name, backendOneSignalId, ModelChangeTags.HYDRATE) } - return ExecutionResponse(ExecutionResult.SUCCESS, idTranslations, listOf(RefreshUserOperation(loginUserOp.appId, backendOneSignalId))) + return ExecutionResponse( + ExecutionResult.SUCCESS, + idTranslations, + listOf(RefreshUserOperation(loginUserOp.appId, backendOneSignalId)), + ) } catch (ex: BackendException) { val responseType = NetworkUtils.getResponseStatusType(ex.statusCode) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt index ac537a1e09..159ffa2a3f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt @@ -1,7 +1,12 @@ package com.onesignal.user.internal.operations.impl.executors import android.os.Build -import com.onesignal.common.* +import com.onesignal.common.AndroidUtils +import com.onesignal.common.DeviceUtils +import com.onesignal.common.NetworkUtils +import com.onesignal.common.OneSignalUtils +import com.onesignal.common.RootToolsInternalMethods +import com.onesignal.common.TimeUtils import com.onesignal.common.exceptions.BackendException import com.onesignal.common.modeling.ModelChangeTags import com.onesignal.core.internal.application.IApplicationService @@ -13,8 +18,10 @@ import com.onesignal.core.internal.operations.ExecutionResult import com.onesignal.core.internal.operations.IOperationExecutor import com.onesignal.core.internal.operations.Operation import com.onesignal.debug.internal.logging.Logging -import com.onesignal.user.internal.backend.* +import com.onesignal.user.internal.backend.IUserBackendService import com.onesignal.user.internal.backend.IdentityConstants +import com.onesignal.user.internal.backend.SubscriptionObject +import com.onesignal.user.internal.backend.SubscriptionObjectType import com.onesignal.user.internal.identity.IdentityModelStore import com.onesignal.user.internal.operations.CreateSubscriptionOperation import com.onesignal.user.internal.operations.DeleteSubscriptionOperation @@ -37,9 +44,8 @@ internal class LoginUserOperationExecutor( private val _propertiesModelStore: PropertiesModelStore, private val _subscriptionsModelStore: SubscriptionModelStore, private val _configModelStore: ConfigModelStore, - private val _languageContext: ILanguageContext + private val _languageContext: ILanguageContext, ) : IOperationExecutor { - override val operations: List get() = listOf(LOGIN_USER) @@ -55,7 +61,10 @@ internal class LoginUserOperationExecutor( throw Exception("Unrecognized operation: $startingOp") } - private suspend fun loginUser(loginUserOp: LoginUserOperation, operations: List): ExecutionResponse { + private suspend fun loginUser( + loginUserOp: LoginUserOperation, + operations: List, + ): ExecutionResponse { if (loginUserOp.existingOnesignalId == null || loginUserOp.externalId == null) { // When there is no existing user to attempt to associate with the externalId provided, we go right to // createUser. If there is no externalId provided this is an insert, if there is this will be an @@ -65,7 +74,17 @@ internal class LoginUserOperationExecutor( // before we create a user we attempt to associate the user defined by existingOnesignalId with the // externalId provided. If that association cannot be made, typically because the externalId is already // associated to a user, we fall back to our "upsert with retrieval" method. - val result = _identityOperationExecutor.execute(listOf(SetAliasOperation(loginUserOp.appId, loginUserOp.existingOnesignalId!!, IdentityConstants.EXTERNAL_ID, loginUserOp.externalId!!))) + val result = + _identityOperationExecutor.execute( + listOf( + SetAliasOperation( + loginUserOp.appId, + loginUserOp.existingOnesignalId!!, + IdentityConstants.EXTERNAL_ID, + loginUserOp.externalId!!, + ), + ), + ) return when (result.result) { ExecutionResult.SUCCESS -> { @@ -73,11 +92,19 @@ internal class LoginUserOperationExecutor( // because the set alias was successful any grouped operations could not be executed, let the // caller know those still need to be executed. if (_identityModelStore.model.onesignalId == loginUserOp.onesignalId) { - _identityModelStore.model.setStringProperty(IdentityConstants.ONESIGNAL_ID, backendOneSignalId, ModelChangeTags.HYDRATE) + _identityModelStore.model.setStringProperty( + IdentityConstants.ONESIGNAL_ID, + backendOneSignalId, + ModelChangeTags.HYDRATE, + ) } if (_propertiesModelStore.model.onesignalId == loginUserOp.onesignalId) { - _propertiesModelStore.model.setStringProperty(PropertiesModel::onesignalId.name, backendOneSignalId, ModelChangeTags.HYDRATE) + _propertiesModelStore.model.setStringProperty( + PropertiesModel::onesignalId.name, + backendOneSignalId, + ModelChangeTags.HYDRATE, + ) } ExecutionResponse(ExecutionResult.SUCCESS_STARTING_ONLY, mapOf(loginUserOp.onesignalId to backendOneSignalId)) @@ -86,12 +113,16 @@ internal class LoginUserOperationExecutor( // When the SetAliasOperation fails with conflict that *most likely* means the externalId provided // is already associated to a user. This *expected* condition means we must create a user. // We hardcode the response of "user-2" in the log to provide information to the SDK consumer - Logging.debug("LoginUserOperationExecutor now handling 409 response with \"code\": \"user-2\" by switching to user with \"external_id\": \"${loginUserOp.externalId}\"") + Logging.debug( + "LoginUserOperationExecutor now handling 409 response with \"code\": \"user-2\" by switching to user with \"external_id\": \"${loginUserOp.externalId}\"", + ) createUser(loginUserOp, operations) } ExecutionResult.FAIL_NORETRY -> { // Some other failure occurred, still try to recover by creating the user - Logging.error("LoginUserOperationExecutor encountered error. Attempt to recover by switching to user with \"external_id\": \"${loginUserOp.externalId}\"") + Logging.error( + "LoginUserOperationExecutor encountered error. Attempt to recover by switching to user with \"external_id\": \"${loginUserOp.externalId}\"", + ) createUser(loginUserOp, operations) } else -> ExecutionResponse(result.result) @@ -99,7 +130,10 @@ internal class LoginUserOperationExecutor( } } - private suspend fun createUser(createUserOperation: LoginUserOperation, operations: List): ExecutionResponse { + private suspend fun createUser( + createUserOperation: LoginUserOperation, + operations: List, + ): ExecutionResponse { var identities = mapOf() var subscriptions = mapOf() val properties = mutableMapOf() @@ -176,23 +210,27 @@ internal class LoginUserOperationExecutor( } } - private fun createSubscriptionsFromOperation(operation: TransferSubscriptionOperation, subscriptions: Map): Map { + private fun createSubscriptionsFromOperation( + operation: TransferSubscriptionOperation, + subscriptions: Map, + ): Map { val mutableSubscriptions = subscriptions.toMutableMap() if (mutableSubscriptions.containsKey(operation.subscriptionId)) { - mutableSubscriptions[operation.subscriptionId] = SubscriptionObject( - operation.subscriptionId, - subscriptions[operation.subscriptionId]!!.type, - subscriptions[operation.subscriptionId]!!.token, - subscriptions[operation.subscriptionId]!!.enabled, - subscriptions[operation.subscriptionId]!!.notificationTypes, - subscriptions[operation.subscriptionId]!!.sdk, - subscriptions[operation.subscriptionId]!!.deviceModel, - subscriptions[operation.subscriptionId]!!.deviceOS, - subscriptions[operation.subscriptionId]!!.rooted, - subscriptions[operation.subscriptionId]!!.netType, - subscriptions[operation.subscriptionId]!!.carrier, - subscriptions[operation.subscriptionId]!!.appVersion, - ) + mutableSubscriptions[operation.subscriptionId] = + SubscriptionObject( + operation.subscriptionId, + subscriptions[operation.subscriptionId]!!.type, + subscriptions[operation.subscriptionId]!!.token, + subscriptions[operation.subscriptionId]!!.enabled, + subscriptions[operation.subscriptionId]!!.notificationTypes, + subscriptions[operation.subscriptionId]!!.sdk, + subscriptions[operation.subscriptionId]!!.deviceModel, + subscriptions[operation.subscriptionId]!!.deviceOS, + subscriptions[operation.subscriptionId]!!.rooted, + subscriptions[operation.subscriptionId]!!.netType, + subscriptions[operation.subscriptionId]!!.carrier, + subscriptions[operation.subscriptionId]!!.appVersion, + ) } else { mutableSubscriptions[operation.subscriptionId] = SubscriptionObject(operation.subscriptionId) } @@ -200,60 +238,72 @@ internal class LoginUserOperationExecutor( return mutableSubscriptions } - private fun createSubscriptionsFromOperation(operation: CreateSubscriptionOperation, subscriptions: Map): Map { + private fun createSubscriptionsFromOperation( + operation: CreateSubscriptionOperation, + subscriptions: Map, + ): Map { val mutableSubscriptions = subscriptions.toMutableMap() - val subscriptionType: SubscriptionObjectType = when (operation.type) { - SubscriptionType.SMS -> { - SubscriptionObjectType.SMS - } - SubscriptionType.EMAIL -> { - SubscriptionObjectType.EMAIL - } - else -> { - SubscriptionObjectType.fromDeviceType(_deviceService.deviceType) + val subscriptionType: SubscriptionObjectType = + when (operation.type) { + SubscriptionType.SMS -> { + SubscriptionObjectType.SMS + } + SubscriptionType.EMAIL -> { + SubscriptionObjectType.EMAIL + } + else -> { + SubscriptionObjectType.fromDeviceType(_deviceService.deviceType) + } } - } - mutableSubscriptions[operation.subscriptionId] = SubscriptionObject( - id = null, - subscriptionType, - operation.address, - operation.enabled, - operation.status.value, - OneSignalUtils.sdkVersion, - Build.MODEL, - Build.VERSION.RELEASE, - RootToolsInternalMethods.isRooted, - DeviceUtils.getNetType(_application.appContext), - DeviceUtils.getCarrierName(_application.appContext), - AndroidUtils.getAppVersion(_application.appContext), - ) + mutableSubscriptions[operation.subscriptionId] = + SubscriptionObject( + id = null, + subscriptionType, + operation.address, + operation.enabled, + operation.status.value, + OneSignalUtils.SDK_VERSION, + Build.MODEL, + Build.VERSION.RELEASE, + RootToolsInternalMethods.isRooted, + DeviceUtils.getNetType(_application.appContext), + DeviceUtils.getCarrierName(_application.appContext), + AndroidUtils.getAppVersion(_application.appContext), + ) return mutableSubscriptions } - private fun createSubscriptionsFromOperation(operation: UpdateSubscriptionOperation, subscriptions: Map): Map { + private fun createSubscriptionsFromOperation( + operation: UpdateSubscriptionOperation, + subscriptions: Map, + ): Map { val mutableSubscriptions = subscriptions.toMutableMap() if (mutableSubscriptions.containsKey(operation.subscriptionId)) { - mutableSubscriptions[operation.subscriptionId] = SubscriptionObject( - subscriptions[operation.subscriptionId]!!.id, - subscriptions[operation.subscriptionId]!!.type, - operation.address, - operation.enabled, - operation.status.value, - subscriptions[operation.subscriptionId]!!.sdk, - subscriptions[operation.subscriptionId]!!.deviceModel, - subscriptions[operation.subscriptionId]!!.deviceOS, - subscriptions[operation.subscriptionId]!!.rooted, - subscriptions[operation.subscriptionId]!!.netType, - subscriptions[operation.subscriptionId]!!.carrier, - subscriptions[operation.subscriptionId]!!.appVersion, - ) + mutableSubscriptions[operation.subscriptionId] = + SubscriptionObject( + subscriptions[operation.subscriptionId]!!.id, + subscriptions[operation.subscriptionId]!!.type, + operation.address, + operation.enabled, + operation.status.value, + subscriptions[operation.subscriptionId]!!.sdk, + subscriptions[operation.subscriptionId]!!.deviceModel, + subscriptions[operation.subscriptionId]!!.deviceOS, + subscriptions[operation.subscriptionId]!!.rooted, + subscriptions[operation.subscriptionId]!!.netType, + subscriptions[operation.subscriptionId]!!.carrier, + subscriptions[operation.subscriptionId]!!.appVersion, + ) } return mutableSubscriptions } - private fun createSubscriptionsFromOperation(operation: DeleteSubscriptionOperation, subscriptions: Map): Map { + private fun createSubscriptionsFromOperation( + operation: DeleteSubscriptionOperation, + subscriptions: Map, + ): Map { val mutableSubscriptions = subscriptions.toMutableMap() mutableSubscriptions.remove(operation.subscriptionId) return mutableSubscriptions diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/PropertyOperationHelper.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/PropertyOperationHelper.kt index c12501ccda..f6a136cac3 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/PropertyOperationHelper.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/PropertyOperationHelper.kt @@ -7,37 +7,108 @@ import com.onesignal.user.internal.operations.SetTagOperation import com.onesignal.user.internal.properties.PropertiesModel internal object PropertyOperationHelper { - fun createPropertiesFromOperation(operation: SetTagOperation, propertiesObject: PropertiesObject): PropertiesObject { + fun createPropertiesFromOperation( + operation: SetTagOperation, + propertiesObject: PropertiesObject, + ): PropertiesObject { var tags = propertiesObject.tags?.toMutableMap() if (tags == null) { tags = mutableMapOf() } tags[operation.key] = operation.value - return PropertiesObject(tags, propertiesObject.language, propertiesObject.timezoneId, propertiesObject.country, propertiesObject.latitude, propertiesObject.longitude) + return PropertiesObject( + tags, + propertiesObject.language, + propertiesObject.timezoneId, + propertiesObject.country, + propertiesObject.latitude, + propertiesObject.longitude, + ) } - fun createPropertiesFromOperation(operation: DeleteTagOperation, propertiesObject: PropertiesObject): PropertiesObject { + fun createPropertiesFromOperation( + operation: DeleteTagOperation, + propertiesObject: PropertiesObject, + ): PropertiesObject { var tags = propertiesObject.tags?.toMutableMap() if (tags == null) { tags = mutableMapOf() } tags[operation.key] = null - return PropertiesObject(tags, propertiesObject.language, propertiesObject.timezoneId, propertiesObject.country, propertiesObject.latitude, propertiesObject.longitude) + return PropertiesObject( + tags, + propertiesObject.language, + propertiesObject.timezoneId, + propertiesObject.country, + propertiesObject.latitude, + propertiesObject.longitude, + ) } - fun createPropertiesFromOperation(operation: SetPropertyOperation, propertiesObject: PropertiesObject): PropertiesObject { + fun createPropertiesFromOperation( + operation: SetPropertyOperation, + propertiesObject: PropertiesObject, + ): PropertiesObject { return when (operation.property) { - PropertiesModel::language.name -> PropertiesObject(propertiesObject.tags, operation.value?.toString(), propertiesObject.timezoneId, propertiesObject.country, propertiesObject.latitude, propertiesObject.longitude) - PropertiesModel::timezone.name -> PropertiesObject(propertiesObject.tags, propertiesObject.language, operation.value?.toString(), propertiesObject.country, propertiesObject.latitude, propertiesObject.longitude) - PropertiesModel::country.name -> PropertiesObject(propertiesObject.tags, propertiesObject.language, propertiesObject.timezoneId, operation.value?.toString(), propertiesObject.latitude, propertiesObject.longitude) - PropertiesModel::locationLatitude.name -> PropertiesObject(propertiesObject.tags, propertiesObject.language, propertiesObject.timezoneId, propertiesObject.country, operation.value?.toString()?.toDouble(), propertiesObject.longitude) - PropertiesModel::locationLongitude.name -> PropertiesObject(propertiesObject.tags, propertiesObject.language, propertiesObject.timezoneId, propertiesObject.country, propertiesObject.latitude, operation.value?.toString()?.toDouble()) + PropertiesModel::language.name -> + PropertiesObject( + propertiesObject.tags, + operation.value?.toString(), + propertiesObject.timezoneId, + propertiesObject.country, + propertiesObject.latitude, + propertiesObject.longitude, + ) + PropertiesModel::timezone.name -> + PropertiesObject( + propertiesObject.tags, + propertiesObject.language, + operation.value?.toString(), + propertiesObject.country, + propertiesObject.latitude, + propertiesObject.longitude, + ) + PropertiesModel::country.name -> + PropertiesObject( + propertiesObject.tags, + propertiesObject.language, + propertiesObject.timezoneId, + operation.value?.toString(), + propertiesObject.latitude, + propertiesObject.longitude, + ) + PropertiesModel::locationLatitude.name -> + PropertiesObject( + propertiesObject.tags, + propertiesObject.language, + propertiesObject.timezoneId, + propertiesObject.country, + operation.value?.toString()?.toDouble(), + propertiesObject.longitude, + ) + PropertiesModel::locationLongitude.name -> + PropertiesObject( + propertiesObject.tags, + propertiesObject.language, + propertiesObject.timezoneId, + propertiesObject.country, + propertiesObject.latitude, + operation.value?.toString()?.toDouble(), + ) // PropertiesModel::locationAccuracy.name -> PropertiesObject(propertiesObject.tags, propertiesObject.language, propertiesObject.timezoneId, propertiesObject.country, propertiesObject.latitude, propertiesObject.longitude) // PropertiesModel::locationType.name -> PropertiesObject(propertiesObject.tags, propertiesObject.language, propertiesObject.timezoneId, propertiesObject.country, propertiesObject.latitude, propertiesObject.longitude) // PropertiesModel::locationBackground.name -> PropertiesObject(propertiesObject.tags, propertiesObject.language, propertiesObject.timezoneId, propertiesObject.country, propertiesObject.latitude, propertiesObject.longitude) // PropertiesModel::locationTimestamp.name -> PropertiesObject(propertiesObject.tags, propertiesObject.language, propertiesObject.timezoneId, propertiesObject.country, propertiesObject.latitude, propertiesObject.longitude) - else -> PropertiesObject(propertiesObject.tags, propertiesObject.language, propertiesObject.timezoneId, propertiesObject.country, propertiesObject.latitude, propertiesObject.longitude) + else -> + PropertiesObject( + propertiesObject.tags, + propertiesObject.language, + propertiesObject.timezoneId, + propertiesObject.country, + propertiesObject.latitude, + propertiesObject.longitude, + ) } } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/RefreshUserOperationExecutor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/RefreshUserOperationExecutor.kt index c178eb0b07..7ee10334dd 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/RefreshUserOperationExecutor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/RefreshUserOperationExecutor.kt @@ -32,7 +32,6 @@ internal class RefreshUserOperationExecutor( private val _configModelStore: ConfigModelStore, private val _buildUserService: IRebuildUserService, ) : IOperationExecutor { - override val operations: List get() = listOf(REFRESH_USER) @@ -49,11 +48,12 @@ internal class RefreshUserOperationExecutor( private suspend fun getUser(op: RefreshUserOperation): ExecutionResponse { try { - val response = _userBackend.getUser( - op.appId, - IdentityConstants.ONESIGNAL_ID, - op.onesignalId, - ) + val response = + _userBackend.getUser( + op.appId, + IdentityConstants.ONESIGNAL_ID, + op.onesignalId, + ) if (op.onesignalId != _identityModelStore.model.onesignalId) { return ExecutionResponse(ExecutionResult.SUCCESS) @@ -93,17 +93,18 @@ internal class RefreshUserOperationExecutor( subscriptionModel.id = subscription.id!! subscriptionModel.address = subscription.token ?: "" subscriptionModel.status = SubscriptionStatus.fromInt(subscription.notificationTypes ?: SubscriptionStatus.SUBSCRIBED.value) ?: SubscriptionStatus.SUBSCRIBED - subscriptionModel.type = when (subscription.type!!) { - SubscriptionObjectType.EMAIL -> { - SubscriptionType.EMAIL - } - SubscriptionObjectType.SMS -> { - SubscriptionType.SMS + subscriptionModel.type = + when (subscription.type!!) { + SubscriptionObjectType.EMAIL -> { + SubscriptionType.EMAIL + } + SubscriptionObjectType.SMS -> { + SubscriptionType.SMS + } + else -> { + SubscriptionType.PUSH + } } - else -> { - SubscriptionType.PUSH - } - } subscriptionModel.optedIn = subscriptionModel.status != SubscriptionStatus.UNSUBSCRIBE // We only add a push subscription if it is this device's push subscription. diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/SubscriptionOperationExecutor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/SubscriptionOperationExecutor.kt index 65c1c1cdad..a13f47c3f6 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/SubscriptionOperationExecutor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/SubscriptionOperationExecutor.kt @@ -38,7 +38,6 @@ internal class SubscriptionOperationExecutor( private val _configModelStore: ConfigModelStore, private val _buildUserService: IRebuildUserService, ) : IOperationExecutor { - override val operations: List get() = listOf(CREATE_SUBSCRIPTION, UPDATE_SUBSCRIPTION, DELETE_SUBSCRIPTION, TRANSFER_SUBSCRIPTION) @@ -60,7 +59,10 @@ internal class SubscriptionOperationExecutor( } } - private suspend fun createSubscription(createOperation: CreateSubscriptionOperation, operations: List): ExecutionResponse { + private suspend fun createSubscription( + createOperation: CreateSubscriptionOperation, + operations: List, + ): ExecutionResponse { // if there are any deletes all operations should be tossed, nothing to do. if (operations.any { it is DeleteSubscriptionOperation }) { return ExecutionResponse(ExecutionResult.SUCCESS) @@ -74,27 +76,29 @@ internal class SubscriptionOperationExecutor( val status = lastUpdateOperation?.status ?: createOperation.status try { - val subscription = SubscriptionObject( - id = null, - convert(createOperation.type), - address, - enabled, - status.value, - OneSignalUtils.sdkVersion, - Build.MODEL, - Build.VERSION.RELEASE, - RootToolsInternalMethods.isRooted, - DeviceUtils.getNetType(_applicationService.appContext), - DeviceUtils.getCarrierName(_applicationService.appContext), - AndroidUtils.getAppVersion(_applicationService.appContext), - ) + val subscription = + SubscriptionObject( + id = null, + convert(createOperation.type), + address, + enabled, + status.value, + OneSignalUtils.SDK_VERSION, + Build.MODEL, + Build.VERSION.RELEASE, + RootToolsInternalMethods.isRooted, + DeviceUtils.getNetType(_applicationService.appContext), + DeviceUtils.getCarrierName(_applicationService.appContext), + AndroidUtils.getAppVersion(_applicationService.appContext), + ) - val backendSubscriptionId = _subscriptionBackend.createSubscription( - createOperation.appId, - IdentityConstants.ONESIGNAL_ID, - createOperation.onesignalId, - subscription, - ) ?: return ExecutionResponse(ExecutionResult.SUCCESS) + val backendSubscriptionId = + _subscriptionBackend.createSubscription( + createOperation.appId, + IdentityConstants.ONESIGNAL_ID, + createOperation.onesignalId, + subscription, + ) ?: return ExecutionResponse(ExecutionResult.SUCCESS) // update the subscription model with the new ID, if it's still active. val subscriptionModel = _subscriptionModelStore.get(createOperation.subscriptionId) @@ -136,24 +140,28 @@ internal class SubscriptionOperationExecutor( } } - private suspend fun updateSubscription(startingOperation: UpdateSubscriptionOperation, operations: List): ExecutionResponse { + private suspend fun updateSubscription( + startingOperation: UpdateSubscriptionOperation, + operations: List, + ): ExecutionResponse { // the effective enabled/address is the last update performed val lastOperation = operations.last() as UpdateSubscriptionOperation try { - val subscription = SubscriptionObject( - id = null, - convert(lastOperation.type), - lastOperation.address, - lastOperation.enabled, - lastOperation.status.value, - OneSignalUtils.sdkVersion, - Build.MODEL, - Build.VERSION.RELEASE, - RootToolsInternalMethods.isRooted, - DeviceUtils.getNetType(_applicationService.appContext), - DeviceUtils.getCarrierName(_applicationService.appContext), - AndroidUtils.getAppVersion(_applicationService.appContext), - ) + val subscription = + SubscriptionObject( + id = null, + convert(lastOperation.type), + lastOperation.address, + lastOperation.enabled, + lastOperation.status.value, + OneSignalUtils.SDK_VERSION, + Build.MODEL, + Build.VERSION.RELEASE, + RootToolsInternalMethods.isRooted, + DeviceUtils.getNetType(_applicationService.appContext), + DeviceUtils.getCarrierName(_applicationService.appContext), + AndroidUtils.getAppVersion(_applicationService.appContext), + ) _subscriptionBackend.updateSubscription(lastOperation.appId, lastOperation.subscriptionId, subscription) } catch (ex: BackendException) { @@ -164,7 +172,21 @@ internal class SubscriptionOperationExecutor( ExecutionResponse(ExecutionResult.FAIL_RETRY) NetworkUtils.ResponseStatusType.MISSING -> // toss this, but create an identical CreateSubscriptionOperation to re-create the subscription being updated. - ExecutionResponse(ExecutionResult.FAIL_NORETRY, operations = listOf(CreateSubscriptionOperation(lastOperation.appId, lastOperation.onesignalId, lastOperation.subscriptionId, lastOperation.type, lastOperation.enabled, lastOperation.address, lastOperation.status))) + ExecutionResponse( + ExecutionResult.FAIL_NORETRY, + operations = + listOf( + CreateSubscriptionOperation( + lastOperation.appId, + lastOperation.onesignalId, + lastOperation.subscriptionId, + lastOperation.type, + lastOperation.enabled, + lastOperation.address, + lastOperation.status, + ), + ), + ) else -> ExecutionResponse(ExecutionResult.FAIL_NORETRY) } @@ -175,7 +197,12 @@ internal class SubscriptionOperationExecutor( private suspend fun transferSubscription(startingOperation: TransferSubscriptionOperation): ExecutionResponse { try { - _subscriptionBackend.transferSubscription(startingOperation.appId, startingOperation.subscriptionId, IdentityConstants.ONESIGNAL_ID, startingOperation.onesignalId) + _subscriptionBackend.transferSubscription( + startingOperation.appId, + startingOperation.subscriptionId, + IdentityConstants.ONESIGNAL_ID, + startingOperation.onesignalId, + ) } catch (ex: BackendException) { val responseType = NetworkUtils.getResponseStatusType(ex.statusCode) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/UpdateUserOperationExecutor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/UpdateUserOperationExecutor.kt index db5d812504..19551eaca1 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/UpdateUserOperationExecutor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/UpdateUserOperationExecutor.kt @@ -30,7 +30,6 @@ internal class UpdateUserOperationExecutor( private val _propertiesModelStore: PropertiesModelStore, private val _buildUserService: IRebuildUserService, ) : IOperationExecutor { - override val operations: List get() = listOf(SET_TAG, DELETE_TAG, SET_PROPERTY, TRACK_SESSION_START, TRACK_SESSION_END, TRACK_PURCHASE) @@ -120,15 +119,37 @@ internal class UpdateUserOperationExecutor( if (appId != null && onesignalId != null) { try { - _userBackend.updateUser(appId, IdentityConstants.ONESIGNAL_ID, onesignalId, propertiesObject, refreshDeviceMetadata, deltasObject) + _userBackend.updateUser( + appId, + IdentityConstants.ONESIGNAL_ID, + onesignalId, + propertiesObject, + refreshDeviceMetadata, + deltasObject, + ) if (_identityModelStore.model.onesignalId == onesignalId) { // go through and make sure any properties are in the correct model state for (operation in ops) { when (operation) { - is SetTagOperation -> _propertiesModelStore.model.tags.setStringProperty(operation.key, operation.value, ModelChangeTags.HYDRATE) - is DeleteTagOperation -> _propertiesModelStore.model.tags.setOptStringProperty(operation.key, null, ModelChangeTags.HYDRATE) - is SetPropertyOperation -> _propertiesModelStore.model.setOptAnyProperty(operation.property, operation.value, ModelChangeTags.HYDRATE) + is SetTagOperation -> + _propertiesModelStore.model.tags.setStringProperty( + operation.key, + operation.value, + ModelChangeTags.HYDRATE, + ) + is DeleteTagOperation -> + _propertiesModelStore.model.tags.setOptStringProperty( + operation.key, + null, + ModelChangeTags.HYDRATE, + ) + is SetPropertyOperation -> + _propertiesModelStore.model.setOptAnyProperty( + operation.property, + operation.value, + ModelChangeTags.HYDRATE, + ) } } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/IdentityModelStoreListener.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/IdentityModelStoreListener.kt index 839513bbcf..90a565a5a2 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/IdentityModelStoreListener.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/IdentityModelStoreListener.kt @@ -14,13 +14,18 @@ internal class IdentityModelStoreListener( opRepo: IOperationRepo, private val _configModelStore: ConfigModelStore, ) : SingletonModelStoreListener(store, opRepo) { - override fun getReplaceOperation(model: IdentityModel): Operation? { // when the identity model is replaced, nothing to do on the backend. Already handled via login process. return null } - override fun getUpdateOperation(model: IdentityModel, path: String, property: String, oldValue: Any?, newValue: Any?): Operation { + override fun getUpdateOperation( + model: IdentityModel, + path: String, + property: String, + oldValue: Any?, + newValue: Any?, + ): Operation { return if (newValue != null && newValue is String) { SetAliasOperation(_configModelStore.model.appId, model.onesignalId, property, newValue) } else { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/PropertiesModelStoreListener.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/PropertiesModelStoreListener.kt index 13c199ab03..d020c5cc66 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/PropertiesModelStoreListener.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/PropertiesModelStoreListener.kt @@ -15,13 +15,18 @@ internal class PropertiesModelStoreListener( opRepo: IOperationRepo, private val _configModelStore: ConfigModelStore, ) : SingletonModelStoreListener(store, opRepo) { - override fun getReplaceOperation(model: PropertiesModel): Operation? { // when the property model is replaced, nothing to do on the backend. Already handled via login process. return null } - override fun getUpdateOperation(model: PropertiesModel, path: String, property: String, oldValue: Any?, newValue: Any?): Operation? { + override fun getUpdateOperation( + model: PropertiesModel, + path: String, + property: String, + oldValue: Any?, + newValue: Any?, + ): Operation? { // for any of the property changes, we do not need to fire an operation. if (path.startsWith(PropertiesModel::locationTimestamp.name) || path.startsWith(PropertiesModel::locationBackground.name) || diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/SubscriptionModelStoreListener.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/SubscriptionModelStoreListener.kt index fd28027c74..f0002940e9 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/SubscriptionModelStoreListener.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/listeners/SubscriptionModelStoreListener.kt @@ -18,19 +18,40 @@ internal class SubscriptionModelStoreListener( private val _identityModelStore: IdentityModelStore, private val _configModelStore: ConfigModelStore, ) : ModelStoreListener(store, opRepo) { - override fun getAddOperation(model: SubscriptionModel): Operation { val enabledAndStatus = getSubscriptionEnabledAndStatus(model) - return CreateSubscriptionOperation(_configModelStore.model.appId, _identityModelStore.model.onesignalId, model.id, model.type, enabledAndStatus.first, model.address, enabledAndStatus.second) + return CreateSubscriptionOperation( + _configModelStore.model.appId, + _identityModelStore.model.onesignalId, + model.id, + model.type, + enabledAndStatus.first, + model.address, + enabledAndStatus.second, + ) } override fun getRemoveOperation(model: SubscriptionModel): Operation { return DeleteSubscriptionOperation(_configModelStore.model.appId, _identityModelStore.model.onesignalId, model.id) } - override fun getUpdateOperation(model: SubscriptionModel, path: String, property: String, oldValue: Any?, newValue: Any?): Operation { + override fun getUpdateOperation( + model: SubscriptionModel, + path: String, + property: String, + oldValue: Any?, + newValue: Any?, + ): Operation { val enabledAndStatus = getSubscriptionEnabledAndStatus(model) - return UpdateSubscriptionOperation(_configModelStore.model.appId, _identityModelStore.model.onesignalId, model.id, model.type, enabledAndStatus.first, model.address, enabledAndStatus.second) + return UpdateSubscriptionOperation( + _configModelStore.model.appId, + _identityModelStore.model.onesignalId, + model.id, + model.type, + enabledAndStatus.first, + model.address, + enabledAndStatus.second, + ) } companion object { @@ -43,11 +64,12 @@ internal class SubscriptionModelStoreListener( status = SubscriptionStatus.SUBSCRIBED } else { enabled = false - status = if (!model.optedIn) { - SubscriptionStatus.UNSUBSCRIBE - } else { - model.status - } + status = + if (!model.optedIn) { + SubscriptionStatus.UNSUBSCRIBE + } else { + model.status + } } return Pair(enabled, status) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/properties/PropertiesModel.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/properties/PropertiesModel.kt index 7000afd0c8..be268f9c8a 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/properties/PropertiesModel.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/properties/PropertiesModel.kt @@ -10,7 +10,9 @@ class PropertiesModel : Model() { */ var onesignalId: String get() = getStringProperty(::onesignalId.name) - set(value) { setStringProperty(::onesignalId.name, value) } + set(value) { + setStringProperty(::onesignalId.name, value) + } /** * The language for this user (ISO 639-1 format). When `null` the device default will be used. @@ -19,7 +21,9 @@ class PropertiesModel : Model() { */ var language: String? get() = getOptStringProperty(::language.name) - set(value) { setOptStringProperty(::language.name, value) } + set(value) { + setOptStringProperty(::language.name, value) + } /** * The country code for this user (ISO 3166-1 Alpha 2 format). When `null` the default will @@ -29,7 +33,9 @@ class PropertiesModel : Model() { */ var country: String get() = getStringProperty(::country.name) { "US" } - set(value) { setStringProperty(::country.name, value) } + set(value) { + setStringProperty(::country.name, value) + } /** * The timezone for this user (TZ database name). @@ -38,7 +44,9 @@ class PropertiesModel : Model() { */ var timezone: String? get() = getOptStringProperty(::timezone.name) - set(value) { setOptStringProperty(::timezone.name, value) } + set(value) { + setOptStringProperty(::timezone.name, value) + } /** * The data tags for this user. @@ -51,44 +59,59 @@ class PropertiesModel : Model() { */ var locationLatitude: Double? get() = getOptDoubleProperty(::locationLatitude.name) - set(value) { setOptDoubleProperty(::locationLatitude.name, value) } + set(value) { + setOptDoubleProperty(::locationLatitude.name, value) + } /** * The user's last known location longitude reading. */ var locationLongitude: Double? get() = getOptDoubleProperty(::locationLongitude.name) - set(value) { setOptDoubleProperty(::locationLongitude.name, value) } + set(value) { + setOptDoubleProperty(::locationLongitude.name, value) + } /** * The user's last location accuracy reading. */ var locationAccuracy: Float? get() = getOptFloatProperty(::locationAccuracy.name) - set(value) { setOptFloatProperty(::locationAccuracy.name, value) } + set(value) { + setOptFloatProperty(::locationAccuracy.name, value) + } /** * The user's last location type reading (0 - COARSE, 1 - FINE). */ var locationType: Int? get() = getOptIntProperty(::locationType.name) - set(value) { setOptIntProperty(::locationType.name, value) } + set(value) { + setOptIntProperty(::locationType.name, value) + } /** * Whether the user's last location reading was done with the app in the background. */ var locationBackground: Boolean? get() = getOptBooleanProperty(::locationBackground.name) - set(value) { setOptBooleanProperty(::locationBackground.name, value) } + set(value) { + setOptBooleanProperty(::locationBackground.name, value) + } /** * When the user's last location reading was. */ var locationTimestamp: Long? get() = getOptLongProperty(::locationTimestamp.name) - set(value) { setOptLongProperty(::locationTimestamp.name, value) } + set(value) { + setOptLongProperty(::locationTimestamp.name, value) + } - override fun createModelForProperty(property: String, jsonObject: JSONObject): Model? { + override fun createModelForProperty( + property: String, + jsonObject: JSONObject, + ): Model? { if (property == ::tags.name) { val model = MapModel(this, ::tags.name) model.initializeFromJson(jsonObject) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/ISubscriptionManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/ISubscriptionManager.kt index 0316049bef..4df6412733 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/ISubscriptionManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/ISubscriptionManager.kt @@ -8,15 +8,28 @@ interface ISubscriptionManager : IEventNotifier { var subscriptions: SubscriptionList val pushSubscriptionModel: SubscriptionModel + fun addEmailSubscription(email: String) - fun addOrUpdatePushSubscription(pushToken: String?, pushTokenStatus: SubscriptionStatus) + + fun addOrUpdatePushSubscription( + pushToken: String?, + pushTokenStatus: SubscriptionStatus, + ) + fun addSmsSubscription(sms: String) + fun removeEmailSubscription(email: String) + fun removeSmsSubscription(sms: String) } interface ISubscriptionChangedHandler { fun onSubscriptionAdded(subscription: ISubscription) - fun onSubscriptionChanged(subscription: ISubscription, args: ModelChangedArgs) + + fun onSubscriptionChanged( + subscription: ISubscription, + args: ModelChangedArgs, + ) + fun onSubscriptionRemoved(subscription: ISubscription) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionList.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionList.kt index d0769e9f8b..7bfd086105 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionList.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionList.kt @@ -10,7 +10,6 @@ import com.onesignal.user.subscriptions.ISubscription * subscriptions. The full list can be accessed via [SubscriptionList.collection]. */ class SubscriptionList(val collection: List, private val _fallbackPushSub: IPushSubscription) { - /** * Retrieve the push subscription for this user on the current device. */ diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionModel.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionModel.kt index f46f8bc161..f8ff8b206a 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionModel.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionModel.kt @@ -48,11 +48,13 @@ enum class SubscriptionStatus(val value: Int) { FIREBASE_FCM_ERROR_MISC_EXCEPTION(-12), // -13 to -24 reserved for other platforms + /** The subscription is not enabled due the an HMS timeout, this can be retried */ HMS_TOKEN_TIMEOUT(-25), // Most likely missing "client/app_id". // Check that there is "apply plugin: 'com.huawei.agconnect'" in your app/build.gradle + /** The subscription is not enabled due to the HMS arguments being invalid */ HMS_ARGUMENTS_INVALID(-26), diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionModelStore.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionModelStore.kt index 7253a52b4c..1e76b8a892 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionModelStore.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionModelStore.kt @@ -3,4 +3,6 @@ package com.onesignal.user.internal.subscriptions import com.onesignal.common.modeling.SimpleModelStore import com.onesignal.core.internal.preferences.IPreferencesService -open class SubscriptionModelStore(prefs: IPreferencesService) : SimpleModelStore({ SubscriptionModel() }, "subscriptions", prefs) +open class SubscriptionModelStore(prefs: IPreferencesService) : SimpleModelStore({ + SubscriptionModel() +}, "subscriptions", prefs) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/impl/SubscriptionManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/impl/SubscriptionManager.kt index a76fd78842..6f8c465695 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/impl/SubscriptionManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/impl/SubscriptionManager.kt @@ -13,12 +13,12 @@ import com.onesignal.user.internal.Subscription import com.onesignal.user.internal.UninitializedPushSubscription import com.onesignal.user.internal.subscriptions.ISubscriptionChangedHandler import com.onesignal.user.internal.subscriptions.ISubscriptionManager +import com.onesignal.user.internal.subscriptions.SubscriptionList import com.onesignal.user.internal.subscriptions.SubscriptionModel import com.onesignal.user.internal.subscriptions.SubscriptionModelStore import com.onesignal.user.internal.subscriptions.SubscriptionStatus import com.onesignal.user.internal.subscriptions.SubscriptionType import com.onesignal.user.subscriptions.ISubscription -import com.onesignal.user.internal.subscriptions.SubscriptionList import com.onesignal.user.subscriptions.PushSubscriptionChangedState /** @@ -34,8 +34,7 @@ import com.onesignal.user.subscriptions.PushSubscriptionChangedState internal class SubscriptionManager( private val _subscriptionModelStore: SubscriptionModelStore, ) : ISubscriptionManager, IModelStoreChangeHandler { - - private val _events = EventProducer() + private val events = EventProducer() override var subscriptions: SubscriptionList = SubscriptionList(listOf(), UninitializedPushSubscription()) override val pushSubscriptionModel: SubscriptionModel get() = (subscriptions.push as PushSubscription).model @@ -56,7 +55,10 @@ internal class SubscriptionManager( addSubscriptionToModels(SubscriptionType.SMS, sms) } - override fun addOrUpdatePushSubscription(pushToken: String?, pushTokenStatus: SubscriptionStatus) { + override fun addOrUpdatePushSubscription( + pushToken: String?, + pushTokenStatus: SubscriptionStatus, + ) { val pushSub = subscriptions.push if (pushSub is UninitializedPushSubscription) { @@ -88,7 +90,11 @@ internal class SubscriptionManager( } } - private fun addSubscriptionToModels(type: SubscriptionType, address: String, status: SubscriptionStatus? = null) { + private fun addSubscriptionToModels( + type: SubscriptionType, + address: String, + status: SubscriptionStatus? = null, + ) { Logging.log(LogLevel.DEBUG, "SubscriptionManager.addSubscription(type: $type, address: $address)") val subscriptionModel = SubscriptionModel() @@ -107,16 +113,21 @@ internal class SubscriptionManager( _subscriptionModelStore.remove(subscription.id) } - override fun subscribe(handler: ISubscriptionChangedHandler) = _events.subscribe(handler) - override fun unsubscribe(handler: ISubscriptionChangedHandler) = _events.unsubscribe(handler) + override fun subscribe(handler: ISubscriptionChangedHandler) = events.subscribe(handler) + + override fun unsubscribe(handler: ISubscriptionChangedHandler) = events.unsubscribe(handler) + override val hasSubscribers: Boolean - get() = _events.hasSubscribers + get() = events.hasSubscribers /** * Called when the model store has added a new subscription. The subscription list must be updated * to reflect the added subscription. */ - override fun onModelAdded(model: SubscriptionModel, tag: String) { + override fun onModelAdded( + model: SubscriptionModel, + tag: String, + ) { createSubscriptionAndAddToSubscriptionList(model) } @@ -124,7 +135,10 @@ internal class SubscriptionManager( * Called when a subscription model has been updated. The subscription list must be updated * to reflect the update subscription. */ - override fun onModelUpdated(args: ModelChangedArgs, tag: String) { + override fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) { val subscription = subscriptions.collection.firstOrNull { it.id == args.model.id } if (subscription == null) { @@ -135,14 +149,15 @@ internal class SubscriptionManager( if (subscription is PushSubscription) { subscription.changeHandlersNotifier.fireOnMain { it.onPushSubscriptionChange( - PushSubscriptionChangedState( - subscription.savedState, - subscription.refreshState()) + PushSubscriptionChangedState( + subscription.savedState, + subscription.refreshState(), + ), ) } } // the model has already been updated, so fire the update event - _events.fire { it.onSubscriptionChanged(subscription, args) } + events.fire { it.onSubscriptionChanged(subscription, args) } } } @@ -150,7 +165,10 @@ internal class SubscriptionManager( * Called when a subscription model has been removed. The subscription list must be updated * to reflect the subscription removed. */ - override fun onModelRemoved(model: SubscriptionModel, tag: String) { + override fun onModelRemoved( + model: SubscriptionModel, + tag: String, + ) { val subscription = subscriptions.collection.firstOrNull { it.id == model.id } if (subscription != null) { @@ -173,7 +191,7 @@ internal class SubscriptionManager( subscriptions.add(subscription) this.subscriptions = SubscriptionList(subscriptions, UninitializedPushSubscription()) - _events.fire { it.onSubscriptionAdded(subscription) } + events.fire { it.onSubscriptionAdded(subscription) } } private fun removeSubscriptionFromSubscriptionList(subscription: ISubscription) { @@ -181,7 +199,7 @@ internal class SubscriptionManager( subscriptions.remove(subscription) this.subscriptions = SubscriptionList(subscriptions, UninitializedPushSubscription()) - _events.fire { it.onSubscriptionRemoved(subscription) } + events.fire { it.onSubscriptionRemoved(subscription) } } private fun createSubscriptionFromModel(subscriptionModel: SubscriptionModel): ISubscription { diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/IPushSubscriptionObserver.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/IPushSubscriptionObserver.kt index 8a53eb8017..8b17d8e226 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/IPushSubscriptionObserver.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/IPushSubscriptionObserver.kt @@ -5,7 +5,6 @@ package com.onesignal.user.subscriptions * to [ISubscription.addObserver] to be notified when the subscription has changed. */ interface IPushSubscriptionObserver { - /** * Called when the subscription this change handler was added to, has changed. A * subscription can change either because of a change driven by the application, or diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/ISmsSubscription.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/ISmsSubscription.kt index 47113c9e36..00ba8d86d3 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/ISmsSubscription.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/ISmsSubscription.kt @@ -5,7 +5,6 @@ package com.onesignal.user.subscriptions * channel. */ interface ISmsSubscription : ISubscription { - /** * The phone number notifications will be sent to for this subscription, in * [E.164](https://documentation.onesignal.com/docs/sms-faq#what-is-the-e164-format) format. diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/PushSubscriptionChangedState.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/PushSubscriptionChangedState.kt index 669090d77a..28dbd3dbc8 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/PushSubscriptionChangedState.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/PushSubscriptionChangedState.kt @@ -4,12 +4,11 @@ import org.json.JSONObject class PushSubscriptionChangedState( val previous: PushSubscriptionState, - val current: PushSubscriptionState + val current: PushSubscriptionState, ) { fun toJSONObject(): JSONObject { return JSONObject() - .put("previous", previous.toJSONObject()) - .put("current", current.toJSONObject()) + .put("previous", previous.toJSONObject()) + .put("current", current.toJSONObject()) } } - diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/PushSubscriptionState.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/PushSubscriptionState.kt index 5520b2432b..f43dbdb8b6 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/PushSubscriptionState.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/PushSubscriptionState.kt @@ -13,13 +13,11 @@ class PushSubscriptionState( * been successfully assigned. */ val id: String, - /** * The token which identifies the device/app that notifications are to be sent. May * be an empty string, indicating the push token has not yet been retrieved. */ val token: String, - /** * Whether the user of this subscription is opted-in to received notifications. When true, * the user is able to receive notifications through this subscription. Otherwise, the @@ -30,10 +28,8 @@ class PushSubscriptionState( ) { fun toJSONObject(): JSONObject { return JSONObject() - .put("id", id) - .put("token", token) - .put("optedIn", optedIn) + .put("id", id) + .put("token", token) + .put("optedIn", optedIn) } } - - diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt index 24b704051b..9a0586b47b 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt @@ -24,20 +24,20 @@ class ApplicationServiceTests : FunSpec({ } test("start application service with non-activity shows entry state as closed") { - /* Given */ + // Given val context = ApplicationProvider.getApplicationContext() val applicationService = ApplicationService() - /* When */ + // When applicationService.start(context) val entryState = applicationService.entryState - /* Then */ + // Then entryState shouldBe AppEntryAction.APP_CLOSE } test("start application service with activity shows entry state as closed") { - /* Given */ + // Given val activity: Activity Robolectric.buildActivity(Activity::class.java).use { controller -> @@ -46,16 +46,16 @@ class ApplicationServiceTests : FunSpec({ } val applicationService = ApplicationService() - /* When */ + // When applicationService.start(activity) val entryState = applicationService.entryState - /* Then */ + // Then entryState shouldBe AppEntryAction.APP_OPEN } test("current activity is established when activity is started") { - /* Given */ + // Given val activity1: Activity val activity2: Activity val context = ApplicationProvider.getApplicationContext() @@ -70,20 +70,20 @@ class ApplicationServiceTests : FunSpec({ val applicationService = ApplicationService() - /* When */ + // When applicationService.start(activity1) val initialActivity = applicationService.current pushActivity(applicationService, activity1, activity2) val currentActivity = applicationService.current - /* Then */ + // Then initialActivity shouldBe activity1 currentActivity shouldBe activity2 } test("current activity is established when activity is stopped") { - /* Given */ + // Given val activity1: Activity val activity2: Activity @@ -98,20 +98,20 @@ class ApplicationServiceTests : FunSpec({ val applicationService = ApplicationService() - /* When */ + // When applicationService.start(activity1) val initialActivity = applicationService.current pushActivity(applicationService, activity1, activity2) popActivity(applicationService, activity2, activity1) val currentActivity = applicationService.current - /* Then */ + // Then initialActivity shouldBe activity1 currentActivity shouldBe activity1 } test("unfocus will occur when when all activities are stopped") { - /* Given */ + // Given val activity1: Activity val activity2: Activity @@ -128,7 +128,7 @@ class ApplicationServiceTests : FunSpec({ val applicationService = ApplicationService() applicationService.addApplicationLifecycleHandler(mockApplicationLifecycleHandler) - /* When */ + // When applicationService.start(activity1) pushActivity(applicationService, activity1, activity2) @@ -137,13 +137,13 @@ class ApplicationServiceTests : FunSpec({ val currentActivity = applicationService.current - /* Then */ + // Then currentActivity shouldBe null verify(exactly = 1) { mockApplicationLifecycleHandler.onUnfocused() } } test("focus will occur when when the first activity is started") { - /* Given */ + // Given val activity1: Activity val activity2: Activity @@ -160,7 +160,7 @@ class ApplicationServiceTests : FunSpec({ val applicationService = ApplicationService() applicationService.addApplicationLifecycleHandler(mockApplicationLifecycleHandler) - /* When */ + // When applicationService.start(activity1) pushActivity(applicationService, activity1, activity2) @@ -172,25 +172,25 @@ class ApplicationServiceTests : FunSpec({ val currentActivity = applicationService.current - /* Then */ + // Then currentActivity shouldBe activity2 verify(exactly = 1) { mockApplicationLifecycleHandler.onUnfocused() } verify(exactly = 1) { mockApplicationLifecycleHandler.onFocus() } } test("wait until system condition returns false when there is no activity") { - /* Given */ + // Given val applicationService = ApplicationService() - /* When */ + // When val response = applicationService.waitUntilSystemConditionsAvailable() - /* Then */ + // Then response shouldBe false } test("wait until system condition returns true when there is no system condition") { - /* Given */ + // Given val activity: Activity Robolectric.buildActivity(Activity::class.java).use { controller -> @@ -199,16 +199,21 @@ class ApplicationServiceTests : FunSpec({ } val applicationService = ApplicationService() - /* When */ + // When applicationService.start(activity) val response = applicationService.waitUntilSystemConditionsAvailable() - /* Then */ + // Then response shouldBe true } }) { companion object { - fun pushActivity(applicationService: ApplicationService, currActivity: Activity, newActivity: Activity, destoryCurrent: Boolean = false) { + fun pushActivity( + applicationService: ApplicationService, + currActivity: Activity, + newActivity: Activity, + destoryCurrent: Boolean = false, + ) { applicationService.onActivityPaused(currActivity) applicationService.onActivityCreated(newActivity, null) applicationService.onActivityStarted(newActivity) @@ -220,7 +225,11 @@ class ApplicationServiceTests : FunSpec({ } } - fun popActivity(applicationService: ApplicationService, currActivity: Activity, oldActivity: Activity) { + fun popActivity( + applicationService: ApplicationService, + currActivity: Activity, + oldActivity: Activity, + ) { applicationService.onActivityPaused(currActivity) applicationService.onActivityStarted(oldActivity) applicationService.onActivityResumed(oldActivity) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/InitialOSDatabase.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/InitialOSDatabase.kt index a4af76365a..2c8cd8dea4 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/InitialOSDatabase.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/InitialOSDatabase.kt @@ -10,36 +10,40 @@ import com.onesignal.core.internal.database.impl.OneSignalDbContract * This class setups up the database in it's initial form to test database upgrade paths. */ internal class InitialOSDatabase(context: Context?) : SQLiteOpenHelper(context, "OneSignal.db", null, 1) { + private val textType = " TEXT" + private val intType = " INTEGER" + private val commaSep = "," - private val TEXT_TYPE = " TEXT" - private val INT_TYPE = " INTEGER" - private val COMMA_SEP = "," - - private val SQL_CREATE_ENTRIES = + private val sqlCreateEntries = "CREATE TABLE " + OneSignalDbContract.NotificationTable.TABLE_NAME.toString() + " (" + BaseColumns._ID.toString() + " INTEGER PRIMARY KEY," + - OneSignalDbContract.NotificationTable.COLUMN_NAME_NOTIFICATION_ID + TEXT_TYPE + COMMA_SEP + - OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID + INT_TYPE + COMMA_SEP + - OneSignalDbContract.NotificationTable.COLUMN_NAME_GROUP_ID + TEXT_TYPE + COMMA_SEP + - OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + INT_TYPE.toString() + " DEFAULT 0" + COMMA_SEP + - OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + INT_TYPE.toString() + " DEFAULT 0" + COMMA_SEP + - OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED + INT_TYPE.toString() + " DEFAULT 0" + COMMA_SEP + - OneSignalDbContract.NotificationTable.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP + - OneSignalDbContract.NotificationTable.COLUMN_NAME_MESSAGE + TEXT_TYPE + COMMA_SEP + - OneSignalDbContract.NotificationTable.COLUMN_NAME_FULL_DATA + TEXT_TYPE + COMMA_SEP + + OneSignalDbContract.NotificationTable.COLUMN_NAME_NOTIFICATION_ID + textType + commaSep + + OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID + intType + commaSep + + OneSignalDbContract.NotificationTable.COLUMN_NAME_GROUP_ID + textType + commaSep + + OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + intType.toString() + " DEFAULT 0" + commaSep + + OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + intType.toString() + " DEFAULT 0" + commaSep + + OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED + intType.toString() + " DEFAULT 0" + commaSep + + OneSignalDbContract.NotificationTable.COLUMN_NAME_TITLE + textType + commaSep + + OneSignalDbContract.NotificationTable.COLUMN_NAME_MESSAGE + textType + commaSep + + OneSignalDbContract.NotificationTable.COLUMN_NAME_FULL_DATA + textType + commaSep + OneSignalDbContract.NotificationTable.COLUMN_NAME_CREATED_TIME.toString() + " TIMESTAMP DEFAULT (strftime('%s', 'now'))" + ");" - private val SQL_INDEX_ENTRIES: String = OneSignalDbContract.NotificationTable.INDEX_CREATE_NOTIFICATION_ID + - OneSignalDbContract.NotificationTable.INDEX_CREATE_ANDROID_NOTIFICATION_ID + - OneSignalDbContract.NotificationTable.INDEX_CREATE_GROUP_ID + - OneSignalDbContract.NotificationTable.INDEX_CREATE_CREATED_TIME + private val sqlIndexEntries: String = + OneSignalDbContract.NotificationTable.INDEX_CREATE_NOTIFICATION_ID + + OneSignalDbContract.NotificationTable.INDEX_CREATE_ANDROID_NOTIFICATION_ID + + OneSignalDbContract.NotificationTable.INDEX_CREATE_GROUP_ID + + OneSignalDbContract.NotificationTable.INDEX_CREATE_CREATED_TIME override fun onCreate(db: SQLiteDatabase) { - db.execSQL(SQL_CREATE_ENTRIES) - db.execSQL(SQL_INDEX_ENTRIES) + db.execSQL(sqlCreateEntries) + db.execSQL(sqlIndexEntries) } - override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) { + override fun onUpgrade( + p0: SQLiteDatabase?, + p1: Int, + p2: Int, + ) { } } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/OSDatabaseTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/OSDatabaseTests.kt index 31688aee92..a32d20b438 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/OSDatabaseTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/database/OSDatabaseTests.kt @@ -44,11 +44,11 @@ class OSDatabaseTests : FunSpec({ } test("upgrade database from v1 To v3") { - /* Given */ + // Given val outcomeTableProvider = mockk() val db = OSDatabase(outcomeTableProvider, ApplicationProvider.getApplicationContext(), 3) - /* When */ + // When var createdTime: Long = 0 var expireTime: Long = 0 db.query(OneSignalDbContract.NotificationTable.TABLE_NAME) { @@ -57,7 +57,7 @@ class OSDatabaseTests : FunSpec({ expireTime = it.getLong(OneSignalDbContract.NotificationTable.COLUMN_NAME_EXPIRE_TIME) } - /* Then */ + // Then expireTime shouldBe createdTime + (72L * (60 * 60)) } }) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/http/HttpClientTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/http/HttpClientTests.kt index bf50004229..3b0a569e1f 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/http/HttpClientTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/http/HttpClientTests.kt @@ -24,48 +24,49 @@ class HttpClientTests : FunSpec({ } test("timeout request will give a bad response") { - /* Given */ + // Given val mockResponse = MockHttpConnectionFactory.MockResponse() mockResponse.mockRequestTime = 10000 // HttpClient will add 5 seconds to the httpTimeout to "give up" so we need to fail the request more than 5 seconds beyond our timeout. - val mockConfigModel = MockHelper.configModelStore { - it.httpTimeout = 200 - it.httpGetTimeout = 200 - } + val mockConfigModel = + MockHelper.configModelStore { + it.httpTimeout = 200 + it.httpGetTimeout = 200 + } val factory = MockHttpConnectionFactory(mockResponse) val httpClient = HttpClient(factory, MockPreferencesService(), mockConfigModel) - /* When */ + // When val response = httpClient.get("URL") - /* Then */ + // Then response.statusCode shouldBe 0 response.throwable shouldNotBe null response.throwable should beInstanceOf() } test("SDKHeader is included in all requests") { - /* Given */ + // Given val mockResponse = MockHttpConnectionFactory.MockResponse() val factory = MockHttpConnectionFactory(mockResponse) val httpClient = HttpClient(factory, MockPreferencesService(), MockHelper.configModelStore()) - /* When */ + // When httpClient.get("URL") httpClient.delete("URL") httpClient.patch("URL", JSONObject()) httpClient.post("URL", JSONObject()) httpClient.put("URL", JSONObject()) - /* Then */ + // Then for (connection in factory.connections) { - connection.getRequestProperty("SDK-Version") shouldBe "onesignal/android/${OneSignalUtils.sdkVersion}" + connection.getRequestProperty("SDK-Version") shouldBe "onesignal/android/${OneSignalUtils.SDK_VERSION}" } } test("GET with cache key uses cache when unchanged") { - /* Given */ + // Given val payload = "RESPONSE IS THIS" val mockResponse1 = MockHttpConnectionFactory.MockResponse() mockResponse1.status = 200 @@ -78,13 +79,13 @@ class HttpClientTests : FunSpec({ val factory = MockHttpConnectionFactory(mockResponse1) val httpClient = HttpClient(factory, MockPreferencesService(), MockHelper.configModelStore()) - /* When */ + // When var response1 = httpClient.get("URL", "CACHE_KEY") factory.mockResponse = mockResponse2 var response2 = httpClient.get("URL", "CACHE_KEY") - /* Then */ + // Then response1.statusCode shouldBe 200 response1.payload shouldBe payload response2.statusCode shouldBe 304 @@ -93,7 +94,7 @@ class HttpClientTests : FunSpec({ } test("GET with cache key replaces cache when changed") { - /* Given */ + // Given val payload1 = "RESPONSE IS THIS" val payload2 = "A DIFFERENT RESPONSE" val mockResponse1 = MockHttpConnectionFactory.MockResponse() @@ -112,7 +113,7 @@ class HttpClientTests : FunSpec({ val factory = MockHttpConnectionFactory(mockResponse1) val httpClient = HttpClient(factory, MockPreferencesService(), MockHelper.configModelStore()) - /* When */ + // When var response1 = httpClient.get("URL", "CACHE_KEY") factory.mockResponse = mockResponse2 @@ -121,7 +122,7 @@ class HttpClientTests : FunSpec({ factory.mockResponse = mockResponse3 var response3 = httpClient.get("URL", "CACHE_KEY") - /* Then */ + // Then response1.statusCode shouldBe 200 response1.payload shouldBe payload1 response2.statusCode shouldBe 200 @@ -133,7 +134,7 @@ class HttpClientTests : FunSpec({ } test("Error response") { - /* Given */ + // Given val payload = "ERROR RESPONSE" val mockResponse = MockHttpConnectionFactory.MockResponse() mockResponse.status = 400 @@ -142,10 +143,10 @@ class HttpClientTests : FunSpec({ val factory = MockHttpConnectionFactory(mockResponse) val httpClient = HttpClient(factory, MockPreferencesService(), MockHelper.configModelStore()) - /* When */ + // When var response = httpClient.post("URL", JSONObject()) - /* Then */ + // Then response.statusCode shouldBe 400 response.payload shouldBe payload } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/http/MockHttpConnectionFactory.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/http/MockHttpConnectionFactory.kt index 03e0aa748f..156b83fc56 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/http/MockHttpConnectionFactory.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/http/MockHttpConnectionFactory.kt @@ -11,7 +11,6 @@ import java.net.URL internal class MockHttpConnectionFactory( var mockResponse: MockResponse, ) : IHttpConnectionFactory { - val connections: MutableList = mutableListOf() var lastConnection: MockHttpURLConnection? = null @@ -34,6 +33,7 @@ internal class MockHttpConnectionFactory( private val mockResponse: MockResponse, ) : HttpURLConnection(url) { override fun disconnect() {} + override fun usingProxy(): Boolean { return false } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/operations/OperationRepoTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/operations/OperationRepoTests.kt index ecf182f0dc..c1d78dca1e 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/operations/OperationRepoTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/operations/OperationRepoTests.kt @@ -27,7 +27,7 @@ class OperationRepoTests : FunSpec({ } test("enqueue operation executes and is removed when executed") { - /* Given */ + // Given val mockExecutor = mockk() every { mockExecutor.operations } returns listOf("DUMMY_OPERATION") coEvery { mockExecutor.execute(any()) } returns ExecutionResponse(ExecutionResult.SUCCESS) @@ -37,16 +37,17 @@ class OperationRepoTests : FunSpec({ every { mockOperationModelStore.add(any()) } just runs every { mockOperationModelStore.remove(any()) } just runs - val operationRepo = OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) + val operationRepo = + OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) val operationIdSlot = slot() val operation = mockOperation(operationIdSlot = operationIdSlot) - /* When */ + // When operationRepo.start() val response = operationRepo.enqueueAndWait(operation) - /* Then */ + // Then response shouldBe true operationIdSlot.isCaptured shouldBe true coVerifyOrder { @@ -62,26 +63,29 @@ class OperationRepoTests : FunSpec({ } test("enqueue operation executes and is removed when executed after retry") { - /* Given */ + // Given val mockExecutor = mockk() every { mockExecutor.operations } returns listOf("DUMMY_OPERATION") - coEvery { mockExecutor.execute(any()) } returns ExecutionResponse(ExecutionResult.FAIL_RETRY) andThen ExecutionResponse(ExecutionResult.SUCCESS) + coEvery { + mockExecutor.execute(any()) + } returns ExecutionResponse(ExecutionResult.FAIL_RETRY) andThen ExecutionResponse(ExecutionResult.SUCCESS) val mockOperationModelStore = mockk() every { mockOperationModelStore.list() } returns listOf() every { mockOperationModelStore.add(any()) } just runs every { mockOperationModelStore.remove(any()) } just runs - val operationRepo = OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) + val operationRepo = + OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) val operationIdSlot = slot() val operation = mockOperation(operationIdSlot = operationIdSlot) - /* When */ + // When operationRepo.start() val response = operationRepo.enqueueAndWait(operation) - /* Then */ + // Then response shouldBe true operationIdSlot.isCaptured shouldBe true coVerifyOrder { @@ -103,7 +107,7 @@ class OperationRepoTests : FunSpec({ } test("enqueue operation executes and is removed when executed after fail") { - /* Given */ + // Given val mockExecutor = mockk() every { mockExecutor.operations } returns listOf("DUMMY_OPERATION") coEvery { mockExecutor.execute(any()) } returns ExecutionResponse(ExecutionResult.FAIL_NORETRY) @@ -113,16 +117,17 @@ class OperationRepoTests : FunSpec({ every { mockOperationModelStore.add(any()) } just runs every { mockOperationModelStore.remove(any()) } just runs - val operationRepo = OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) + val operationRepo = + OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) val operationIdSlot = slot() val operation = mockOperation(operationIdSlot = operationIdSlot) - /* When */ + // When operationRepo.start() val response = operationRepo.enqueueAndWait(operation) - /* Then */ + // Then response shouldBe false operationIdSlot.isCaptured shouldBe true coVerifyOrder { @@ -138,7 +143,7 @@ class OperationRepoTests : FunSpec({ } test("enqueue 2 operations that cannot be grouped will be executed separately from each other") { - /* Given */ + // Given val waiter = Waiter() val mockExecutor = mockk() every { mockExecutor.operations } returns listOf("DUMMY_OPERATION") @@ -149,19 +154,20 @@ class OperationRepoTests : FunSpec({ every { mockOperationModelStore.add(any()) } just runs every { mockOperationModelStore.remove(any()) } answers {} andThenAnswer { waiter.wake() } - val operationRepo = OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) + val operationRepo = + OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) val operation1 = mockOperation("operationId1", groupComparisonType = GroupComparisonType.CREATE) val operation2 = mockOperation("operationId2", createComparisonKey = "create-key2") - /* When */ + // When operationRepo.enqueue(operation1) operationRepo.enqueue(operation2) operationRepo.start() waiter.waitForWake() - /* Then */ + // Then coVerifyOrder { mockOperationModelStore.add(operation1) mockOperationModelStore.add(operation2) @@ -183,7 +189,7 @@ class OperationRepoTests : FunSpec({ } test("enqueue 2 operations that can be grouped via create will be executed as a group") { - /* Given */ + // Given val waiter = Waiter() val mockExecutor = mockk() every { mockExecutor.operations } returns listOf("DUMMY_OPERATION") @@ -194,19 +200,20 @@ class OperationRepoTests : FunSpec({ every { mockOperationModelStore.add(any()) } just runs every { mockOperationModelStore.remove(any()) } answers {} andThenAnswer { waiter.wake() } - val operationRepo = OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) + val operationRepo = + OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) val operation1 = mockOperation("operationId1", groupComparisonType = GroupComparisonType.CREATE) val operation2 = mockOperation("operationId2") - /* When */ + // When operationRepo.enqueue(operation1) operationRepo.enqueue(operation2) operationRepo.start() waiter.waitForWake() - /* Then */ + // Then coVerifyOrder { mockOperationModelStore.add(operation1) mockOperationModelStore.add(operation2) @@ -223,7 +230,7 @@ class OperationRepoTests : FunSpec({ } test("enqueue 2 operations where the first cannot be executed but can be grouped via create will be executed as a group") { - /* Given */ + // Given val waiter = Waiter() val mockExecutor = mockk() every { mockExecutor.operations } returns listOf("DUMMY_OPERATION") @@ -234,19 +241,20 @@ class OperationRepoTests : FunSpec({ every { mockOperationModelStore.add(any()) } just runs every { mockOperationModelStore.remove(any()) } answers {} andThenAnswer { waiter.wake() } - val operationRepo = OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) + val operationRepo = + OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) val operation1 = mockOperation("operationId1", canStartExecute = false, groupComparisonType = GroupComparisonType.ALTER) val operation2 = mockOperation("operationId2", groupComparisonType = GroupComparisonType.CREATE) - /* When */ + // When operationRepo.enqueue(operation1) operationRepo.enqueue(operation2) operationRepo.start() waiter.waitForWake() - /* Then */ + // Then coVerifyOrder { mockOperationModelStore.add(operation1) mockOperationModelStore.add(operation2) @@ -263,30 +271,33 @@ class OperationRepoTests : FunSpec({ } test("execution of 1 operation with translation IDs will drive translateId of subsequence operations") { - /* Given */ + // Given val waiter = Waiter() val mockExecutor = mockk() every { mockExecutor.operations } returns listOf("DUMMY_OPERATION") - coEvery { mockExecutor.execute(any()) } returns ExecutionResponse(ExecutionResult.SUCCESS, mapOf("id1" to "id2")) andThen ExecutionResponse(ExecutionResult.SUCCESS) + coEvery { + mockExecutor.execute(any()) + } returns ExecutionResponse(ExecutionResult.SUCCESS, mapOf("id1" to "id2")) andThen ExecutionResponse(ExecutionResult.SUCCESS) val mockOperationModelStore = mockk() every { mockOperationModelStore.list() } returns listOf() every { mockOperationModelStore.add(any()) } just runs every { mockOperationModelStore.remove(any()) } answers {} andThenAnswer { waiter.wake() } - val operationRepo = OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) + val operationRepo = + OperationRepo(listOf(mockExecutor), mockOperationModelStore, MockHelper.configModelStore(), MockHelper.time(1000)) val operation1 = mockOperation("operationId1") val operation2 = mockOperation("operationId2") - /* When */ + // When operationRepo.enqueue(operation1) operationRepo.enqueue(operation2) operationRepo.start() waiter.waitForWake() - /* Then */ + // Then coVerifyOrder { mockOperationModelStore.add(operation1) mockOperationModelStore.add(operation2) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/preferences/PreferencesServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/preferences/PreferencesServiceTests.kt index 216eedaa5e..1a9065b6da 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/preferences/PreferencesServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/preferences/PreferencesServiceTests.kt @@ -30,10 +30,10 @@ class PreferencesServiceTests : FunSpec({ } test("throws exception when store is not known") { - /* Given */ + // Given val preferencesService = PreferencesService(AndroidMockHelper.applicationService(), MockHelper.time(1000)) - /* When */ + // When shouldThrowUnit { preferencesService.getBool("not-known-store", mockBoolPrefStoreKey) } @@ -42,21 +42,21 @@ class PreferencesServiceTests : FunSpec({ preferencesService.saveBool("not-known-store", mockBoolPrefStoreKey, false) } - /* Then */ + // Then } test("retrieve preference with no default returns internal default when not in android shared preferences") { - /* Given */ + // Given val preferencesService = PreferencesService(AndroidMockHelper.applicationService(), MockHelper.time(1000)) - /* When */ + // When val boolValue = preferencesService.getBool(mockPrefStoreName, mockBoolPrefStoreKey) val intValue = preferencesService.getInt(mockPrefStoreName, mockIntPrefStoreKey) val longValue = preferencesService.getLong(mockPrefStoreName, mockLongPrefStoreKey) val stringValue = preferencesService.getString(mockPrefStoreName, mockStringPrefStoreKey) val stringSetValue = preferencesService.getStringSet(mockPrefStoreName, mockStringSetPrefStoreKey) - /* Then */ + // Then boolValue shouldBe false intValue shouldBe 0 longValue shouldBe 0 @@ -65,17 +65,17 @@ class PreferencesServiceTests : FunSpec({ } test("retrieve preference with default returns specified default when not in android shared preferences") { - /* Given */ + // Given val preferencesService = PreferencesService(AndroidMockHelper.applicationService(), MockHelper.time(1000)) - /* When */ + // When val boolValue = preferencesService.getBool(mockPrefStoreName, mockBoolPrefStoreKey, true) val intValue = preferencesService.getInt(mockPrefStoreName, mockIntPrefStoreKey, 10) val longValue = preferencesService.getLong(mockPrefStoreName, mockLongPrefStoreKey, 20) val stringValue = preferencesService.getString(mockPrefStoreName, mockStringPrefStoreKey, "default") val stringSetValue = preferencesService.getStringSet(mockPrefStoreName, mockStringSetPrefStoreKey, setOf("default1", "default2")) - /* Then */ + // Then boolValue shouldBe true intValue shouldBe 10 longValue shouldBe 20 @@ -84,7 +84,7 @@ class PreferencesServiceTests : FunSpec({ } test("retrieve preference returns what's in android shared preferences") { - /* Given */ + // Given val store = ApplicationProvider.getApplicationContext().getSharedPreferences(mockPrefStoreName, Context.MODE_PRIVATE) val editor = store.edit() editor.putBoolean(mockBoolPrefStoreKey, true) @@ -96,14 +96,14 @@ class PreferencesServiceTests : FunSpec({ val preferencesService = PreferencesService(AndroidMockHelper.applicationService(), MockHelper.time(1000)) - /* When */ + // When val boolValue = preferencesService.getBool(mockPrefStoreName, mockBoolPrefStoreKey) val intValue = preferencesService.getInt(mockPrefStoreName, mockIntPrefStoreKey) val longValue = preferencesService.getLong(mockPrefStoreName, mockLongPrefStoreKey) val stringValue = preferencesService.getString(mockPrefStoreName, mockStringPrefStoreKey) val stringSetValue = preferencesService.getStringSet(mockPrefStoreName, mockStringSetPrefStoreKey) - /* Then */ + // Then boolValue shouldBe true intValue shouldBe 10 longValue shouldBe 20 @@ -112,7 +112,7 @@ class PreferencesServiceTests : FunSpec({ } test("retrieve preference returns default value when in android shared preferences but is different type") { - /* Given */ + // Given val store = ApplicationProvider.getApplicationContext().getSharedPreferences(mockPrefStoreName, Context.MODE_PRIVATE) val editor = store.edit() editor.putInt(mockBoolPrefStoreKey, 0) @@ -124,14 +124,14 @@ class PreferencesServiceTests : FunSpec({ val preferencesService = PreferencesService(AndroidMockHelper.applicationService(), MockHelper.time(1000)) - /* When */ + // When val boolValue = preferencesService.getBool(mockPrefStoreName, mockBoolPrefStoreKey) val intValue = preferencesService.getInt(mockPrefStoreName, mockIntPrefStoreKey) val longValue = preferencesService.getLong(mockPrefStoreName, mockLongPrefStoreKey) val stringValue = preferencesService.getString(mockPrefStoreName, mockStringPrefStoreKey) val stringSetValue = preferencesService.getStringSet(mockPrefStoreName, mockStringSetPrefStoreKey) - /* Then */ + // Then boolValue shouldBe false intValue shouldBe 0 longValue shouldBe 0 @@ -140,7 +140,7 @@ class PreferencesServiceTests : FunSpec({ } test("retrieve preference returns what's in cache rather than android shared preferences") { - /* Given */ + // Given val store = ApplicationProvider.getApplicationContext().getSharedPreferences(mockPrefStoreName, Context.MODE_PRIVATE) val editor = store.edit() editor.putBoolean(mockBoolPrefStoreKey, false) @@ -152,7 +152,7 @@ class PreferencesServiceTests : FunSpec({ val preferencesService = PreferencesService(AndroidMockHelper.applicationService(), MockHelper.time(1000)) - /* When */ + // When preferencesService.saveBool(mockPrefStoreName, mockBoolPrefStoreKey, true) preferencesService.saveInt(mockPrefStoreName, mockIntPrefStoreKey, 10) preferencesService.saveLong(mockPrefStoreName, mockLongPrefStoreKey, 20) @@ -165,7 +165,7 @@ class PreferencesServiceTests : FunSpec({ val stringValue = preferencesService.getString(mockPrefStoreName, mockStringPrefStoreKey) val stringSetValue = preferencesService.getStringSet(mockPrefStoreName, mockStringSetPrefStoreKey) - /* Then */ + // Then boolValue shouldBe true intValue shouldBe 10 longValue shouldBe 20 @@ -174,10 +174,10 @@ class PreferencesServiceTests : FunSpec({ } test("save preference are stored in android shared preferences") { - /* Given */ + // Given val preferencesService = PreferencesService(AndroidMockHelper.applicationService(), MockHelper.time(1000)) - /* When */ + // When preferencesService.saveBool(mockPrefStoreName, mockBoolPrefStoreKey, true) preferencesService.saveInt(mockPrefStoreName, mockIntPrefStoreKey, 10) preferencesService.saveLong(mockPrefStoreName, mockLongPrefStoreKey, 20) @@ -187,9 +187,13 @@ class PreferencesServiceTests : FunSpec({ delay(1000) - val store = ApplicationProvider.getApplicationContext().getSharedPreferences(PreferenceStores.ONESIGNAL, Context.MODE_PRIVATE) + val store = + ApplicationProvider.getApplicationContext().getSharedPreferences( + PreferenceStores.ONESIGNAL, + Context.MODE_PRIVATE, + ) - /* Then */ + // Then store.getBoolean(mockBoolPrefStoreKey, false) shouldBe true store.getInt(mockIntPrefStoreKey, 0) shouldBe 10 store.getLong(mockLongPrefStoreKey, 0) shouldBe 20 @@ -198,7 +202,7 @@ class PreferencesServiceTests : FunSpec({ } test("save preference as null will remove from android shared preferences store") { - /* Given */ + // Given val store = ApplicationProvider.getApplicationContext().getSharedPreferences(mockPrefStoreName, Context.MODE_PRIVATE) val editor = store.edit() editor.putBoolean(mockBoolPrefStoreKey, false) @@ -210,7 +214,7 @@ class PreferencesServiceTests : FunSpec({ val preferencesService = PreferencesService(AndroidMockHelper.applicationService(), MockHelper.time(1000)) - /* When */ + // When preferencesService.saveBool(mockPrefStoreName, mockBoolPrefStoreKey, null) preferencesService.saveInt(mockPrefStoreName, mockIntPrefStoreKey, null) preferencesService.saveLong(mockPrefStoreName, mockLongPrefStoreKey, null) @@ -220,7 +224,7 @@ class PreferencesServiceTests : FunSpec({ delay(1000) - /* Then */ + // Then store.contains(mockBoolPrefStoreKey) shouldBe false store.contains(mockIntPrefStoreKey) shouldBe false store.contains(mockLongPrefStoreKey) shouldBe false diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/startup/StartupServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/startup/StartupServiceTests.kt index d9693a3746..0fd44cf2bb 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/startup/StartupServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/startup/StartupServiceTests.kt @@ -20,32 +20,32 @@ class StartupServiceTests : FunSpec({ } test("bootstrap with no IBootstrapService dependencies is a no-op") { - /* Given */ + // Given val startupService = StartupService(listOf(), listOf()) - /* When */ + // When startupService.bootstrap() - /* Then */ + // Then } test("bootstrap will call all IBootstrapService dependencies successfully") { - /* Given */ + // Given val mockBootstrapService1 = spyk() val mockBootstrapService2 = spyk() val startupService = StartupService(listOf(mockBootstrapService1, mockBootstrapService2), listOf()) - /* When */ + // When startupService.bootstrap() - /* Then */ + // Then verify(exactly = 1) { mockBootstrapService1.bootstrap() } verify(exactly = 1) { mockBootstrapService2.bootstrap() } } test("bootstrap will propagate exception when an IBootstrapService throws an exception") { - /* Given */ + // Given val exception = Exception("SOMETHING BAD") val mockBootstrapService1 = mockk() @@ -54,34 +54,35 @@ class StartupServiceTests : FunSpec({ val startupService = StartupService(listOf(mockBootstrapService1, mockBootstrapService2), listOf()) - /* When */ - val actualException = shouldThrowUnit { - startupService.bootstrap() - } + // When + val actualException = + shouldThrowUnit { + startupService.bootstrap() + } - /* Then */ + // Then actualException shouldBe exception verify(exactly = 1) { mockBootstrapService1.bootstrap() } verify(exactly = 0) { mockBootstrapService2.bootstrap() } } test("startup will call all IStartableService dependencies successfully") { - /* Given */ + // Given val mockStartupService1 = spyk() val mockStartupService2 = spyk() val startupService = StartupService(listOf(), listOf(mockStartupService1, mockStartupService2)) - /* When */ + // When startupService.start() - /* Then */ + // Then verify(exactly = 1) { mockStartupService1.start() } verify(exactly = 1) { mockStartupService2.start() } } test("startup will propagate exception when an IStartableService throws an exception") { - /* Given */ + // Given val exception = Exception("SOMETHING BAD") val mockStartableService1 = mockk() @@ -90,12 +91,13 @@ class StartupServiceTests : FunSpec({ val startupService = StartupService(listOf(), listOf(mockStartableService1, mockStartableService2)) - /* When */ - val actualException = shouldThrowUnit { - startupService.start() - } + // When + val actualException = + shouldThrowUnit { + startupService.start() + } - /* Then */ + // Then actualException shouldBe exception verify(exactly = 1) { mockStartableService1.start() } verify(exactly = 0) { mockStartableService2.start() } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/ContainedRobolectricRunner.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/ContainedRobolectricRunner.kt index 2308e9c994..3f6529695a 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/ContainedRobolectricRunner.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/ContainedRobolectricRunner.kt @@ -17,11 +17,13 @@ internal class ContainedRobolectricRunner( private val config: Config?, ) : RobolectricTestRunner(PlaceholderTest::class.java, injector) { private val placeHolderMethod: FrameworkMethod = children[0] - val sdkEnvironment = getSandbox(placeHolderMethod).also { - configureSandbox(it, placeHolderMethod) - } - private val bootStrapMethod = sdkEnvironment.bootstrappedClass(testClass.javaClass) - .getMethod(PlaceholderTest::bootStrapMethod.name) + val sdkEnvironment = + getSandbox(placeHolderMethod).also { + configureSandbox(it, placeHolderMethod) + } + private val bootStrapMethod = + sdkEnvironment.bootstrappedClass(testClass.javaClass) + .getMethod(PlaceholderTest::bootStrapMethod.name) fun containedBefore() { Thread.currentThread().contextClassLoader = sdkEnvironment.robolectricClassLoader @@ -41,8 +43,9 @@ internal class ContainedRobolectricRunner( } override fun getConfig(method: Method?): Config { - val defaultConfiguration = injector.getInstance(ConfigurationStrategy::class.java) - .getConfig(testClass.javaClass, method) + val defaultConfiguration = + injector.getInstance(ConfigurationStrategy::class.java) + .getConfig(testClass.javaClass, method) if (config != null) { val configConfigurer = injector.getInstance(ConfigConfigurer::class.java) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt index d554cdf8e2..f5353ceab5 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/extensions/RobolectricExtension.kt @@ -30,12 +30,14 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { } private fun KClass<*>.getConfig(): Config { - val annotations = listOf(this.java).plus(this.java.getParentClass()) - .mapNotNull { it.kotlin.findAnnotation() } - .asSequence() + val annotations = + listOf(this.java).plus(this.java.getParentClass()) + .mapNotNull { it.kotlin.findAnnotation() } + .asSequence() - val application: KClass? = annotations - .firstOrNull { it.application != KotestDefaultApplication::class }?.application + val application: KClass? = + annotations + .firstOrNull { it.application != KotestDefaultApplication::class }?.application val sdk: Int? = annotations.firstOrNull { it.sdk != -1 }?.takeUnless { it.sdk == -1 }?.sdk return Config.Builder() @@ -62,9 +64,10 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { execute: suspend (TestCase) -> TestResult, ): TestResult { // FIXED: Updated code based on https://github.com/kotest/kotest/issues/2717 - val hasRobolectricAnnotation = testCase.spec::class.annotations.any { annotation -> - annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName - } + val hasRobolectricAnnotation = + testCase.spec::class.annotations.any { annotation -> + annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName + } if (!hasRobolectricAnnotation) { return execute(testCase) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/AndroidMockHelper.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/AndroidMockHelper.kt index eff5fcc5b9..b2db452b6c 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/AndroidMockHelper.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/AndroidMockHelper.kt @@ -8,7 +8,6 @@ import io.mockk.every * Singleton which provides common mock services when running in an Android environment. */ internal object AndroidMockHelper { - fun applicationService(): IApplicationService { val mockAppService = MockHelper.applicationService() diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/DatabaseMockHelper.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/DatabaseMockHelper.kt index 90fcf42ae7..4a71a6474b 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/DatabaseMockHelper.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/DatabaseMockHelper.kt @@ -11,7 +11,10 @@ import io.mockk.spyk * Singleton which provides common mock services. */ internal object DatabaseMockHelper { - fun databaseProvider(tableName: String, records: List>? = null): Pair { + fun databaseProvider( + tableName: String, + records: List>? = null, + ): Pair { val mockOneSignalDatabase = spyk() if (records != null) { @@ -33,8 +36,14 @@ internal object DatabaseMockHelper { val mockCursor = mockk() var index = 0 every { mockCursor.count } returns records.count() - every { mockCursor.moveToFirst() } answers { index = 0; true } - every { mockCursor.moveToNext() } answers { index++; index < records.count() } + every { mockCursor.moveToFirst() } answers { + index = 0 + true + } + every { mockCursor.moveToNext() } answers { + index++ + index < records.count() + } every { mockCursor.getString(any()) } answers { records[index][firstArg()] as String } every { mockCursor.getFloat(any()) } answers { records[index][firstArg()] as Float } every { mockCursor.getLong(any()) } answers { records[index][firstArg()] as Long } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/MockHelper.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/MockHelper.kt index bc4b32f861..1974ff9a3c 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/MockHelper.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/MockHelper.kt @@ -38,6 +38,7 @@ object MockHelper { } const val DEFAULT_APP_ID = "appId" + fun configModelStore(action: ((ConfigModel) -> Unit)? = null): ConfigModelStore { val configModel = ConfigModel() diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/MockPreferencesService.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/MockPreferencesService.kt index ccf0a13b5c..a5bf374599 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/MockPreferencesService.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/mocks/MockPreferencesService.kt @@ -7,17 +7,75 @@ import com.onesignal.core.internal.preferences.IPreferencesService * and will return any saved value in memory. */ internal class MockPreferencesService(map: Map? = null) : IPreferencesService { - private val _map: MutableMap = map?.toMutableMap() ?: mutableMapOf() - - override fun getString(store: String, key: String, defValue: String?): String? = (_map[key] as String?) ?: defValue - override fun getBool(store: String, key: String, defValue: Boolean?): Boolean? = (_map[key] as Boolean?) ?: defValue - override fun getInt(store: String, key: String, defValue: Int?): Int? = (_map[key] as Int?) ?: defValue - override fun getLong(store: String, key: String, defValue: Long?): Long? = (_map[key] as Long?) ?: defValue - override fun getStringSet(store: String, key: String, defValue: Set?): Set? = (_map[key] as Set?) ?: defValue - - override fun saveString(store: String, key: String, value: String?) { _map[key] = value } - override fun saveBool(store: String, key: String, value: Boolean?) { _map[key] = value } - override fun saveInt(store: String, key: String, value: Int?) { _map[key] = value } - override fun saveLong(store: String, key: String, value: Long?) { _map[key] = value } - override fun saveStringSet(store: String, key: String, value: Set?) { _map[key] = value } + private val map: MutableMap = map?.toMutableMap() ?: mutableMapOf() + + override fun getString( + store: String, + key: String, + defValue: String?, + ): String? = (map[key] as String?) ?: defValue + + override fun getBool( + store: String, + key: String, + defValue: Boolean?, + ): Boolean? = (map[key] as Boolean?) ?: defValue + + override fun getInt( + store: String, + key: String, + defValue: Int?, + ): Int? = (map[key] as Int?) ?: defValue + + override fun getLong( + store: String, + key: String, + defValue: Long?, + ): Long? = (map[key] as Long?) ?: defValue + + override fun getStringSet( + store: String, + key: String, + defValue: Set?, + ): Set? = (map[key] as Set?) ?: defValue + + override fun saveString( + store: String, + key: String, + value: String?, + ) { + map[key] = value + } + + override fun saveBool( + store: String, + key: String, + value: Boolean?, + ) { + map[key] = value + } + + override fun saveInt( + store: String, + key: String, + value: Int?, + ) { + map[key] = value + } + + override fun saveLong( + store: String, + key: String, + value: Long?, + ) { + map[key] = value + } + + override fun saveStringSet( + store: String, + key: String, + value: Set?, + ) { + map[key] = value + } } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/influence/InfluenceManagerTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/influence/InfluenceManagerTests.kt index 3cd3ce5b54..c315b562e1 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/influence/InfluenceManagerTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/influence/InfluenceManagerTests.kt @@ -20,23 +20,25 @@ import org.junit.runner.RunWith class InfluenceManagerTests : FunSpec({ test("default are disabled influences") { - /* Given */ + // Given val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs val mockApplicationService = mockk() - val mockConfigModelStore = MockHelper.configModelStore { - it.influenceParams.isDirectEnabled = false - it.influenceParams.isIndirectEnabled = false - it.influenceParams.isUnattributedEnabled = false - } + val mockConfigModelStore = + MockHelper.configModelStore { + it.influenceParams.isDirectEnabled = false + it.influenceParams.isIndirectEnabled = false + it.influenceParams.isUnattributedEnabled = false + } val mockPreferences = MockPreferencesService() - val influenceManager = InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) + val influenceManager = + InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) - /* When */ + // When val influences = influenceManager.influences - /* Then */ + // Then influences.count() shouldBe 2 val notificationInfluence = influences.first { it.influenceChannel == InfluenceChannel.NOTIFICATION } notificationInfluence.influenceType.isDisabled() shouldBe true @@ -50,26 +52,28 @@ class InfluenceManagerTests : FunSpec({ } test("session begin are unattributed influences") { - /* Given */ + // Given val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs val mockApplicationService = mockk() every { mockApplicationService.entryState } returns AppEntryAction.APP_OPEN - val mockConfigModelStore = MockHelper.configModelStore { - it.influenceParams.isDirectEnabled = true - it.influenceParams.isIndirectEnabled = true - it.influenceParams.isUnattributedEnabled = true - } + val mockConfigModelStore = + MockHelper.configModelStore { + it.influenceParams.isDirectEnabled = true + it.influenceParams.isIndirectEnabled = true + it.influenceParams.isUnattributedEnabled = true + } val mockPreferences = MockPreferencesService() - val influenceManager = InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) + val influenceManager = + InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) - /* When */ + // When influenceManager.onSessionStarted() val influences = influenceManager.influences - /* Then */ + // Then influences.count() shouldBe 2 val notificationInfluence = influences.first { it.influenceChannel == InfluenceChannel.NOTIFICATION } notificationInfluence.influenceType.isUnattributed() shouldBe true @@ -83,27 +87,29 @@ class InfluenceManagerTests : FunSpec({ } test("notification received creates notification indirect influence") { - /* Given */ + // Given val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs val mockApplicationService = mockk() every { mockApplicationService.entryState } returns AppEntryAction.APP_OPEN - val mockConfigModelStore = MockHelper.configModelStore { - it.influenceParams.isDirectEnabled = true - it.influenceParams.isIndirectEnabled = true - it.influenceParams.isUnattributedEnabled = true - } + val mockConfigModelStore = + MockHelper.configModelStore { + it.influenceParams.isDirectEnabled = true + it.influenceParams.isIndirectEnabled = true + it.influenceParams.isUnattributedEnabled = true + } val mockPreferences = MockPreferencesService() - val influenceManager = InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) + val influenceManager = + InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) - /* When */ + // When influenceManager.onNotificationReceived("notificationId") influenceManager.onSessionActive() val influences = influenceManager.influences - /* Then */ + // Then influences.count() shouldBe 2 val notificationInfluence = influences.first { it.influenceChannel == InfluenceChannel.NOTIFICATION } notificationInfluence.influenceType.isIndirect() shouldBe true @@ -117,25 +123,27 @@ class InfluenceManagerTests : FunSpec({ } test("IAM received creates IAM indirect influence") { - /* Given */ + // Given val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs val mockApplicationService = mockk() - val mockConfigModelStore = MockHelper.configModelStore { - it.influenceParams.isDirectEnabled = true - it.influenceParams.isIndirectEnabled = true - it.influenceParams.isUnattributedEnabled = true - } + val mockConfigModelStore = + MockHelper.configModelStore { + it.influenceParams.isDirectEnabled = true + it.influenceParams.isIndirectEnabled = true + it.influenceParams.isUnattributedEnabled = true + } val mockPreferences = MockPreferencesService() - val influenceManager = InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) + val influenceManager = + InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) - /* When */ + // When influenceManager.onInAppMessageDisplayed("inAppMessageId") influenceManager.onInAppMessageDismissed() val influences = influenceManager.influences - /* Then */ + // Then influences.count() shouldBe 2 val notificationInfluence = influences.first { it.influenceChannel == InfluenceChannel.NOTIFICATION } notificationInfluence.influenceType.isUnattributed() shouldBe true @@ -151,25 +159,27 @@ class InfluenceManagerTests : FunSpec({ } test("notification opened creates notification direct influence") { - /* Given */ + // Given val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs val mockApplicationService = mockk() - val mockConfigModelStore = MockHelper.configModelStore { - it.influenceParams.isDirectEnabled = true - it.influenceParams.isIndirectEnabled = true - it.influenceParams.isUnattributedEnabled = true - } + val mockConfigModelStore = + MockHelper.configModelStore { + it.influenceParams.isDirectEnabled = true + it.influenceParams.isIndirectEnabled = true + it.influenceParams.isUnattributedEnabled = true + } val mockPreferences = MockPreferencesService() - val influenceManager = InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) + val influenceManager = + InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) - /* When */ + // When influenceManager.onNotificationReceived("notificationId") influenceManager.onDirectInfluenceFromNotification("notificationId") val influences = influenceManager.influences - /* Then */ + // Then influences.count() shouldBe 2 val notificationInfluence = influences.first { it.influenceChannel == InfluenceChannel.NOTIFICATION } notificationInfluence.influenceType.isDirect() shouldBe true @@ -183,25 +193,27 @@ class InfluenceManagerTests : FunSpec({ } test("IAM clicked while open creates IAM direct influence") { - /* Given */ + // Given val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs val mockApplicationService = mockk() - val mockConfigModelStore = MockHelper.configModelStore { - it.influenceParams.isDirectEnabled = true - it.influenceParams.isIndirectEnabled = true - it.influenceParams.isUnattributedEnabled = true - } + val mockConfigModelStore = + MockHelper.configModelStore { + it.influenceParams.isDirectEnabled = true + it.influenceParams.isIndirectEnabled = true + it.influenceParams.isUnattributedEnabled = true + } val mockPreferences = MockPreferencesService() - val influenceManager = InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) + val influenceManager = + InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) - /* When */ + // When influenceManager.onInAppMessageDisplayed("inAppMessageId") influenceManager.onDirectInfluenceFromIAM("inAppMessageId") val influences = influenceManager.influences - /* Then */ + // Then influences.count() shouldBe 2 val notificationInfluence = influences.first { it.influenceChannel == InfluenceChannel.NOTIFICATION } notificationInfluence.influenceType.isUnattributed() shouldBe true @@ -215,26 +227,28 @@ class InfluenceManagerTests : FunSpec({ } test("IAM clicked then dismissed creates IAM indirect influence") { - /* Given */ + // Given val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs val mockApplicationService = mockk() - val mockConfigModelStore = MockHelper.configModelStore { - it.influenceParams.isDirectEnabled = true - it.influenceParams.isIndirectEnabled = true - it.influenceParams.isUnattributedEnabled = true - } + val mockConfigModelStore = + MockHelper.configModelStore { + it.influenceParams.isDirectEnabled = true + it.influenceParams.isIndirectEnabled = true + it.influenceParams.isUnattributedEnabled = true + } val mockPreferences = MockPreferencesService() - val influenceManager = InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) + val influenceManager = + InfluenceManager(mockSessionService, mockApplicationService, mockConfigModelStore, mockPreferences, MockHelper.time(1111)) - /* When */ + // When influenceManager.onInAppMessageDisplayed("inAppMessageId") influenceManager.onDirectInfluenceFromIAM("inAppMessageId") influenceManager.onInAppMessageDismissed() val influences = influenceManager.influences - /* Then */ + // Then influences.count() shouldBe 2 val notificationInfluence = influences.first { it.influenceChannel == InfluenceChannel.NOTIFICATION } notificationInfluence.influenceType.isUnattributed() shouldBe true diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsBackendServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsBackendServiceTests.kt index 9b67c4592e..baf3cea4b6 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsBackendServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsBackendServiceTests.kt @@ -24,16 +24,16 @@ class OutcomeEventsBackendServiceTests : FunSpec({ } test("send outcome event") { - /* Given */ + // Given val evnt = OutcomeEvent(InfluenceType.DIRECT, null, "EVENT_NAME", 0, 0, 0F) val spyHttpClient = mockk() coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(200, null) val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) - /* When */ + // When outcomeEventsController.sendOutcomeEvent("appId", "onesignalId", "subscriptionId", "AndroidPush", null, evnt) - /* Then */ + // Then coVerify { spyHttpClient.post( "outcomes/measure", @@ -52,16 +52,16 @@ class OutcomeEventsBackendServiceTests : FunSpec({ } test("send outcome event with weight") { - /* Given */ + // Given val evnt = OutcomeEvent(InfluenceType.DIRECT, null, "EVENT_NAME", 0, 0, 1F) val spyHttpClient = mockk() coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(200, null) val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) - /* When */ + // When outcomeEventsController.sendOutcomeEvent("appId", "onesignalId", "subscriptionId", "AndroidPush", null, evnt) - /* Then */ + // Then coVerify { spyHttpClient.post( "outcomes/measure", @@ -80,16 +80,16 @@ class OutcomeEventsBackendServiceTests : FunSpec({ } test("send outcome event with indirect") { - /* Given */ + // Given val evnt = OutcomeEvent(InfluenceType.DIRECT, null, "EVENT_NAME", 0, 0, 0F) val spyHttpClient = mockk() coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(200, null) val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) - /* When */ + // When outcomeEventsController.sendOutcomeEvent("appId", "onesignalId", "subscriptionId", "AndroidPush", false, evnt) - /* Then */ + // Then coVerify { spyHttpClient.post( "outcomes/measure", @@ -108,16 +108,16 @@ class OutcomeEventsBackendServiceTests : FunSpec({ } test("send outcome event with direct") { - /* Given */ + // Given val evnt = OutcomeEvent(InfluenceType.DIRECT, null, "EVENT_NAME", 0, 0, 0F) val spyHttpClient = mockk() coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(200, null) val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) - /* When */ + // When outcomeEventsController.sendOutcomeEvent("appId", "onesignalId", "subscriptionId", "AndroidPush", true, evnt) - /* Then */ + // Then coVerify { spyHttpClient.post( "outcomes/measure", @@ -136,16 +136,16 @@ class OutcomeEventsBackendServiceTests : FunSpec({ } test("send outcome event with timestamp") { - /* Given */ + // Given val evnt = OutcomeEvent(InfluenceType.DIRECT, null, "EVENT_NAME", 1111L, 0, 0F) val spyHttpClient = mockk() coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(200, null) val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) - /* When */ + // When outcomeEventsController.sendOutcomeEvent("appId", "onesignalId", "subscriptionId", "AndroidPush", null, evnt) - /* Then */ + // Then coVerify { spyHttpClient.post( "outcomes/measure", @@ -164,18 +164,19 @@ class OutcomeEventsBackendServiceTests : FunSpec({ } test("send outcome event with unsuccessful response") { - /* Given */ + // Given val evnt = OutcomeEvent(InfluenceType.DIRECT, null, "EVENT_NAME", 1111L, 0, 0F) val spyHttpClient = mockk() coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(503, "SERVICE UNAVAILABLE") val outcomeEventsController = OutcomeEventsBackendService(spyHttpClient) - /* When */ - val exception = shouldThrowUnit { - outcomeEventsController.sendOutcomeEvent("appId", "onesignalId", "subscriptionId", "AndroidPush", null, evnt) - } + // When + val exception = + shouldThrowUnit { + outcomeEventsController.sendOutcomeEvent("appId", "onesignalId", "subscriptionId", "AndroidPush", null, evnt) + } - /* Then */ + // Then exception.statusCode shouldBe 503 exception.response shouldBe "SERVICE UNAVAILABLE" } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt index 3c4b5318c2..0242cfa3f5 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt @@ -52,7 +52,7 @@ class OutcomeEventsControllerTests : FunSpec({ } test("send outcome with disabled influences") { - /* Given */ + // Given val now = 111L val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs @@ -65,29 +65,30 @@ class OutcomeEventsControllerTests : FunSpec({ val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = spyk() - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore(), - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore(), + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When val evnt = outcomeEventsController.sendOutcomeEvent("OUTCOME_1") - /* Then */ + // Then evnt shouldBe null coVerify(exactly = 0) { mockOutcomeEventsBackend.sendOutcomeEvent(any(), any(), any(), any(), any(), any()) } } test("send outcome with unattributed influences") { - /* Given */ + // Given val now = 111L val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs @@ -104,23 +105,24 @@ class OutcomeEventsControllerTests : FunSpec({ val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = spyk() - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When val evnt = outcomeEventsController.sendOutcomeEvent("OUTCOME_1") - /* Then */ + // Then evnt shouldNotBe null evnt!!.name shouldBe "OUTCOME_1" evnt.notificationIds shouldBe null @@ -128,18 +130,22 @@ class OutcomeEventsControllerTests : FunSpec({ evnt.session shouldBe InfluenceType.UNATTRIBUTED evnt.timestamp shouldBe 0 // timestamp only set when it had to be saved. - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", null, evnt) } + coVerify(exactly = 1) { + mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", null, evnt) + } } test("send outcome with indirect influences") { - /* Given */ + // Given val now = 111L val notificationIds = "[\"id1\",\"id2\"]" val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs val mockInfluenceManager = mockk() - every { mockInfluenceManager.influences } returns listOf(Influence(InfluenceChannel.NOTIFICATION, InfluenceType.INDIRECT, JSONArray(notificationIds))) + every { + mockInfluenceManager.influences + } returns listOf(Influence(InfluenceChannel.NOTIFICATION, InfluenceType.INDIRECT, JSONArray(notificationIds))) val subscriptionModel = createTestSubscriptionModel() @@ -150,23 +156,24 @@ class OutcomeEventsControllerTests : FunSpec({ val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = spyk() - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When val evnt = outcomeEventsController.sendOutcomeEvent("OUTCOME_1") - /* Then */ + // Then evnt shouldNotBe null evnt!!.name shouldBe "OUTCOME_1" evnt.notificationIds shouldNotBe null @@ -175,18 +182,29 @@ class OutcomeEventsControllerTests : FunSpec({ evnt.session shouldBe InfluenceType.INDIRECT evnt.timestamp shouldBe 0 // timestamp only set when it had to be saved. - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", false, evnt) } + coVerify(exactly = 1) { + mockOutcomeEventsBackend.sendOutcomeEvent( + MockHelper.DEFAULT_APP_ID, + "onesignalId", + "subscriptionId", + "AndroidPush", + false, + evnt, + ) + } } test("send outcome with direct influence") { - /* Given */ + // Given val now = 111L val notificationIds = "[\"id1\",\"id2\"]" val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs val mockInfluenceManager = mockk() - every { mockInfluenceManager.influences } returns listOf(Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray(notificationIds))) + every { + mockInfluenceManager.influences + } returns listOf(Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray(notificationIds))) val subscriptionModel = createTestSubscriptionModel() @@ -197,23 +215,24 @@ class OutcomeEventsControllerTests : FunSpec({ val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = spyk() - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When val evnt = outcomeEventsController.sendOutcomeEvent("OUTCOME_1") - /* Then */ + // Then evnt shouldNotBe null evnt!!.name shouldBe "OUTCOME_1" evnt.notificationIds shouldNotBe null @@ -222,11 +241,13 @@ class OutcomeEventsControllerTests : FunSpec({ evnt.session shouldBe InfluenceType.DIRECT evnt.timestamp shouldBe 0 // timestamp only set when it had to be saved. - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", true, evnt) } + coVerify(exactly = 1) { + mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", true, evnt) + } } test("send outcome with weight") { - /* Given */ + // Given val now = 111L val weight = 999F val mockSessionService = mockk() @@ -244,23 +265,24 @@ class OutcomeEventsControllerTests : FunSpec({ val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = spyk() - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When val evnt = outcomeEventsController.sendOutcomeEventWithValue("OUTCOME_1", weight) - /* Then */ + // Then evnt shouldNotBe null evnt!!.name shouldBe "OUTCOME_1" evnt.notificationIds shouldBe null @@ -268,11 +290,13 @@ class OutcomeEventsControllerTests : FunSpec({ evnt.session shouldBe InfluenceType.UNATTRIBUTED evnt.timestamp shouldBe 0 // timestamp only set when it had to be saved. - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", null, evnt) } + coVerify(exactly = 1) { + mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", null, evnt) + } } test("send unique outcome with unattributed influences") { - /* Given */ + // Given val now = 111L val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs @@ -289,24 +313,25 @@ class OutcomeEventsControllerTests : FunSpec({ val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = spyk() - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When val evnt1 = outcomeEventsController.sendUniqueOutcomeEvent("OUTCOME_1") val evnt2 = outcomeEventsController.sendUniqueOutcomeEvent("OUTCOME_1") - /* Then */ + // Then evnt1 shouldNotBe null evnt1!!.name shouldBe "OUTCOME_1" evnt1.notificationIds shouldBe null @@ -316,11 +341,20 @@ class OutcomeEventsControllerTests : FunSpec({ evnt2 shouldBe null - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", any(), any()) } + coVerify(exactly = 1) { + mockOutcomeEventsBackend.sendOutcomeEvent( + MockHelper.DEFAULT_APP_ID, + "onesignalId", + "subscriptionId", + "AndroidPush", + any(), + any(), + ) + } } test("send unique outcome with same indirect influences") { - /* Given */ + // Given val waiter = Waiter() val now = 111L val notificationIds = "[\"id1\",\"id2\"]" @@ -332,7 +366,9 @@ class OutcomeEventsControllerTests : FunSpec({ every { mockInfluenceManager.influences } returns listOf(notificationInfluence) val mockOutcomeEventsRepository = mockk() - coEvery { mockOutcomeEventsRepository.getNotCachedUniqueInfluencesForOutcome("OUTCOME_1", any()) } returns listOf(notificationInfluence) andThen listOf() + coEvery { + mockOutcomeEventsRepository.getNotCachedUniqueInfluencesForOutcome("OUTCOME_1", any()) + } returns listOf(notificationInfluence) andThen listOf() coEvery { mockOutcomeEventsRepository.saveUniqueOutcomeEventParams(any()) } answers { waiter.wake() } val subscriptionModel = createTestSubscriptionModel() @@ -343,26 +379,27 @@ class OutcomeEventsControllerTests : FunSpec({ val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = spyk() - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When val evnt1 = outcomeEventsController.sendUniqueOutcomeEvent("OUTCOME_1") val evnt2 = outcomeEventsController.sendUniqueOutcomeEvent("OUTCOME_1") waiter.waitForWake() - /* Then */ + // Then evnt1 shouldNotBe null evnt1!!.name shouldBe "OUTCOME_1" evnt1.notificationIds shouldNotBe null @@ -373,11 +410,20 @@ class OutcomeEventsControllerTests : FunSpec({ evnt2 shouldBe null - coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", any(), any()) } + coVerify(exactly = 1) { + mockOutcomeEventsBackend.sendOutcomeEvent( + MockHelper.DEFAULT_APP_ID, + "onesignalId", + "subscriptionId", + "AndroidPush", + any(), + any(), + ) + } } test("send unique outcome with different indirect influences") { - /* Given */ + // Given val waiter = Waiter() val now = 111L val notificationIds1 = "[\"id1\",\"id2\"]" @@ -396,32 +442,35 @@ class OutcomeEventsControllerTests : FunSpec({ every { mockSubscriptionManager.subscriptions.push } returns PushSubscription(subscriptionModel) val mockOutcomeEventsRepository = mockk() - coEvery { mockOutcomeEventsRepository.getNotCachedUniqueInfluencesForOutcome("OUTCOME_1", any()) } returns listOf(notificationInfluence1) andThen listOf(notificationInfluence2) + coEvery { + mockOutcomeEventsRepository.getNotCachedUniqueInfluencesForOutcome("OUTCOME_1", any()) + } returns listOf(notificationInfluence1) andThen listOf(notificationInfluence2) coEvery { mockOutcomeEventsRepository.saveUniqueOutcomeEventParams(any()) } answers { waiter.wake() } val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = spyk() - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When val evnt1 = outcomeEventsController.sendUniqueOutcomeEvent("OUTCOME_1") val evnt2 = outcomeEventsController.sendUniqueOutcomeEvent("OUTCOME_1") waiter.waitForWake() - /* Then */ + // Then evnt1 shouldNotBe null evnt1!!.name shouldBe "OUTCOME_1" evnt1.notificationIds shouldNotBe null @@ -439,13 +488,27 @@ class OutcomeEventsControllerTests : FunSpec({ evnt2.timestamp shouldBe 0 // timestamp only set when it had to be saved. coVerifySequence { - mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", false, evnt1) - mockOutcomeEventsBackend.sendOutcomeEvent(MockHelper.DEFAULT_APP_ID, "onesignalId", "subscriptionId", "AndroidPush", true, evnt2) + mockOutcomeEventsBackend.sendOutcomeEvent( + MockHelper.DEFAULT_APP_ID, + "onesignalId", + "subscriptionId", + "AndroidPush", + false, + evnt1, + ) + mockOutcomeEventsBackend.sendOutcomeEvent( + MockHelper.DEFAULT_APP_ID, + "onesignalId", + "subscriptionId", + "AndroidPush", + true, + evnt2, + ) } } test("send outcome in offline mode") { - /* Given */ + // Given val now = 111111L val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs @@ -463,23 +526,24 @@ class OutcomeEventsControllerTests : FunSpec({ val mockOutcomeEventsBackend = mockk() coEvery { mockOutcomeEventsBackend.sendOutcomeEvent(any(), any(), any(), any(), any(), any()) } throws BackendException(408, null) - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore(), - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore(), + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When val evnt = outcomeEventsController.sendOutcomeEvent("OUTCOME_1") - /* Then */ + // Then evnt shouldBe null coVerify(exactly = 1) { @@ -494,7 +558,7 @@ class OutcomeEventsControllerTests : FunSpec({ } test("send unsent outcomes on startup") { - /* Given */ + // Given val now = 111111L val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs @@ -508,33 +572,35 @@ class OutcomeEventsControllerTests : FunSpec({ val mockOutcomeEventsRepository = mockk() coEvery { mockOutcomeEventsRepository.cleanCachedUniqueOutcomeEventNotifications() } just runs coEvery { mockOutcomeEventsRepository.deleteOldOutcomeEvent(any()) } just runs - coEvery { mockOutcomeEventsRepository.getAllEventsToSend() } returns listOf( - OutcomeEventParams("outcomeId1", OutcomeSource(OutcomeSourceBody(JSONArray().put("notificationId1")), null), .4f, 0, 1111), - OutcomeEventParams("outcomeId2", OutcomeSource(null, OutcomeSourceBody(JSONArray().put("notificationId2").put("notificationId3"))), .2f, 0, 2222), - ) + coEvery { mockOutcomeEventsRepository.getAllEventsToSend() } returns + listOf( + OutcomeEventParams("outcomeId1", OutcomeSource(OutcomeSourceBody(JSONArray().put("notificationId1")), null), .4f, 0, 1111), + OutcomeEventParams("outcomeId2", OutcomeSource(null, OutcomeSourceBody(JSONArray().put("notificationId2").put("notificationId3"))), .2f, 0, 2222), + ) val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = mockk() coEvery { mockOutcomeEventsBackend.sendOutcomeEvent(any(), any(), any(), any(), any(), any()) } just runs - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When outcomeEventsController.start() delay(1000) - /* Then */ + // Then coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent( "appId", @@ -585,7 +651,7 @@ class OutcomeEventsControllerTests : FunSpec({ } test("send unsent outcomes on startup fails gracefully") { - /* Given */ + // Given val now = 111111L val mockSessionService = mockk() every { mockSessionService.subscribe(any()) } just Runs @@ -598,33 +664,35 @@ class OutcomeEventsControllerTests : FunSpec({ val mockInfluenceManager = mockk() val mockOutcomeEventsRepository = mockk() coEvery { mockOutcomeEventsRepository.cleanCachedUniqueOutcomeEventNotifications() } just runs - coEvery { mockOutcomeEventsRepository.getAllEventsToSend() } returns listOf( - OutcomeEventParams("outcomeId1", OutcomeSource(OutcomeSourceBody(JSONArray().put("notificationId1")), null), .4f, 0, 1111), - OutcomeEventParams("outcomeId2", OutcomeSource(null, OutcomeSourceBody(JSONArray().put("notificationId2").put("notificationId3"))), .2f, 0, 2222), - ) + coEvery { mockOutcomeEventsRepository.getAllEventsToSend() } returns + listOf( + OutcomeEventParams("outcomeId1", OutcomeSource(OutcomeSourceBody(JSONArray().put("notificationId1")), null), .4f, 0, 1111), + OutcomeEventParams("outcomeId2", OutcomeSource(null, OutcomeSourceBody(JSONArray().put("notificationId2").put("notificationId3"))), .2f, 0, 2222), + ) val mockOutcomeEventsPreferences = spyk() val mockOutcomeEventsBackend = mockk() coEvery { mockOutcomeEventsBackend.sendOutcomeEvent(any(), any(), any(), any(), any(), any()) } throws BackendException(408, null) - val outcomeEventsController = OutcomeEventsController( - mockSessionService, - mockInfluenceManager, - mockOutcomeEventsRepository, - mockOutcomeEventsPreferences, - mockOutcomeEventsBackend, - MockHelper.configModelStore(), - MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, - mockSubscriptionManager, - MockHelper.deviceService(), - MockHelper.time(now), - ) - - /* When */ + val outcomeEventsController = + OutcomeEventsController( + mockSessionService, + mockInfluenceManager, + mockOutcomeEventsRepository, + mockOutcomeEventsPreferences, + mockOutcomeEventsBackend, + MockHelper.configModelStore(), + MockHelper.identityModelStore { it.onesignalId = "onesignalId" }, + mockSubscriptionManager, + MockHelper.deviceService(), + MockHelper.time(now), + ) + + // When outcomeEventsController.start() delay(1000) - /* Then */ + // Then coVerify(exactly = 1) { mockOutcomeEventsBackend.sendOutcomeEvent( "appId", diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt index 3c378ce649..05a05f14fe 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsRepositoryTests.kt @@ -31,23 +31,31 @@ class OutcomeEventsRepositoryTests : FunSpec({ } test("delete outcome event should use the timestamp to delete row from database") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(OutcomeEventsTable.TABLE_NAME) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When outcomeEventsRepository.deleteOldOutcomeEvent(OutcomeEventParams("outcomeId", null, 0f, 0, 1111)) - /* Then */ - verify(exactly = 1) { mockDatabasePair.second.delete(OutcomeEventsTable.TABLE_NAME, withArg { it.contains(OutcomeEventsTable.COLUMN_NAME_TIMESTAMP) }, withArg { it.contains("1111") }) } + // Then + verify(exactly = 1) { + mockDatabasePair.second.delete( + OutcomeEventsTable.TABLE_NAME, + withArg { + it.contains(OutcomeEventsTable.COLUMN_NAME_TIMESTAMP) + }, + withArg { it.contains("1111") }, + ) + } } test("save outcome event should insert row into database") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(OutcomeEventsTable.TABLE_NAME) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When outcomeEventsRepository.saveOutcomeEvent(OutcomeEventParams("outcomeId1", null, 0f, 0, 1111)) outcomeEventsRepository.saveOutcomeEvent( OutcomeEventParams( @@ -86,7 +94,7 @@ class OutcomeEventsRepositoryTests : FunSpec({ ), ) - /* Then */ + // Then verifySequence { mockDatabasePair.second.insert( OutcomeEventsTable.TABLE_NAME, @@ -144,54 +152,55 @@ class OutcomeEventsRepositoryTests : FunSpec({ } test("get events should retrieve return empty list when database is empty") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(OutcomeEventsTable.TABLE_NAME) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When val events = outcomeEventsRepository.getAllEventsToSend() - /* Then */ + // Then events.count() shouldBe 0 } test("get events should retrieve return an item per row in database") { - /* Given */ - val records = listOf( - mapOf( - OutcomeEventsTable.COLUMN_NAME_NAME to "outcomeId1", - OutcomeEventsTable.COLUMN_NAME_WEIGHT to 0.2f, - OutcomeEventsTable.COLUMN_NAME_TIMESTAMP to 1111L, - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE to "unattributed", - OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE to "unattributed", - ), - mapOf( - OutcomeEventsTable.COLUMN_NAME_NAME to "outcomeId2", - OutcomeEventsTable.COLUMN_NAME_WEIGHT to 0.4f, - OutcomeEventsTable.COLUMN_NAME_TIMESTAMP to 2222L, - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE to "indirect", - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS to "[\"notificationId1\",\"notificationId2\"]", - OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE to "indirect", - OutcomeEventsTable.COLUMN_NAME_IAM_IDS to "[\"iamId1\",\"iamId2\"]", - ), - mapOf( - OutcomeEventsTable.COLUMN_NAME_NAME to "outcomeId3", - OutcomeEventsTable.COLUMN_NAME_WEIGHT to 0.6f, - OutcomeEventsTable.COLUMN_NAME_TIMESTAMP to 3333L, - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE to "direct", - OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS to "[\"notificationId3\"]", - OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE to "direct", - OutcomeEventsTable.COLUMN_NAME_IAM_IDS to "[\"iamId3\"]", - ), - ) + // Given + val records = + listOf( + mapOf( + OutcomeEventsTable.COLUMN_NAME_NAME to "outcomeId1", + OutcomeEventsTable.COLUMN_NAME_WEIGHT to 0.2f, + OutcomeEventsTable.COLUMN_NAME_TIMESTAMP to 1111L, + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE to "unattributed", + OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE to "unattributed", + ), + mapOf( + OutcomeEventsTable.COLUMN_NAME_NAME to "outcomeId2", + OutcomeEventsTable.COLUMN_NAME_WEIGHT to 0.4f, + OutcomeEventsTable.COLUMN_NAME_TIMESTAMP to 2222L, + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE to "indirect", + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS to "[\"notificationId1\",\"notificationId2\"]", + OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE to "indirect", + OutcomeEventsTable.COLUMN_NAME_IAM_IDS to "[\"iamId1\",\"iamId2\"]", + ), + mapOf( + OutcomeEventsTable.COLUMN_NAME_NAME to "outcomeId3", + OutcomeEventsTable.COLUMN_NAME_WEIGHT to 0.6f, + OutcomeEventsTable.COLUMN_NAME_TIMESTAMP to 3333L, + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_INFLUENCE_TYPE to "direct", + OutcomeEventsTable.COLUMN_NAME_NOTIFICATION_IDS to "[\"notificationId3\"]", + OutcomeEventsTable.COLUMN_NAME_IAM_INFLUENCE_TYPE to "direct", + OutcomeEventsTable.COLUMN_NAME_IAM_IDS to "[\"iamId3\"]", + ), + ) val mockDatabasePair = DatabaseMockHelper.databaseProvider(OutcomeEventsTable.TABLE_NAME, records) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When val events = outcomeEventsRepository.getAllEventsToSend() - /* Then */ + // Then events.count() shouldBe 3 events[0].outcomeId shouldBe "outcomeId1" events[0].weight shouldBe 0.2f @@ -224,23 +233,23 @@ class OutcomeEventsRepositoryTests : FunSpec({ } test("save unique outcome should insert no rows when no influences") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(CachedUniqueOutcomeTable.COLUMN_NAME_NAME) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When outcomeEventsRepository.saveUniqueOutcomeEventParams(OutcomeEventParams("outcomeId1", null, 0f, 0, 1111)) - /* Then */ + // Then verify(exactly = 0) { mockDatabasePair.second.insert(CachedUniqueOutcomeTable.COLUMN_NAME_NAME, null, any()) } } test("save unique outcome should insert 1 row for each unique influence when direct notification and indiract iam") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(CachedUniqueOutcomeTable.TABLE_NAME) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When outcomeEventsRepository.saveUniqueOutcomeEventParams( OutcomeEventParams( "outcomeId1", @@ -254,7 +263,7 @@ class OutcomeEventsRepositoryTests : FunSpec({ ), ) - /* Then */ + // Then verifyAll { mockDatabasePair.second.insert( CachedUniqueOutcomeTable.TABLE_NAME, @@ -287,11 +296,11 @@ class OutcomeEventsRepositoryTests : FunSpec({ } test("save unique outcome should insert 1 row for each unique influence when direct iam and indiract notifications") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(CachedUniqueOutcomeTable.TABLE_NAME) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When outcomeEventsRepository.saveUniqueOutcomeEventParams( OutcomeEventParams( "outcomeId1", @@ -305,7 +314,7 @@ class OutcomeEventsRepositoryTests : FunSpec({ ), ) - /* Then */ + // Then verifyAll { mockDatabasePair.second.insert( CachedUniqueOutcomeTable.TABLE_NAME, @@ -338,11 +347,11 @@ class OutcomeEventsRepositoryTests : FunSpec({ } test("save unique outcome should insert 1 row for each unique influence when direct notification and iam") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(CachedUniqueOutcomeTable.TABLE_NAME) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When outcomeEventsRepository.saveUniqueOutcomeEventParams( OutcomeEventParams( "outcomeId1", @@ -356,7 +365,7 @@ class OutcomeEventsRepositoryTests : FunSpec({ ), ) - /* Then */ + // Then verifyAll { mockDatabasePair.second.insert( CachedUniqueOutcomeTable.TABLE_NAME, @@ -380,11 +389,11 @@ class OutcomeEventsRepositoryTests : FunSpec({ } test("save unique outcome should insert 1 row for each unique influence when indirect notification and iam") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(CachedUniqueOutcomeTable.TABLE_NAME) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When outcomeEventsRepository.saveUniqueOutcomeEventParams( OutcomeEventParams( "outcomeId1", @@ -398,7 +407,7 @@ class OutcomeEventsRepositoryTests : FunSpec({ ), ) - /* Then */ + // Then verifyAll { mockDatabasePair.second.insert( CachedUniqueOutcomeTable.TABLE_NAME, @@ -440,52 +449,54 @@ class OutcomeEventsRepositoryTests : FunSpec({ } test("retrieve non-cached influence should return full list when there are no cached unique influences") { - /* Given */ + // Given val records = listOf>() val mockDatabasePair = DatabaseMockHelper.databaseProvider(CachedUniqueOutcomeTable.TABLE_NAME, records) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ - val influences = outcomeEventsRepository.getNotCachedUniqueInfluencesForOutcome( - "outcomeId1", - listOf( - Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray().put("notificationId1")), - Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray().put("notificationId2")), - ), - ) + // When + val influences = + outcomeEventsRepository.getNotCachedUniqueInfluencesForOutcome( + "outcomeId1", + listOf( + Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray().put("notificationId1")), + Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray().put("notificationId2")), + ), + ) - /* Then */ + // Then influences.count() shouldBe 2 } test("retrieve non-cached influence should filter out an influence when there are is a matching influence") { - /* Given */ + // Given val records = listOf(mapOf(CachedUniqueOutcomeTable.COLUMN_NAME_NAME to "outcomeId1")) val mockDatabasePair = DatabaseMockHelper.databaseProvider(CachedUniqueOutcomeTable.TABLE_NAME, records) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ - val influences = outcomeEventsRepository.getNotCachedUniqueInfluencesForOutcome( - "outcomeId1", - listOf( - Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray().put("notificationId1")), - Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray().put("notificationId2")), - ), - ) + // When + val influences = + outcomeEventsRepository.getNotCachedUniqueInfluencesForOutcome( + "outcomeId1", + listOf( + Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray().put("notificationId1")), + Influence(InfluenceChannel.NOTIFICATION, InfluenceType.DIRECT, JSONArray().put("notificationId2")), + ), + ) - /* Then */ + // Then influences.count() shouldBe 0 } test("clear unique influence should delete out an influence when there are is a matching influence") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(CachedUniqueOutcomeTable.TABLE_NAME) val outcomeEventsRepository = OutcomeEventsRepository(mockDatabasePair.first) - /* When */ + // When outcomeEventsRepository.cleanCachedUniqueOutcomeEventNotifications() - /* Then */ + // Then verifyAll { mockDatabasePair.second.delete(CachedUniqueOutcomeTable.TABLE_NAME, any(), any()) } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/session/SessionServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/session/SessionServiceTests.kt index af6a6fe295..1bf1479d23 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/session/SessionServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/session/SessionServiceTests.kt @@ -13,23 +13,25 @@ import org.junit.runner.RunWith class SessionServiceTests : FunSpec({ test("session created on focus when current session invalid") { - /* Given */ + // Given val currentTime = 1111L val configModelStoreMock = MockHelper.configModelStore() - val sessionModelStoreMock = MockHelper.sessionModelStore { - it.isValid = false - } + val sessionModelStoreMock = + MockHelper.sessionModelStore { + it.isValid = false + } val spyCallback = spyk() - val sessionService = SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) + val sessionService = + SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) sessionService.start() sessionService.subscribe(spyCallback) - /* When */ + // When sessionService.onFocus() - /* Then */ + // Then sessionModelStoreMock.model.isValid shouldBe true sessionModelStoreMock.model.startTime shouldBe currentTime sessionModelStoreMock.model.focusTime shouldBe currentTime @@ -37,25 +39,27 @@ class SessionServiceTests : FunSpec({ } test("session focus time updated when current session valid") { - /* Given */ + // Given val currentTime = 1111L val startTime = 555L val configModelStoreMock = MockHelper.configModelStore() - val sessionModelStoreMock = MockHelper.sessionModelStore { - it.isValid = true - it.startTime = startTime - } + val sessionModelStoreMock = + MockHelper.sessionModelStore { + it.isValid = true + it.startTime = startTime + } val spyCallback = spyk() - val sessionService = SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) + val sessionService = + SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) sessionService.start() sessionService.subscribe(spyCallback) - /* When */ + // When sessionService.onFocus() - /* Then */ + // Then sessionModelStoreMock.model.isValid shouldBe true sessionModelStoreMock.model.startTime shouldBe startTime sessionModelStoreMock.model.focusTime shouldBe currentTime @@ -63,52 +67,56 @@ class SessionServiceTests : FunSpec({ } test("session active duration updated when unfocused") { - /* Given */ + // Given val startTime = 555L val focusTime = 666L val startingDuration = 1000L val currentTime = 1111L val configModelStoreMock = MockHelper.configModelStore() - val sessionModelStoreMock = MockHelper.sessionModelStore { - it.isValid = true - it.startTime = startTime - it.focusTime = focusTime - it.activeDuration = startingDuration - } - - val sessionService = SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) + val sessionModelStoreMock = + MockHelper.sessionModelStore { + it.isValid = true + it.startTime = startTime + it.focusTime = focusTime + it.activeDuration = startingDuration + } + + val sessionService = + SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) sessionService.start() - /* When */ + // When sessionService.onUnfocused() - /* Then */ + // Then sessionModelStoreMock.model.isValid shouldBe true sessionModelStoreMock.model.startTime shouldBe startTime sessionModelStoreMock.model.activeDuration shouldBe startingDuration + (currentTime - focusTime) } test("session ended when background run") { - /* Given */ + // Given val activeDuration = 555L val currentTime = 1111L val configModelStoreMock = MockHelper.configModelStore() - val sessionModelStoreMock = MockHelper.sessionModelStore { - it.isValid = true - it.activeDuration = activeDuration - } + val sessionModelStoreMock = + MockHelper.sessionModelStore { + it.isValid = true + it.activeDuration = activeDuration + } val spyCallback = spyk() - val sessionService = SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) + val sessionService = + SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) sessionService.start() sessionService.subscribe(spyCallback) - /* When */ + // When sessionService.backgroundRun() - /* Then */ + // Then sessionModelStoreMock.model.isValid shouldBe false verify(exactly = 1) { spyCallback.onSessionEnded(activeDuration) } } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/UserManagerTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/UserManagerTests.kt index b4c71bb962..b0e0953805 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/UserManagerTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/UserManagerTests.kt @@ -19,7 +19,7 @@ import org.junit.runner.RunWith class UserManagerTests : FunSpec({ test("language is backed by the language context") { - /* Given */ + // Given val mockSubscriptionManager = mockk() val languageContext = mockk() @@ -27,42 +27,47 @@ class UserManagerTests : FunSpec({ every { languageContext.language } returns "custom-language" every { languageContext.language = capture(languageSlot) } answers { } - val userManager = UserManager(mockSubscriptionManager, MockHelper.identityModelStore(), MockHelper.propertiesModelStore(), languageContext) + val userManager = + UserManager(mockSubscriptionManager, MockHelper.identityModelStore(), MockHelper.propertiesModelStore(), languageContext) - /* When */ + // When userManager.setLanguage("new-language") - /* Then */ + // Then languageSlot.captured shouldBe "new-language" } test("externalId is backed by the identity model") { - /* Given */ + // Given val mockSubscriptionManager = mockk() - val identityModelStore = MockHelper.identityModelStore { - it.externalId = "my-external-id" - } + val identityModelStore = + MockHelper.identityModelStore { + it.externalId = "my-external-id" + } - val userManager = UserManager(mockSubscriptionManager, identityModelStore, MockHelper.propertiesModelStore(), MockHelper.languageContext()) + val userManager = + UserManager(mockSubscriptionManager, identityModelStore, MockHelper.propertiesModelStore(), MockHelper.languageContext()) - /* When */ + // When val externalId = userManager.externalId - /* Then */ + // Then externalId shouldBe "my-external-id" } test("aliases are backed by the identity model") { - /* Given */ + // Given val mockSubscriptionManager = mockk() - val identityModelStore = MockHelper.identityModelStore { - it["my-alias-key1"] = "my-alias-value1" - it["my-alias-key2"] = "my-alias-value2" - } + val identityModelStore = + MockHelper.identityModelStore { + it["my-alias-key1"] = "my-alias-value1" + it["my-alias-key2"] = "my-alias-value2" + } - val userManager = UserManager(mockSubscriptionManager, identityModelStore, MockHelper.propertiesModelStore(), MockHelper.languageContext()) + val userManager = + UserManager(mockSubscriptionManager, identityModelStore, MockHelper.propertiesModelStore(), MockHelper.languageContext()) - /* When */ + // When val alias1 = userManager.aliases["my-alias-key1"] val alias2 = userManager.aliases["my-alias-key2"] @@ -77,7 +82,7 @@ class UserManagerTests : FunSpec({ // remove userManager.removeAlias("my-alias-key1") - /* Then */ + // Then alias1 shouldBe "my-alias-value1" alias2 shouldBe "my-alias-value2" identityModelStore.model["my-alias-key3"] shouldBe "my-alias-value3" @@ -88,18 +93,20 @@ class UserManagerTests : FunSpec({ } test("tags are backed by the properties model") { - /* Given */ + // Given val mockSubscriptionManager = mockk() - val propertiesModelStore = MockHelper.propertiesModelStore() { - it.tags["my-tag-key1"] = "my-tag-value1" - it.tags["my-tag-key2"] = "my-tag-value2" - it.tags["my-tag-key3"] = "my-tag-value3" - it.tags["my-tag-key4"] = "my-tag-value4" - } - - val userManager = UserManager(mockSubscriptionManager, MockHelper.identityModelStore(), propertiesModelStore, MockHelper.languageContext()) - - /* When */ + val propertiesModelStore = + MockHelper.propertiesModelStore { + it.tags["my-tag-key1"] = "my-tag-value1" + it.tags["my-tag-key2"] = "my-tag-value2" + it.tags["my-tag-key3"] = "my-tag-value3" + it.tags["my-tag-key4"] = "my-tag-value4" + } + + val userManager = + UserManager(mockSubscriptionManager, MockHelper.identityModelStore(), propertiesModelStore, MockHelper.languageContext()) + + // When val tag1 = userManager.tags["my-tag-key1"] val tag2 = userManager.tags["my-tag-key2"] @@ -115,7 +122,7 @@ class UserManagerTests : FunSpec({ userManager.removeTag("my-tag-key1") userManager.removeTags(listOf("my-tag-key2", "my-tag-key3")) - /* Then */ + // Then tag1 shouldBe "my-tag-value1" tag2 shouldBe "my-tag-value2" propertiesModelStore.model.tags["my-tag-key4"] shouldBe "my-tag-value4" @@ -129,7 +136,7 @@ class UserManagerTests : FunSpec({ } test("subscriptions are backed by the subscriptions manager") { - /* Given */ + // Given val subscriptionList = SubscriptionList(listOf(), UninitializedPushSubscription()) val mockSubscriptionManager = mockk() every { mockSubscriptionManager.subscriptions } returns subscriptionList @@ -138,9 +145,15 @@ class UserManagerTests : FunSpec({ every { mockSubscriptionManager.addSmsSubscription(any()) } just runs every { mockSubscriptionManager.removeSmsSubscription(any()) } just runs - val userManager = UserManager(mockSubscriptionManager, MockHelper.identityModelStore(), MockHelper.propertiesModelStore(), MockHelper.languageContext()) + val userManager = + UserManager( + mockSubscriptionManager, + MockHelper.identityModelStore(), + MockHelper.propertiesModelStore(), + MockHelper.languageContext(), + ) - /* When */ + // When val subscriptions = userManager.subscriptions userManager.addEmail("email@co.com") userManager.removeEmail("email@co.com") @@ -148,7 +161,7 @@ class UserManagerTests : FunSpec({ userManager.addSms("+15558675309") userManager.removeSms("+15558675309") - /* Then */ + // Then subscriptions shouldBe subscriptionList verify(exactly = 1) { mockSubscriptionManager.addEmailSubscription("email@co.com") } verify(exactly = 1) { mockSubscriptionManager.removeEmailSubscription("email@co.com") } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/IdentityBackendServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/IdentityBackendServiceTests.kt index 9348354bd0..622722fcca 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/IdentityBackendServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/IdentityBackendServiceTests.kt @@ -20,7 +20,7 @@ class IdentityBackendServiceTests : FunSpec({ } test("create identity") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -28,10 +28,10 @@ class IdentityBackendServiceTests : FunSpec({ val identityBackendService = IdentityBackendService(spyHttpClient) val identities = mapOf("aliasKey1" to "aliasValue1") - /* When */ + // When val response = identityBackendService.setAlias("appId", aliasLabel, aliasValue, identities) - /* Then */ + // Then response["aliasKey1"] shouldBe "aliasValue1" coVerify { spyHttpClient.patch( @@ -46,7 +46,7 @@ class IdentityBackendServiceTests : FunSpec({ } test("delete identity") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val aliasToDelete = "aliasKey1" @@ -54,10 +54,10 @@ class IdentityBackendServiceTests : FunSpec({ coEvery { spyHttpClient.delete(any()) } returns HttpResponse(200, "") val identityBackendService = IdentityBackendService(spyHttpClient) - /* When */ + // When identityBackendService.deleteAlias("appId", aliasLabel, aliasValue, aliasToDelete) - /* Then */ + // Then coVerify { spyHttpClient.delete("apps/appId/users/by/$aliasLabel/$aliasValue/identity/$aliasToDelete") } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt index 1401227c82..2fe09b7a4e 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/SubscriptionBackendServiceTests.kt @@ -25,25 +25,26 @@ class SubscriptionBackendServiceTests : FunSpec({ } test("create subscription") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{id: \"subscriptionId\"}") val subscriptionBackendService = SubscriptionBackendService(spyHttpClient) - /* When */ - val subscription = SubscriptionObject( - "no-id", - SubscriptionObjectType.ANDROID_PUSH, - "pushToken", - true, - SubscriptionStatus.SUBSCRIBED.value, - ) + // When + val subscription = + SubscriptionObject( + "no-id", + SubscriptionObjectType.ANDROID_PUSH, + "pushToken", + true, + SubscriptionStatus.SUBSCRIBED.value, + ) val response = subscriptionBackendService.createSubscription("appId", aliasLabel, aliasValue, subscription) - /* Then */ + // Then response shouldBe "subscriptionId" coVerify { spyHttpClient.post( @@ -60,33 +61,35 @@ class SubscriptionBackendServiceTests : FunSpec({ } test("create subscription throws exception when bad response") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(404, "NOT FOUND") val subscriptionBackendService = SubscriptionBackendService(spyHttpClient) - /* When */ - val subscription = SubscriptionObject( - "no-id", - SubscriptionObjectType.ANDROID_PUSH, - "pushToken", - true, - SubscriptionStatus.SUBSCRIBED.value, - ) - val exception = shouldThrowUnit { - subscriptionBackendService.createSubscription( - "appId", - aliasLabel, - aliasValue, - subscription, + // When + val subscription = + SubscriptionObject( + "no-id", + SubscriptionObjectType.ANDROID_PUSH, + "pushToken", + true, + SubscriptionStatus.SUBSCRIBED.value, ) - } + val exception = + shouldThrowUnit { + subscriptionBackendService.createSubscription( + "appId", + aliasLabel, + aliasValue, + subscription, + ) + } exception.statusCode shouldBe 404 exception.response shouldBe "NOT FOUND" - /* Then */ + // Then coVerify { spyHttpClient.post( "apps/appId/user/by/$aliasLabel/$aliasValue/subscription", diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/UserBackendServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/UserBackendServiceTests.kt index d26b4b94d6..976ec9eb1d 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/UserBackendServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/UserBackendServiceTests.kt @@ -23,7 +23,7 @@ class UserBackendServiceTests : FunSpec({ } test("create user with nothing throws an exception") { - /* Given */ + // Given val spyHttpClient = mockk() coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(403, "FORBIDDEN") val userBackendService = UserBackendService(spyHttpClient) @@ -31,30 +31,33 @@ class UserBackendServiceTests : FunSpec({ val properties = mapOf() val subscriptions = listOf() - /* When */ - val exception = shouldThrowUnit { - userBackendService.createUser("appId", identities, subscriptions, properties) - } + // When + val exception = + shouldThrowUnit { + userBackendService.createUser("appId", identities, subscriptions, properties) + } - /* Then */ + // Then exception.statusCode shouldBe 403 exception.response shouldBe "FORBIDDEN" } test("create user with an alias creates a new user") { - /* Given */ + // Given val osId = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() - coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{identity:{onesignal_id: \"$osId\", aliasLabel1: \"aliasValue1\"}, properties:{timezone_id: \"testTimeZone\", language: \"testLanguage\"}}") + coEvery { + spyHttpClient.post(any(), any()) + } returns HttpResponse(202, "{identity:{onesignal_id: \"$osId\", aliasLabel1: \"aliasValue1\"}, properties:{timezone_id: \"testTimeZone\", language: \"testLanguage\"}}") val userBackendService = UserBackendService(spyHttpClient) val identities = mapOf("aliasLabel1" to "aliasValue1") val properties = mapOf("timezone_id" to "testTimeZone", "language" to "testLanguage") val subscriptions = listOf() - /* When */ + // When val response = userBackendService.createUser("appId", identities, subscriptions, properties) - /* Then */ + // Then response.identities["onesignal_id"] shouldBe osId response.identities["aliasLabel1"] shouldBe "aliasValue1" response.properties.timezoneId shouldBe "testTimeZone" @@ -75,20 +78,22 @@ class UserBackendServiceTests : FunSpec({ } test("create user with a subscription creates a new user") { - /* Given */ + // Given val osId = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() - coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{identity:{onesignal_id: \"$osId\"}, subscriptions:[{id:\"subscriptionId1\", type:\"AndroidPush\"}], properties:{timezone_id: \"testTimeZone\", language: \"testLanguage\"}}") + coEvery { + spyHttpClient.post(any(), any()) + } returns HttpResponse(202, "{identity:{onesignal_id: \"$osId\"}, subscriptions:[{id:\"subscriptionId1\", type:\"AndroidPush\"}], properties:{timezone_id: \"testTimeZone\", language: \"testLanguage\"}}") val userBackendService = UserBackendService(spyHttpClient) val identities = mapOf() val subscriptions = mutableListOf() val properties = mapOf("timezone_id" to "testTimeZone", "language" to "testLanguage") subscriptions.add(SubscriptionObject("SHOULDNOTUSE", SubscriptionObjectType.ANDROID_PUSH)) - /* When */ + // When val response = userBackendService.createUser("appId", identities, subscriptions, properties) - /* Then */ + // Then response.identities["onesignal_id"] shouldBe osId response.properties.timezoneId shouldBe "testTimeZone" response.properties.language shouldBe "testLanguage" @@ -112,7 +117,7 @@ class UserBackendServiceTests : FunSpec({ } test("update user tags") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -121,10 +126,10 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject(tags = mapOf("tagkey1" to "tagValue1")) val propertiesDelta = PropertiesDeltasObject() - /* When */ + // When userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - /* Then */ + // Then coVerify { spyHttpClient.patch( "apps/appId/users/by/$aliasLabel/$aliasValue", @@ -139,7 +144,7 @@ class UserBackendServiceTests : FunSpec({ } test("update user language") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -148,10 +153,10 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject(language = "newLanguage") val propertiesDelta = PropertiesDeltasObject() - /* When */ + // When userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - /* Then */ + // Then coVerify { spyHttpClient.patch( "apps/appId/users/by/$aliasLabel/$aliasValue", @@ -165,7 +170,7 @@ class UserBackendServiceTests : FunSpec({ } test("update user timezone") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -174,10 +179,10 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject(timezoneId = "America/New_York") val propertiesDelta = PropertiesDeltasObject() - /* When */ + // When userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - /* Then */ + // Then coVerify { spyHttpClient.patch( "apps/appId/users/by/$aliasLabel/$aliasValue", @@ -191,7 +196,7 @@ class UserBackendServiceTests : FunSpec({ } test("update user country") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -200,10 +205,10 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject(country = "TV") val propertiesDelta = PropertiesDeltasObject() - /* When */ + // When userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - /* Then */ + // Then coVerify { spyHttpClient.patch( "apps/appId/users/by/$aliasLabel/$aliasValue", @@ -217,7 +222,7 @@ class UserBackendServiceTests : FunSpec({ } test("update user location") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -226,10 +231,10 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject(latitude = 12.34, longitude = 45.67) val propertiesDelta = PropertiesDeltasObject() - /* When */ + // When userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - /* Then */ + // Then coVerify { spyHttpClient.patch( "apps/appId/users/by/$aliasLabel/$aliasValue", @@ -245,7 +250,7 @@ class UserBackendServiceTests : FunSpec({ } test("update user with refresh metadata") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -254,10 +259,10 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject(tags = mapOf("tagkey1" to "tagValue1")) val propertiesDelta = PropertiesDeltasObject() - /* When */ + // When userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - /* Then */ + // Then coVerify { spyHttpClient.patch( "apps/appId/users/by/$aliasLabel/$aliasValue", @@ -269,7 +274,7 @@ class UserBackendServiceTests : FunSpec({ } test("update user without refresh metadata") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -278,10 +283,10 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject(tags = mapOf("tagkey1" to "tagValue1")) val propertiesDelta = PropertiesDeltasObject() - /* When */ + // When userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = false, propertiesDelta) - /* Then */ + // Then coVerify { spyHttpClient.patch( "apps/appId/users/by/$aliasLabel/$aliasValue", @@ -293,7 +298,7 @@ class UserBackendServiceTests : FunSpec({ } test("update user delta session") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -302,10 +307,10 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject() val propertiesDelta = PropertiesDeltasObject(sessionTime = 1111, sessionCount = 1) - /* When */ + // When userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - /* Then */ + // Then coVerify { spyHttpClient.patch( "apps/appId/users/by/$aliasLabel/$aliasValue", @@ -321,25 +326,27 @@ class UserBackendServiceTests : FunSpec({ } test("update user delta purchase") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() coEvery { spyHttpClient.patch(any(), any()) } returns HttpResponse(202, "{properties: { }}") val userBackendService = UserBackendService(spyHttpClient) val properties = PropertiesObject() - val propertiesDelta = PropertiesDeltasObject( - amountSpent = BigDecimal(1111), - purchases = listOf( - PurchaseObject("sku1", "iso1", BigDecimal(2222)), - PurchaseObject("sku2", "iso2", BigDecimal(4444)), - ), - ) - - /* When */ + val propertiesDelta = + PropertiesDeltasObject( + amountSpent = BigDecimal(1111), + purchases = + listOf( + PurchaseObject("sku1", "iso1", BigDecimal(2222)), + PurchaseObject("sku2", "iso2", BigDecimal(4444)), + ), + ) + + // When userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - /* Then */ + // Then coVerify { spyHttpClient.patch( "apps/appId/users/by/$aliasLabel/$aliasValue", @@ -367,7 +374,7 @@ class UserBackendServiceTests : FunSpec({ } test("update user but user not found throws exception") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -376,18 +383,19 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject(tags = mapOf("tagkey1" to "tagValue1")) val propertiesDelta = PropertiesDeltasObject() - /* When */ - val exception = shouldThrowUnit { - userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - } + // When + val exception = + shouldThrowUnit { + userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) + } - /* Then */ + // Then exception.statusCode shouldBe 404 exception.response shouldBe "NOT FOUND" } test("update user but other error throws exception") { - /* Given */ + // Given val aliasLabel = "onesignal_id" val aliasValue = "11111111-1111-1111-1111-111111111111" val spyHttpClient = mockk() @@ -396,12 +404,13 @@ class UserBackendServiceTests : FunSpec({ val properties = PropertiesObject(tags = mapOf("tagkey1" to "tagValue1")) val propertiesDelta = PropertiesDeltasObject() - /* When */ - val exception = shouldThrowUnit { - userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) - } + // When + val exception = + shouldThrowUnit { + userBackendService.updateUser("appId", aliasLabel, aliasValue, properties, refreshDeviceMetadata = true, propertiesDelta) + } - /* Then */ + // Then exception.statusCode shouldBe 403 exception.response shouldBe "FORBIDDEN" } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/IdentityOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/IdentityOperationExecutorTests.kt index 66c8a9feed..1add38f1b6 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/IdentityOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/IdentityOperationExecutorTests.kt @@ -27,7 +27,7 @@ import org.junit.runner.RunWith class IdentityOperationExecutorTests : FunSpec({ test("execution of set alias operation") { - /* Given */ + // Given val mockIdentityBackendService = mockk() coEvery { mockIdentityBackendService.setAlias(any(), any(), any(), any()) } returns mapOf() @@ -43,17 +43,19 @@ class IdentityOperationExecutorTests : FunSpec({ val identityOperationExecutor = IdentityOperationExecutor(mockIdentityBackendService, mockIdentityModelStore, mockBuildUserService) val operations = listOf(SetAliasOperation("appId", "onesignalId", "aliasKey1", "aliasValue1")) - /* When */ + // When val response = identityOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS - coVerify(exactly = 1) { mockIdentityBackendService.setAlias("appId", IdentityConstants.ONESIGNAL_ID, "onesignalId", mapOf("aliasKey1" to "aliasValue1")) } + coVerify(exactly = 1) { + mockIdentityBackendService.setAlias("appId", IdentityConstants.ONESIGNAL_ID, "onesignalId", mapOf("aliasKey1" to "aliasValue1")) + } verify(exactly = 1) { mockIdentityModel.setStringProperty("aliasKey1", "aliasValue1", ModelChangeTags.HYDRATE) } } test("execution of set alias operation with network timeout") { - /* Given */ + // Given val mockIdentityBackendService = mockk() coEvery { mockIdentityBackendService.setAlias(any(), any(), any(), any()) } throws BackendException(408, "TIMEOUT") @@ -63,16 +65,16 @@ class IdentityOperationExecutorTests : FunSpec({ val identityOperationExecutor = IdentityOperationExecutor(mockIdentityBackendService, mockIdentityModelStore, mockBuildUserService) val operations = listOf(SetAliasOperation("appId", "onesignalId", "aliasKey1", "aliasValue1")) - /* When */ + // When val response = identityOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_RETRY } test("execution of set alias operation with non-retryable error") { - /* Given */ + // Given val mockIdentityBackendService = mockk() coEvery { mockIdentityBackendService.setAlias(any(), any(), any(), any()) } throws BackendException(400, "INVALID") @@ -82,16 +84,16 @@ class IdentityOperationExecutorTests : FunSpec({ val identityOperationExecutor = IdentityOperationExecutor(mockIdentityBackendService, mockIdentityModelStore, mockBuildUserService) val operations = listOf(SetAliasOperation("appId", "onesignalId", "aliasKey1", "aliasValue1")) - /* When */ + // When val response = identityOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_NORETRY } test("execution of delete alias operation") { - /* Given */ + // Given val mockIdentityBackendService = mockk() coEvery { mockIdentityBackendService.deleteAlias(any(), any(), any(), any()) } just runs @@ -107,17 +109,19 @@ class IdentityOperationExecutorTests : FunSpec({ val identityOperationExecutor = IdentityOperationExecutor(mockIdentityBackendService, mockIdentityModelStore, mockBuildUserService) val operations = listOf(DeleteAliasOperation("appId", "onesignalId", "aliasKey1")) - /* When */ + // When val response = identityOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS - coVerify(exactly = 1) { mockIdentityBackendService.deleteAlias("appId", IdentityConstants.ONESIGNAL_ID, "onesignalId", "aliasKey1") } + coVerify( + exactly = 1, + ) { mockIdentityBackendService.deleteAlias("appId", IdentityConstants.ONESIGNAL_ID, "onesignalId", "aliasKey1") } verify(exactly = 1) { mockIdentityModel.setOptStringProperty("aliasKey1", null, ModelChangeTags.HYDRATE) } } test("execution of delete alias operation with network timeout") { - /* Given */ + // Given val mockIdentityBackendService = mockk() coEvery { mockIdentityBackendService.deleteAlias(any(), any(), any(), any()) } throws BackendException(408, "TIMEOUT") @@ -127,16 +131,16 @@ class IdentityOperationExecutorTests : FunSpec({ val identityOperationExecutor = IdentityOperationExecutor(mockIdentityBackendService, mockIdentityModelStore, mockBuildUserService) val operations = listOf(DeleteAliasOperation("appId", "onesignalId", "aliasKey1")) - /* When */ + // When val response = identityOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_RETRY } test("execution of delete alias operation with non-retryable error") { - /* Given */ + // Given val mockIdentityBackendService = mockk() coEvery { mockIdentityBackendService.deleteAlias(any(), any(), any(), any()) } throws BackendException(400, "INVALID") @@ -146,11 +150,11 @@ class IdentityOperationExecutorTests : FunSpec({ val identityOperationExecutor = IdentityOperationExecutor(mockIdentityBackendService, mockIdentityModelStore, mockBuildUserService) val operations = listOf(DeleteAliasOperation("appId", "onesignalId", "aliasKey1")) - /* When */ + // When val response = identityOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_NORETRY } }) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt index 8c5a77fb0e..75a2187841 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt @@ -44,7 +44,7 @@ class LoginUserOperationExecutorTests : FunSpec({ val remoteSubscriptionId2 = "remote-subscriptionId2" test("login anonymous user successfully creates user") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns CreateUserResponse( @@ -52,29 +52,30 @@ class LoginUserOperationExecutorTests : FunSpec({ PropertiesObject(), listOf(), ) - /* Given */ + // Given val mockIdentityOperationExecutor = mockk() val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() - val loginUserOperationExecutor = LoginUserOperationExecutor( - mockIdentityOperationExecutor, - MockHelper.applicationService(), - MockHelper.deviceService(), - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - MockHelper.languageContext() - ) + val loginUserOperationExecutor = + LoginUserOperationExecutor( + mockIdentityOperationExecutor, + MockHelper.applicationService(), + MockHelper.deviceService(), + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + MockHelper.languageContext(), + ) val operations = listOf(LoginUserOperation(appId, localOneSignalId, null, null)) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockUserBackendService.createUser( @@ -87,7 +88,7 @@ class LoginUserOperationExecutorTests : FunSpec({ } test("login anonymous user fails with retry when network condition exists") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(408, "TIMEOUT") @@ -97,19 +98,20 @@ class LoginUserOperationExecutorTests : FunSpec({ val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() - val loginUserOperationExecutor = LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) + val loginUserOperationExecutor = + LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) val operations = listOf(LoginUserOperation(appId, localOneSignalId, null, null)) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_RETRY coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) } } test("login anonymous user fails with no retry when backend error condition exists") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(404, "NOT FOUND") @@ -119,19 +121,20 @@ class LoginUserOperationExecutorTests : FunSpec({ val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() - val loginUserOperationExecutor = LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) + val loginUserOperationExecutor = + LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) val operations = listOf(LoginUserOperation(appId, localOneSignalId, null, null)) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_NORETRY coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) } } test("login identified user without association successfully creates user") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns CreateUserResponse(mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId), PropertiesObject(), listOf()) @@ -142,19 +145,22 @@ class LoginUserOperationExecutorTests : FunSpec({ val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() - val loginUserOperationExecutor = LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) + val loginUserOperationExecutor = + LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) val operations = listOf(LoginUserOperation(appId, localOneSignalId, "externalId", null)) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS - coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any(), any()) } + coVerify( + exactly = 1, + ) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any(), any()) } } test("login identified user with association succeeds when association is successful") { - /* Given */ + // Given val mockUserBackendService = mockk() val mockIdentityOperationExecutor = mockk() @@ -164,13 +170,14 @@ class LoginUserOperationExecutorTests : FunSpec({ val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() - val loginUserOperationExecutor = LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) + val loginUserOperationExecutor = + LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) val operations = listOf(LoginUserOperation(appId, localOneSignalId, "externalId", "existingOneSignalId")) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBeOneOf listOf(ExecutionResult.SUCCESS, ExecutionResult.SUCCESS_STARTING_ONLY) coVerify(exactly = 1) { mockIdentityOperationExecutor.execute( @@ -187,7 +194,7 @@ class LoginUserOperationExecutorTests : FunSpec({ } test("login identified user with association fails with retry when association fails with retry") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns CreateUserResponse(mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId), PropertiesObject(), listOf()) @@ -199,13 +206,14 @@ class LoginUserOperationExecutorTests : FunSpec({ val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() - val loginUserOperationExecutor = LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) + val loginUserOperationExecutor = + LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) val operations = listOf(LoginUserOperation(appId, localOneSignalId, "externalId", "existingOneSignalId")) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_RETRY coVerify(exactly = 1) { mockIdentityOperationExecutor.execute( @@ -222,7 +230,7 @@ class LoginUserOperationExecutorTests : FunSpec({ } test("login identified user with association successfully creates user when association fails with no retry") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns CreateUserResponse(mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId), PropertiesObject(), listOf()) @@ -234,13 +242,14 @@ class LoginUserOperationExecutorTests : FunSpec({ val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() - val loginUserOperationExecutor = LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) + val loginUserOperationExecutor = + LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) val operations = listOf(LoginUserOperation(appId, localOneSignalId, "externalId", "existingOneSignalId")) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBeOneOf listOf(ExecutionResult.SUCCESS, ExecutionResult.SUCCESS_STARTING_ONLY) coVerify(exactly = 1) { mockIdentityOperationExecutor.execute( @@ -254,11 +263,13 @@ class LoginUserOperationExecutorTests : FunSpec({ }, ) } - coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any(), any()) } + coVerify( + exactly = 1, + ) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any(), any()) } } test("login identified user with association fails with retry when association fails with no retry and network condition exists") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(408, "TIMEOUT") @@ -269,13 +280,14 @@ class LoginUserOperationExecutorTests : FunSpec({ val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() - val loginUserOperationExecutor = LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) + val loginUserOperationExecutor = + LoginUserOperationExecutor(mockIdentityOperationExecutor, MockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) val operations = listOf(LoginUserOperation(appId, localOneSignalId, "externalId", "existingOneSignalId")) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_RETRY coVerify(exactly = 1) { mockIdentityOperationExecutor.execute( @@ -289,11 +301,13 @@ class LoginUserOperationExecutorTests : FunSpec({ }, ) } - coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any(), any()) } + coVerify( + exactly = 1, + ) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any(), any()) } } test("creating user will merge operations into one backend call") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns CreateUserResponse( @@ -301,53 +315,79 @@ class LoginUserOperationExecutorTests : FunSpec({ PropertiesObject(), listOf(), ) - /* Given */ + // Given val mockIdentityOperationExecutor = mockk() val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() - val loginUserOperationExecutor = LoginUserOperationExecutor( - mockIdentityOperationExecutor, - AndroidMockHelper.applicationService(), - MockHelper.deviceService(), - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - MockHelper.languageContext() - ) - val operations = listOf( - LoginUserOperation(appId, localOneSignalId, null, null), - SetAliasOperation(appId, localOneSignalId, "aliasLabel1", "aliasValue1-1"), - SetAliasOperation(appId, localOneSignalId, "aliasLabel1", "aliasValue1-2"), - SetAliasOperation(appId, localOneSignalId, "aliasLabel2", "aliasValue2"), - DeleteAliasOperation(appId, localOneSignalId, "aliasLabel2"), - CreateSubscriptionOperation(appId, localOneSignalId, "subscriptionId1", SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), - UpdateSubscriptionOperation(appId, localOneSignalId, "subscriptionId1", SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED), - CreateSubscriptionOperation(appId, localOneSignalId, "subscriptionId2", SubscriptionType.EMAIL, true, "name@company.com", SubscriptionStatus.SUBSCRIBED), - DeleteSubscriptionOperation(appId, localOneSignalId, "subscriptionId2"), - SetTagOperation(appId, localOneSignalId, "tagKey1", "tagValue1-1"), - SetTagOperation(appId, localOneSignalId, "tagKey1", "tagValue1-2"), - SetTagOperation(appId, localOneSignalId, "tagKey2", "tagValue2"), - DeleteTagOperation(appId, localOneSignalId, "tagKey2"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::language.name, "lang1"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::language.name, "lang2"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::timezone.name, "timezone"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::country.name, "country"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationLatitude.name, 123.45), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationLongitude.name, 678.90), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationType.name, 1), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationAccuracy.name, 0.15), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationBackground.name, true), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationTimestamp.name, 1111L), - ) - - /* When */ + val loginUserOperationExecutor = + LoginUserOperationExecutor( + mockIdentityOperationExecutor, + AndroidMockHelper.applicationService(), + MockHelper.deviceService(), + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + MockHelper.languageContext(), + ) + val operations = + listOf( + LoginUserOperation(appId, localOneSignalId, null, null), + SetAliasOperation(appId, localOneSignalId, "aliasLabel1", "aliasValue1-1"), + SetAliasOperation(appId, localOneSignalId, "aliasLabel1", "aliasValue1-2"), + SetAliasOperation(appId, localOneSignalId, "aliasLabel2", "aliasValue2"), + DeleteAliasOperation(appId, localOneSignalId, "aliasLabel2"), + CreateSubscriptionOperation( + appId, + localOneSignalId, + "subscriptionId1", + SubscriptionType.PUSH, + true, + "pushToken1", + SubscriptionStatus.SUBSCRIBED, + ), + UpdateSubscriptionOperation( + appId, + localOneSignalId, + "subscriptionId1", + SubscriptionType.PUSH, + true, + "pushToken2", + SubscriptionStatus.SUBSCRIBED, + ), + CreateSubscriptionOperation( + appId, + localOneSignalId, + "subscriptionId2", + SubscriptionType.EMAIL, + true, + "name@company.com", + SubscriptionStatus.SUBSCRIBED, + ), + DeleteSubscriptionOperation(appId, localOneSignalId, "subscriptionId2"), + SetTagOperation(appId, localOneSignalId, "tagKey1", "tagValue1-1"), + SetTagOperation(appId, localOneSignalId, "tagKey1", "tagValue1-2"), + SetTagOperation(appId, localOneSignalId, "tagKey2", "tagValue2"), + DeleteTagOperation(appId, localOneSignalId, "tagKey2"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::language.name, "lang1"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::language.name, "lang2"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::timezone.name, "timezone"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::country.name, "country"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationLatitude.name, 123.45), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationLongitude.name, 678.90), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationType.name, 1), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationAccuracy.name, 0.15), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationBackground.name, true), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationTimestamp.name, 1111L), + ) + + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockUserBackendService.createUser( @@ -366,7 +406,7 @@ class LoginUserOperationExecutorTests : FunSpec({ } test("creating user will hydrate when the user hasn't changed") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns CreateUserResponse( @@ -374,7 +414,7 @@ class LoginUserOperationExecutorTests : FunSpec({ PropertiesObject(), listOf(SubscriptionObject(remoteSubscriptionId1, SubscriptionObjectType.ANDROID_PUSH), SubscriptionObject(remoteSubscriptionId2, SubscriptionObjectType.EMAIL)), ) - /* Given */ + // Given val mockIdentityOperationExecutor = mockk() val mockIdentityModelStore = MockHelper.identityModelStore() @@ -395,27 +435,45 @@ class LoginUserOperationExecutorTests : FunSpec({ every { mockSubscriptionsModelStore.get(localSubscriptionId1) } returns subscriptionModel1 every { mockSubscriptionsModelStore.get(localSubscriptionId2) } returns subscriptionModel2 - val loginUserOperationExecutor = LoginUserOperationExecutor( - mockIdentityOperationExecutor, - AndroidMockHelper.applicationService(), - MockHelper.deviceService(), - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - MockHelper.languageContext() - ) - val operations = listOf( - LoginUserOperation(appId, localOneSignalId, null, null), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionStatus.SUBSCRIBED), - ) - - /* When */ + val loginUserOperationExecutor = + LoginUserOperationExecutor( + mockIdentityOperationExecutor, + AndroidMockHelper.applicationService(), + MockHelper.deviceService(), + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + MockHelper.languageContext(), + ) + val operations = + listOf( + LoginUserOperation(appId, localOneSignalId, null, null), + CreateSubscriptionOperation( + appId, + localOneSignalId, + localSubscriptionId1, + SubscriptionType.PUSH, + true, + "pushToken1", + SubscriptionStatus.SUBSCRIBED, + ), + CreateSubscriptionOperation( + appId, + localOneSignalId, + localSubscriptionId2, + SubscriptionType.EMAIL, + true, + "name@company.com", + SubscriptionStatus.SUBSCRIBED, + ), + ) + + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS mockIdentityModel.onesignalId shouldBe remoteOneSignalId @@ -434,7 +492,7 @@ class LoginUserOperationExecutorTests : FunSpec({ } test("creating user will not hydrate when the user has changed") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns CreateUserResponse( @@ -442,7 +500,7 @@ class LoginUserOperationExecutorTests : FunSpec({ PropertiesObject(), listOf(SubscriptionObject(remoteSubscriptionId1, SubscriptionObjectType.ANDROID_PUSH), SubscriptionObject(remoteSubscriptionId2, SubscriptionObjectType.EMAIL)), ) - /* Given */ + // Given val mockIdentityOperationExecutor = mockk() val mockIdentityModelStore = MockHelper.identityModelStore() @@ -463,27 +521,45 @@ class LoginUserOperationExecutorTests : FunSpec({ every { mockSubscriptionsModelStore.get(localSubscriptionId1) } returns null every { mockSubscriptionsModelStore.get(localSubscriptionId2) } returns null - val loginUserOperationExecutor = LoginUserOperationExecutor( - mockIdentityOperationExecutor, - AndroidMockHelper.applicationService(), - MockHelper.deviceService(), - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - MockHelper.languageContext() - ) - val operations = listOf( - LoginUserOperation(appId, localOneSignalId, null, null), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionStatus.SUBSCRIBED), - ) - - /* When */ + val loginUserOperationExecutor = + LoginUserOperationExecutor( + mockIdentityOperationExecutor, + AndroidMockHelper.applicationService(), + MockHelper.deviceService(), + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + MockHelper.languageContext(), + ) + val operations = + listOf( + LoginUserOperation(appId, localOneSignalId, null, null), + CreateSubscriptionOperation( + appId, + localOneSignalId, + localSubscriptionId1, + SubscriptionType.PUSH, + true, + "pushToken1", + SubscriptionStatus.SUBSCRIBED, + ), + CreateSubscriptionOperation( + appId, + localOneSignalId, + localSubscriptionId2, + SubscriptionType.EMAIL, + true, + "name@company.com", + SubscriptionStatus.SUBSCRIBED, + ), + ) + + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS mockIdentityModel.onesignalId shouldBe "new-local-onesignalId" @@ -502,7 +578,7 @@ class LoginUserOperationExecutorTests : FunSpec({ } test("creating user will provide local to remote translations") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns CreateUserResponse( @@ -510,34 +586,52 @@ class LoginUserOperationExecutorTests : FunSpec({ PropertiesObject(), listOf(SubscriptionObject(remoteSubscriptionId1, SubscriptionObjectType.ANDROID_PUSH), SubscriptionObject(remoteSubscriptionId2, SubscriptionObjectType.EMAIL)), ) - /* Given */ + // Given val mockIdentityOperationExecutor = mockk() val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() every { mockSubscriptionsModelStore.get(any()) } returns null - val loginUserOperationExecutor = LoginUserOperationExecutor( - mockIdentityOperationExecutor, - AndroidMockHelper.applicationService(), - MockHelper.deviceService(), - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - MockHelper.languageContext() - ) - val operations = listOf( - LoginUserOperation(appId, localOneSignalId, null, null), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), - CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionStatus.SUBSCRIBED), - ) - - /* When */ + val loginUserOperationExecutor = + LoginUserOperationExecutor( + mockIdentityOperationExecutor, + AndroidMockHelper.applicationService(), + MockHelper.deviceService(), + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + MockHelper.languageContext(), + ) + val operations = + listOf( + LoginUserOperation(appId, localOneSignalId, null, null), + CreateSubscriptionOperation( + appId, + localOneSignalId, + localSubscriptionId1, + SubscriptionType.PUSH, + true, + "pushToken1", + SubscriptionStatus.SUBSCRIBED, + ), + CreateSubscriptionOperation( + appId, + localOneSignalId, + localSubscriptionId2, + SubscriptionType.EMAIL, + true, + "name@company.com", + SubscriptionStatus.SUBSCRIBED, + ), + ) + + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS response.idTranslations shouldBe mapOf(localOneSignalId to remoteOneSignalId, localSubscriptionId1 to remoteSubscriptionId1, localSubscriptionId2 to remoteSubscriptionId2) coVerify(exactly = 1) { diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/RefreshUserOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/RefreshUserOperationExecutorTests.kt index ac3a343750..c2ee861d8e 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/RefreshUserOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/RefreshUserOperationExecutorTests.kt @@ -37,7 +37,7 @@ class RefreshUserOperationExecutorTests : FunSpec({ val remoteSubscriptionId2 = "remote-subscriptionId2" test("refresh user is successful") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.getUser(appId, IdentityConstants.ONESIGNAL_ID, remoteOneSignalId) } returns CreateUserResponse( @@ -46,7 +46,7 @@ class RefreshUserOperationExecutorTests : FunSpec({ listOf(SubscriptionObject(existingSubscriptionId1, SubscriptionObjectType.ANDROID_PUSH, enabled = true, token = "pushToken1"), SubscriptionObject(remoteSubscriptionId1, SubscriptionObjectType.ANDROID_PUSH, enabled = true, token = "pushToken2"), SubscriptionObject(remoteSubscriptionId2, SubscriptionObjectType.EMAIL, token = "name@company.com")), ) - /* Given */ + // Given val mockIdentityModelStore = MockHelper.identityModelStore() val mockIdentityModel = IdentityModel() mockIdentityModel.onesignalId = remoteOneSignalId @@ -64,27 +64,29 @@ class RefreshUserOperationExecutorTests : FunSpec({ val mockSubscriptionsModelStore = mockk() every { mockSubscriptionsModelStore.replaceAll(any(), any()) } just runs - val mockConfigModelStore = MockHelper.configModelStore { - it.pushSubscriptionId = existingSubscriptionId1 - } + val mockConfigModelStore = + MockHelper.configModelStore { + it.pushSubscriptionId = existingSubscriptionId1 + } val mockBuildUserService = mockk() - val loginUserOperationExecutor = RefreshUserOperationExecutor( - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockSubscriptionsModelStore, - mockConfigModelStore, - mockBuildUserService, - ) + val loginUserOperationExecutor = + RefreshUserOperationExecutor( + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockSubscriptionsModelStore, + mockConfigModelStore, + mockBuildUserService, + ) val operations = listOf(RefreshUserOperation(appId, remoteOneSignalId)) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockUserBackendService.getUser(appId, IdentityConstants.ONESIGNAL_ID, remoteOneSignalId) @@ -119,7 +121,7 @@ class RefreshUserOperationExecutorTests : FunSpec({ } test("refresh user does not hydrate user when user has changed") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.getUser(appId, IdentityConstants.ONESIGNAL_ID, remoteOneSignalId) } returns CreateUserResponse( @@ -128,7 +130,7 @@ class RefreshUserOperationExecutorTests : FunSpec({ listOf(), ) - /* Given */ + // Given val mockIdentityModelStore = MockHelper.identityModelStore() val mockIdentityModel = IdentityModel() mockIdentityModel.onesignalId = "new-onesignalId" @@ -143,21 +145,22 @@ class RefreshUserOperationExecutorTests : FunSpec({ val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() - val loginUserOperationExecutor = RefreshUserOperationExecutor( - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val loginUserOperationExecutor = + RefreshUserOperationExecutor( + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) val operations = listOf(RefreshUserOperation(appId, remoteOneSignalId)) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS mockIdentityModel.onesignalId shouldBe "new-onesignalId" mockPropertiesModel.onesignalId shouldBe "new-onesignalId" @@ -168,31 +171,32 @@ class RefreshUserOperationExecutorTests : FunSpec({ } test("refresh user fails with retry when there is a network condition") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.getUser(appId, IdentityConstants.ONESIGNAL_ID, remoteOneSignalId) } throws BackendException(408) - /* Given */ + // Given val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() - val loginUserOperationExecutor = RefreshUserOperationExecutor( - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val loginUserOperationExecutor = + RefreshUserOperationExecutor( + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) val operations = listOf(RefreshUserOperation(appId, remoteOneSignalId)) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_RETRY coVerify(exactly = 1) { mockUserBackendService.getUser(appId, IdentityConstants.ONESIGNAL_ID, remoteOneSignalId) @@ -200,31 +204,32 @@ class RefreshUserOperationExecutorTests : FunSpec({ } test("refresh user fails without retry when there is a backend error condition") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.getUser(appId, IdentityConstants.ONESIGNAL_ID, remoteOneSignalId) } throws BackendException(400) - /* Given */ + // Given val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() - val loginUserOperationExecutor = RefreshUserOperationExecutor( - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val loginUserOperationExecutor = + RefreshUserOperationExecutor( + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) val operations = listOf(RefreshUserOperation(appId, remoteOneSignalId)) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_NORETRY coVerify(exactly = 1) { mockUserBackendService.getUser(appId, IdentityConstants.ONESIGNAL_ID, remoteOneSignalId) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt index 3c108f830d..ea38d8cf6a 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/SubscriptionOperationExecutorTests.kt @@ -36,7 +36,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ val remoteSubscriptionId = "remote-subscriptionId1" test("create subscription successfully creates subscription") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.createSubscription(any(), any(), any(), any()) } returns remoteSubscriptionId @@ -47,21 +47,33 @@ class SubscriptionOperationExecutorTests : FunSpec({ val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) - val operations = listOf(CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionStatus.SUBSCRIBED)) + val operations = + listOf( + CreateSubscriptionOperation( + appId, + remoteOneSignalId, + localSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken", + SubscriptionStatus.SUBSCRIBED, + ), + ) - /* When */ + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS subscriptionModel1.id shouldBe remoteSubscriptionId coVerify(exactly = 1) { @@ -80,28 +92,40 @@ class SubscriptionOperationExecutorTests : FunSpec({ } test("create subscription fails with retry when there is a network condition") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.createSubscription(any(), any(), any(), any()) } throws BackendException(408) val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) - val operations = listOf(CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionStatus.SUBSCRIBED)) + val operations = + listOf( + CreateSubscriptionOperation( + appId, + remoteOneSignalId, + localSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken", + SubscriptionStatus.SUBSCRIBED, + ), + ) - /* When */ + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_RETRY coVerify(exactly = 1) { mockSubscriptionBackendService.createSubscription( @@ -119,28 +143,40 @@ class SubscriptionOperationExecutorTests : FunSpec({ } test("create subscription fails without retry when there is a backend error") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.createSubscription(any(), any(), any(), any()) } throws BackendException(404) val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) - val operations = listOf(CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionStatus.SUBSCRIBED)) + val operations = + listOf( + CreateSubscriptionOperation( + appId, + remoteOneSignalId, + localSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken", + SubscriptionStatus.SUBSCRIBED, + ), + ) - /* When */ + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_NORETRY coVerify(exactly = 1) { mockSubscriptionBackendService.createSubscription( @@ -158,7 +194,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ } test("create subscription then delete subscription is a successful no-op") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() val mockSubscriptionsModelStore = mockk() @@ -168,29 +204,39 @@ class SubscriptionOperationExecutorTests : FunSpec({ val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) - - val operations = listOf( - CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken", SubscriptionStatus.SUBSCRIBED), - DeleteSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId), - ) - - /* When */ + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) + + val operations = + listOf( + CreateSubscriptionOperation( + appId, + remoteOneSignalId, + localSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken", + SubscriptionStatus.SUBSCRIBED, + ), + DeleteSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId), + ) + + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS } test("create subscription then update subscription successfully creates subscription") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.createSubscription(any(), any(), any(), any()) } returns remoteSubscriptionId @@ -201,24 +247,42 @@ class SubscriptionOperationExecutorTests : FunSpec({ val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) - - val operations = listOf( - CreateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED), - UpdateSubscriptionOperation(appId, remoteOneSignalId, localSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED), - ) - - /* When */ + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) + + val operations = + listOf( + CreateSubscriptionOperation( + appId, + remoteOneSignalId, + localSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken1", + SubscriptionStatus.SUBSCRIBED, + ), + UpdateSubscriptionOperation( + appId, + remoteOneSignalId, + localSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken2", + SubscriptionStatus.SUBSCRIBED, + ), + ) + + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS subscriptionModel1.id shouldBe remoteSubscriptionId coVerify(exactly = 1) { @@ -237,7 +301,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ } test("update subscription successfully updates subscription") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.updateSubscription(any(), any(), any()) } just runs @@ -249,24 +313,42 @@ class SubscriptionOperationExecutorTests : FunSpec({ val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) - - val operations = listOf( - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED), - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken3", SubscriptionStatus.SUBSCRIBED), - ) - - /* When */ + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) + + val operations = + listOf( + UpdateSubscriptionOperation( + appId, + remoteOneSignalId, + remoteSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken2", + SubscriptionStatus.SUBSCRIBED, + ), + UpdateSubscriptionOperation( + appId, + remoteOneSignalId, + remoteSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken3", + SubscriptionStatus.SUBSCRIBED, + ), + ) + + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS subscriptionModel1.address shouldBe "pushToken3" coVerify(exactly = 1) { @@ -284,30 +366,40 @@ class SubscriptionOperationExecutorTests : FunSpec({ } test("update subscription fails with retry when there is a network condition") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.updateSubscription(any(), any(), any()) } throws BackendException(408) val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) - val operations = listOf( - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED), - ) + val operations = + listOf( + UpdateSubscriptionOperation( + appId, + remoteOneSignalId, + remoteSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken2", + SubscriptionStatus.SUBSCRIBED, + ), + ) - /* When */ + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_RETRY coVerify(exactly = 1) { mockSubscriptionBackendService.updateSubscription( @@ -324,30 +416,40 @@ class SubscriptionOperationExecutorTests : FunSpec({ } test("update subscription fails without retry when there is a backend error") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.updateSubscription(any(), any(), any()) } throws BackendException(404) val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) - val operations = listOf( - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED), - ) + val operations = + listOf( + UpdateSubscriptionOperation( + appId, + remoteOneSignalId, + remoteSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken2", + SubscriptionStatus.SUBSCRIBED, + ), + ) - /* When */ + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_NORETRY coVerify(exactly = 1) { mockSubscriptionBackendService.updateSubscription( @@ -364,7 +466,7 @@ class SubscriptionOperationExecutorTests : FunSpec({ } test("delete subscription successfully deletes subscription") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.deleteSubscription(any(), any()) } just runs @@ -373,83 +475,97 @@ class SubscriptionOperationExecutorTests : FunSpec({ val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) - - val operations = listOf( - UpdateSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED), - DeleteSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId), - ) - - /* When */ + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) + + val operations = + listOf( + UpdateSubscriptionOperation( + appId, + remoteOneSignalId, + remoteSubscriptionId, + SubscriptionType.PUSH, + true, + "pushToken2", + SubscriptionStatus.SUBSCRIBED, + ), + DeleteSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId), + ) + + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockSubscriptionBackendService.deleteSubscription(appId, remoteSubscriptionId) } verify(exactly = 1) { mockSubscriptionsModelStore.remove(remoteSubscriptionId, any()) } } test("delete subscription fails with retry when there is a network condition") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.deleteSubscription(any(), any()) } throws BackendException(408) val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) - val operations = listOf( - DeleteSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId), - ) + val operations = + listOf( + DeleteSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId), + ) - /* When */ + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_RETRY coVerify(exactly = 1) { mockSubscriptionBackendService.deleteSubscription(appId, remoteSubscriptionId) } } test("delete subscription fails without retry when there is a backend error") { - /* Given */ + // Given val mockSubscriptionBackendService = mockk() coEvery { mockSubscriptionBackendService.deleteSubscription(any(), any()) } throws BackendException(404) val mockSubscriptionsModelStore = mockk() val mockBuildUserService = mockk() - val subscriptionOperationExecutor = SubscriptionOperationExecutor( - mockSubscriptionBackendService, - MockHelper.deviceService(), - AndroidMockHelper.applicationService(), - mockSubscriptionsModelStore, - MockHelper.configModelStore(), - mockBuildUserService, - ) + val subscriptionOperationExecutor = + SubscriptionOperationExecutor( + mockSubscriptionBackendService, + MockHelper.deviceService(), + AndroidMockHelper.applicationService(), + mockSubscriptionsModelStore, + MockHelper.configModelStore(), + mockBuildUserService, + ) - val operations = listOf( - DeleteSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId), - ) + val operations = + listOf( + DeleteSubscriptionOperation(appId, remoteOneSignalId, remoteSubscriptionId), + ) - /* When */ + // When val response = subscriptionOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.FAIL_NORETRY coVerify(exactly = 1) { mockSubscriptionBackendService.deleteSubscription(appId, remoteSubscriptionId) } } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/UpdateUserOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/UpdateUserOperationExecutorTests.kt index 2db3d7942e..34e4ea33bb 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/UpdateUserOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/UpdateUserOperationExecutorTests.kt @@ -27,27 +27,28 @@ class UpdateUserOperationExecutorTests : FunSpec({ val remoteOneSignalId = "remote-onesignalId" test("update user single operation is successful") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.updateUser(any(), any(), any(), any(), any(), any()) } just runs - /* Given */ + // Given val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockBuildUserService = mockk() - val loginUserOperationExecutor = UpdateUserOperationExecutor( - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockBuildUserService, - ) + val loginUserOperationExecutor = + UpdateUserOperationExecutor( + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockBuildUserService, + ) val operations = listOf(SetTagOperation(appId, remoteOneSignalId, "tagKey1", "tagValue1")) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockUserBackendService.updateUser( @@ -64,43 +65,45 @@ class UpdateUserOperationExecutorTests : FunSpec({ } test("update user multiple property operations are successful") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.updateUser(any(), any(), any(), any(), any(), any()) } just runs - /* Given */ + // Given val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockBuildUserService = mockk() - val loginUserOperationExecutor = UpdateUserOperationExecutor( - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockBuildUserService, - ) - val operations = listOf( - SetTagOperation(appId, remoteOneSignalId, "tagKey1", "tagValue1-1"), - SetTagOperation(appId, remoteOneSignalId, "tagKey1", "tagValue1-2"), - SetTagOperation(appId, remoteOneSignalId, "tagKey2", "tagValue2"), - SetTagOperation(appId, remoteOneSignalId, "tagKey3", "tagValue3"), - DeleteTagOperation(appId, remoteOneSignalId, "tagKey3"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::language.name, "lang1"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::language.name, "lang2"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::timezone.name, "timezone"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::country.name, "country"), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationLatitude.name, 123.45), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationLongitude.name, 678.90), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationType.name, 1), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationAccuracy.name, 0.15), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationBackground.name, true), - SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationTimestamp.name, 1111L), - ) + val loginUserOperationExecutor = + UpdateUserOperationExecutor( + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockBuildUserService, + ) + val operations = + listOf( + SetTagOperation(appId, remoteOneSignalId, "tagKey1", "tagValue1-1"), + SetTagOperation(appId, remoteOneSignalId, "tagKey1", "tagValue1-2"), + SetTagOperation(appId, remoteOneSignalId, "tagKey2", "tagValue2"), + SetTagOperation(appId, remoteOneSignalId, "tagKey3", "tagValue3"), + DeleteTagOperation(appId, remoteOneSignalId, "tagKey3"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::language.name, "lang1"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::language.name, "lang2"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::timezone.name, "timezone"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::country.name, "country"), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationLatitude.name, 123.45), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationLongitude.name, 678.90), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationType.name, 1), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationAccuracy.name, 0.15), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationBackground.name, true), + SetPropertyOperation(appId, localOneSignalId, PropertiesModel::locationTimestamp.name, 1111L), + ) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockUserBackendService.updateUser( @@ -122,29 +125,31 @@ class UpdateUserOperationExecutorTests : FunSpec({ } test("update user single property delta operations is successful") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.updateUser(any(), any(), any(), any(), any(), any()) } just runs - /* Given */ + // Given val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockBuildUserService = mockk() - val loginUserOperationExecutor = UpdateUserOperationExecutor( - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockBuildUserService, - ) - val operations = listOf( - TrackSessionEndOperation(appId, remoteOneSignalId, 1111), - ) + val loginUserOperationExecutor = + UpdateUserOperationExecutor( + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockBuildUserService, + ) + val operations = + listOf( + TrackSessionEndOperation(appId, remoteOneSignalId, 1111), + ) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockUserBackendService.updateUser( @@ -163,40 +168,42 @@ class UpdateUserOperationExecutorTests : FunSpec({ } test("update user multiple property delta operations are successful") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.updateUser(any(), any(), any(), any(), any(), any()) } just runs - /* Given */ + // Given val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockBuildUserService = mockk() - val loginUserOperationExecutor = UpdateUserOperationExecutor( - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockBuildUserService, - ) - val operations = listOf( - TrackSessionEndOperation(appId, remoteOneSignalId, 1111), - TrackPurchaseOperation( - appId, - remoteOneSignalId, - false, - BigDecimal(2222), - listOf( - PurchaseInfo("sku1", "iso1", BigDecimal(1000)), - PurchaseInfo("sku2", "iso2", BigDecimal(1222)), + val loginUserOperationExecutor = + UpdateUserOperationExecutor( + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockBuildUserService, + ) + val operations = + listOf( + TrackSessionEndOperation(appId, remoteOneSignalId, 1111), + TrackPurchaseOperation( + appId, + remoteOneSignalId, + false, + BigDecimal(2222), + listOf( + PurchaseInfo("sku1", "iso1", BigDecimal(1000)), + PurchaseInfo("sku2", "iso2", BigDecimal(1222)), + ), ), - ), - TrackSessionEndOperation(appId, remoteOneSignalId, 3333), - ) + TrackSessionEndOperation(appId, remoteOneSignalId, 3333), + ) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockUserBackendService.updateUser( @@ -224,31 +231,33 @@ class UpdateUserOperationExecutorTests : FunSpec({ } test("update user with both property and property delta operations are successful") { - /* Given */ + // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.updateUser(any(), any(), any(), any(), any(), any()) } just runs - /* Given */ + // Given val mockIdentityModelStore = MockHelper.identityModelStore() val mockPropertiesModelStore = MockHelper.propertiesModelStore() val mockBuildUserService = mockk() - val loginUserOperationExecutor = UpdateUserOperationExecutor( - mockUserBackendService, - mockIdentityModelStore, - mockPropertiesModelStore, - mockBuildUserService, - ) - val operations = listOf( - TrackSessionEndOperation(appId, remoteOneSignalId, 1111), - SetTagOperation(appId, remoteOneSignalId, "tagKey1", "tagValue1"), - TrackSessionEndOperation(appId, remoteOneSignalId, 3333), - ) + val loginUserOperationExecutor = + UpdateUserOperationExecutor( + mockUserBackendService, + mockIdentityModelStore, + mockPropertiesModelStore, + mockBuildUserService, + ) + val operations = + listOf( + TrackSessionEndOperation(appId, remoteOneSignalId, 1111), + SetTagOperation(appId, remoteOneSignalId, "tagKey1", "tagValue1"), + TrackSessionEndOperation(appId, remoteOneSignalId, 3333), + ) - /* When */ + // When val response = loginUserOperationExecutor.execute(operations) - /* Then */ + // Then response.result shouldBe ExecutionResult.SUCCESS coVerify(exactly = 1) { mockUserBackendService.updateUser( diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/subscriptions/SubscriptionManagerTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/subscriptions/SubscriptionManagerTests.kt index 7eb8a73e6d..897c3ee4ea 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/subscriptions/SubscriptionManagerTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/subscriptions/SubscriptionManagerTests.kt @@ -22,7 +22,7 @@ import org.junit.runner.RunWith class SubscriptionManagerTests : FunSpec({ test("initializes subscriptions from model store") { - /* Given */ + // Given val mockSubscriptionModelStore = mockk() val pushSubscription = SubscriptionModel() pushSubscription.id = "subscription1" @@ -51,10 +51,10 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) - /* When */ + // When val subscriptions = subscriptionManager.subscriptions - /* Then */ + // Then subscriptions.collection.count() shouldBe 3 subscriptions.push shouldNotBe null subscriptions.push!!.id shouldBe pushSubscription.id @@ -69,7 +69,7 @@ class SubscriptionManagerTests : FunSpec({ } test("add email subscription adds to model store") { - /* Given */ + // Given val mockSubscriptionModelStore = mockk() val listOfSubscriptions = listOf() @@ -79,10 +79,10 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) - /* When */ + // When subscriptionManager.addEmailSubscription("name@company.com") - /* Then */ + // Then verify { mockSubscriptionModelStore.add( withArg { @@ -96,7 +96,7 @@ class SubscriptionManagerTests : FunSpec({ } test("add sms subscription adds to model store") { - /* Given */ + // Given val mockSubscriptionModelStore = mockk() val listOfSubscriptions = listOf() @@ -106,10 +106,10 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) - /* When */ + // When subscriptionManager.addSmsSubscription("+15558675309") - /* Then */ + // Then verify { mockSubscriptionModelStore.add( withArg { @@ -123,7 +123,7 @@ class SubscriptionManagerTests : FunSpec({ } test("add push subscription adds to model store") { - /* Given */ + // Given val mockSubscriptionModelStore = mockk() val listOfSubscriptions = listOf() @@ -133,10 +133,10 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) - /* When */ + // When subscriptionManager.addOrUpdatePushSubscription("pushToken", SubscriptionStatus.SUBSCRIBED) - /* Then */ + // Then verify { mockSubscriptionModelStore.add( withArg { @@ -150,7 +150,7 @@ class SubscriptionManagerTests : FunSpec({ } test("update push subscription updates model store") { - /* Given */ + // Given val mockSubscriptionModelStore = mockk() val pushSubscription = SubscriptionModel() @@ -169,16 +169,16 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) - /* When */ + // When subscriptionManager.addOrUpdatePushSubscription("pushToken2", SubscriptionStatus.FIREBASE_FCM_ERROR_IOEXCEPTION_OTHER) - /* Then */ + // Then pushSubscription.address shouldBe "pushToken2" pushSubscription.status shouldBe SubscriptionStatus.FIREBASE_FCM_ERROR_IOEXCEPTION_OTHER } test("remove email subscription removes from model store") { - /* Given */ + // Given val mockSubscriptionModelStore = mockk() val emailSubscription = SubscriptionModel() @@ -197,15 +197,15 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) - /* When */ + // When subscriptionManager.removeEmailSubscription("name@company.com") - /* Then */ + // Then verify(exactly = 1) { mockSubscriptionModelStore.remove("subscription1") } } test("remove sms subscription removes from model store") { - /* Given */ + // Given val mockSubscriptionModelStore = mockk() val emailSubscription = SubscriptionModel() @@ -224,15 +224,15 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) - /* When */ + // When subscriptionManager.removeSmsSubscription("+18458675309") - /* Then */ + // Then verify(exactly = 1) { mockSubscriptionModelStore.remove("subscription1") } } test("subscription added when model added") { - /* Given */ + // Given val smsSubscription = SubscriptionModel() smsSubscription.id = "subscription1" smsSubscription.type = SubscriptionType.SMS @@ -251,11 +251,11 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) subscriptionManager.subscribe(spySubscriptionChangedHandler) - /* When */ + // When subscriptionManager.onModelAdded(smsSubscription, ModelChangeTags.NORMAL) val subscriptions = subscriptionManager.subscriptions - /* Then */ + // Then subscriptions.smss.count() shouldBe 1 subscriptions.smss[0].id shouldBe smsSubscription.id subscriptions.smss[0].number shouldBe smsSubscription.address @@ -271,7 +271,7 @@ class SubscriptionManagerTests : FunSpec({ } test("subscription modified when model updated") { - /* Given */ + // Given val emailSubscription = SubscriptionModel() emailSubscription.id = "subscription1" emailSubscription.type = SubscriptionType.SMS @@ -290,12 +290,21 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) subscriptionManager.subscribe(spySubscriptionChangedHandler) - /* When */ + // When emailSubscription.address = "+15551234567" - subscriptionManager.onModelUpdated(ModelChangedArgs(emailSubscription, SubscriptionModel::address.name, SubscriptionModel::address.name, "+15558675309", "+15551234567"), ModelChangeTags.NORMAL) + subscriptionManager.onModelUpdated( + ModelChangedArgs( + emailSubscription, + SubscriptionModel::address.name, + SubscriptionModel::address.name, + "+15558675309", + "+15551234567", + ), + ModelChangeTags.NORMAL, + ) val subscriptions = subscriptionManager.subscriptions - /* Then */ + // Then subscriptions.smss.count() shouldBe 1 subscriptions.smss[0].id shouldBe emailSubscription.id subscriptions.smss[0].number shouldBe "+15551234567" @@ -303,7 +312,7 @@ class SubscriptionManagerTests : FunSpec({ } test("subscription removed when model removed") { - /* Given */ + // Given val smsSubscription = SubscriptionModel() smsSubscription.id = "subscription1" smsSubscription.type = SubscriptionType.SMS @@ -322,11 +331,11 @@ class SubscriptionManagerTests : FunSpec({ val subscriptionManager = SubscriptionManager(mockSubscriptionModelStore) subscriptionManager.subscribe(spySubscriptionChangedHandler) - /* When */ + // When subscriptionManager.onModelRemoved(smsSubscription, ModelChangeTags.NORMAL) val subscriptions = subscriptionManager.subscriptions - /* Then */ + // Then subscriptions.smss.count() shouldBe 0 verify(exactly = 1) { spySubscriptionChangedHandler.onSubscriptionRemoved( diff --git a/OneSignalSDK/onesignal/in-app-messages/build.gradle b/OneSignalSDK/onesignal/in-app-messages/build.gradle index 8e60ebf38a..ced85d59d3 100644 --- a/OneSignalSDK/onesignal/in-app-messages/build.gradle +++ b/OneSignalSDK/onesignal/in-app-messages/build.gradle @@ -93,6 +93,9 @@ dependencies { ktlint { version = "$ktlintVersion" + additionalEditorconfig = [ + "max_line_length": "500", + ] } apply from: '../maven-push.gradle' \ No newline at end of file diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/DummyInAppMessagesManager.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/DummyInAppMessagesManager.kt index e08386d0d5..e8f4b930c1 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/DummyInAppMessagesManager.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/DummyInAppMessagesManager.kt @@ -6,7 +6,11 @@ import com.onesignal.inAppMessages.IInAppMessagesManager internal class DummyInAppMessagesManager : IInAppMessagesManager { override var paused: Boolean = true - override fun addTrigger(key: String, value: String) { + + override fun addTrigger( + key: String, + value: String, + ) { } override fun addTriggers(triggers: Map) { diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessage.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessage.kt index 07c8c0198f..36d85fcdf1 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessage.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessage.kt @@ -106,11 +106,12 @@ internal class InAppMessage( private fun parseEndTimeJson(json: JSONObject): Date? { val endTimeString: String - endTimeString = try { - json.getString(END_TIME) - } catch (e: JSONException) { - return null - } + endTimeString = + try { + json.getString(END_TIME) + } catch (e: JSONException) { + return null + } if (endTimeString == "null") return null try { val format = DateUtils.iso8601Format() diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageClickResult.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageClickResult.kt index 682af74e28..69e3d6b212 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageClickResult.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageClickResult.kt @@ -87,7 +87,10 @@ internal class InAppMessageClickResult(json: JSONObject, promptFactory: IInAppMe } @Throws(JSONException::class) - private fun parsePrompts(json: JSONObject, promptFactory: IInAppMessagePromptFactory) { + private fun parsePrompts( + json: JSONObject, + promptFactory: IInAppMessagePromptFactory, + ) { val promptsJsonArray = json.getJSONArray(PROMPTS) for (i in 0 until promptsJsonArray.length()) { val promptType = promptsJsonArray.getString(i) @@ -111,8 +114,9 @@ internal class InAppMessageClickResult(json: JSONObject, promptFactory: IInAppMe if (tags != null) { mainObj.put(TAGS, tags!!.toJSONObject()) } - if (urlTarget != null) - mainObj.put("url_target", urlTarget.toString()); + if (urlTarget != null) { + mainObj.put("url_target", urlTarget.toString()) + } } catch (e: JSONException) { e.printStackTrace() } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageRedisplayStats.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageRedisplayStats.kt index f46388a4ac..96a586ce38 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageRedisplayStats.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageRedisplayStats.kt @@ -64,7 +64,9 @@ internal class InAppMessageRedisplayStats( val currentTimeInSeconds = _time.currentTimeMillis / 1000 // Calculate gap between display times val diffInSeconds = currentTimeInSeconds - lastDisplayTime - Logging.debug("OSInAppMessage lastDisplayTime: $lastDisplayTime currentTimeInSeconds: $currentTimeInSeconds diffInSeconds: $diffInSeconds displayDelay: $displayDelay") + Logging.debug( + "OSInAppMessage lastDisplayTime: $lastDisplayTime currentTimeInSeconds: $currentTimeInSeconds diffInSeconds: $diffInSeconds displayDelay: $displayDelay", + ) return diffInSeconds >= displayDelay } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageTag.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageTag.kt index 67479ea6a0..21a45e8094 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageTag.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessageTag.kt @@ -7,6 +7,7 @@ import org.json.JSONObject internal class InAppMessageTag(json: JSONObject) { var tagsToAdd: JSONObject? var tagsToRemove: JSONArray? + fun toJSONObject(): JSONObject { val mainObj = JSONObject() try { diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt index 801af856a6..df598f273d 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt @@ -72,38 +72,37 @@ internal class InAppMessagesManager( IInAppLifecycleEventHandler, ITriggerHandler, ISessionLifecycleHandler { - - private val _lifecycleCallback = EventProducer() - private val _messageClickCallback = EventProducer() + private val lifecycleCallback = EventProducer() + private val messageClickCallback = EventProducer() // IAMs loaded remotely from on_session // If on_session won't be called this will be loaded from cache - private var _messages: List = listOf() + private var messages: List = listOf() // IAMs that have been dismissed by the user // This mean they have already displayed to the user - private val _dismissedMessages: MutableSet = mutableSetOf() + private val dismissedMessages: MutableSet = mutableSetOf() // IAMs that have been displayed to the user // This means their impression has been successfully posted to our backend and should not be counted again - private val _impressionedMessages: MutableSet = mutableSetOf() + private val impressionedMessages: MutableSet = mutableSetOf() // This means their impression has been successfully posted to our backend and should not be counted again - private val _viewedPageIds: MutableSet = mutableSetOf() + private val viewedPageIds: MutableSet = mutableSetOf() // IAM clicks that have been successfully posted to our backend and should not be counted again - private val _clickedClickIds: MutableSet = mutableSetOf() + private val clickedClickIds: MutableSet = mutableSetOf() // Ordered IAMs queued to display, includes the message currently displaying, if any. - private val _messageDisplayQueue: MutableList = mutableListOf() - private val _messageDisplayQueueMutex = Mutex() + private val messageDisplayQueue: MutableList = mutableListOf() + private val messageDisplayQueueMutex = Mutex() // IAMs displayed with last displayed time and quantity of displays data // This is retrieved from a DB Table that take care of each object to be unique - private val _redisplayedInAppMessages: MutableList = mutableListOf() + private val redisplayedInAppMessages: MutableList = mutableListOf() - private val _fetchIAMMutex = Mutex() - private var _lastTimeFetchedIAMs: Long? = null + private val fetchIAMMutex = Mutex() + private var lastTimeFetchedIAMs: Long? = null override var paused: Boolean get() = _state.paused @@ -120,8 +119,9 @@ internal class InAppMessagesManager( override fun start() { val tempDismissedSet = _prefs.dismissedMessagesId - if (tempDismissedSet != null) - _dismissedMessages.addAll(tempDismissedSet) + if (tempDismissedSet != null) { + dismissedMessages.addAll(tempDismissedSet) + } val tempLastTimeInAppDismissed = _prefs.lastTimeInAppDismissed if (tempLastTimeInAppDismissed != null) { @@ -138,10 +138,10 @@ internal class InAppMessagesManager( _repository.cleanCachedInAppMessages() // get saved IAMs from database - _redisplayedInAppMessages.addAll(_repository.listInAppMessages()) + redisplayedInAppMessages.addAll(_repository.listInAppMessages()) // reset all messages for redisplay to indicate not shown - for (redisplayInAppMessage in _redisplayedInAppMessages) { + for (redisplayInAppMessage in redisplayedInAppMessages) { redisplayInAppMessage.isDisplayedInSession = false } @@ -152,25 +152,28 @@ internal class InAppMessagesManager( override fun addLifecycleListener(listener: IInAppMessageLifecycleListener) { Logging.debug("InAppMessagesManager.addLifecycleListener(listener: $listener)") - _lifecycleCallback.subscribe(listener) + lifecycleCallback.subscribe(listener) } override fun removeLifecycleListener(listener: IInAppMessageLifecycleListener) { Logging.debug("InAppMessagesManager.removeLifecycleListener(listener: $listener)") - _lifecycleCallback.unsubscribe(listener) + lifecycleCallback.unsubscribe(listener) } override fun addClickListener(listener: IInAppMessageClickListener) { Logging.debug("InAppMessagesManager.addClickListener(listener: $listener)") - _messageClickCallback.subscribe(listener) + messageClickCallback.subscribe(listener) } override fun removeClickListener(listener: IInAppMessageClickListener) { Logging.debug("InAppMessagesManager.removeClickListener(listener: $listener)") - _messageClickCallback.unsubscribe(listener) + messageClickCallback.unsubscribe(listener) } - override fun onModelUpdated(args: ModelChangedArgs, tag: String) { + override fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) { if (args.property != ConfigModel::appId.name) { return } @@ -180,15 +183,23 @@ internal class InAppMessagesManager( } } - override fun onModelReplaced(model: ConfigModel, tag: String) { + override fun onModelReplaced( + model: ConfigModel, + tag: String, + ) { suspendifyOnThread { fetchMessages() } } override fun onSubscriptionAdded(subscription: ISubscription) { } + override fun onSubscriptionRemoved(subscription: ISubscription) { } - override fun onSubscriptionChanged(subscription: ISubscription, args: ModelChangedArgs) { + + override fun onSubscriptionChanged( + subscription: ISubscription, + args: ModelChangedArgs, + ) { if (subscription !is IPushSubscription || args.path != SubscriptionModel::id.name) { return } @@ -199,7 +210,7 @@ internal class InAppMessagesManager( } override fun onSessionStarted() { - for (redisplayInAppMessage in _redisplayedInAppMessages) { + for (redisplayInAppMessage in redisplayedInAppMessages) { redisplayInAppMessage.isDisplayedInSession = false } @@ -209,6 +220,7 @@ internal class InAppMessagesManager( } override fun onSessionActive() { } + override fun onSessionEnded(duration: Long) { } // called when a new push subscription is added, or the app id is updated, or a new session starts @@ -220,19 +232,19 @@ internal class InAppMessagesManager( return } - _fetchIAMMutex.withLock { + fetchIAMMutex.withLock { val now = _time.currentTimeMillis - if (_lastTimeFetchedIAMs != null && (now - _lastTimeFetchedIAMs!!) < _configModelStore.model.fetchIAMMinInterval) { + if (lastTimeFetchedIAMs != null && (now - lastTimeFetchedIAMs!!) < _configModelStore.model.fetchIAMMinInterval) { return } - _lastTimeFetchedIAMs = now + lastTimeFetchedIAMs = now } val newMessages = _backend.listInAppMessages(appId, subscriptionId) if (newMessages != null) { - this._messages = newMessages + this.messages = newMessages evaluateInAppMessages() } } @@ -243,11 +255,11 @@ internal class InAppMessagesManager( private suspend fun evaluateInAppMessages() { Logging.debug("InAppMessagesManager.evaluateInAppMessages()") - for (message in _messages) { + for (message in messages) { // Make trigger evaluation first, dynamic trigger might change "trigger changed" flag value for redisplay messages if (_triggerController.evaluateMessageTriggers(message)) { setDataForRedisplay(message) - if (!_dismissedMessages.contains(message.messageId) && !message.isFinished) { + if (!dismissedMessages.contains(message.messageId) && !message.isFinished) { queueMessageForDisplay(message) } } @@ -269,10 +281,10 @@ internal class InAppMessagesManager( * For click counting, every message has it click id array */ private fun setDataForRedisplay(message: InAppMessage) { - val messageDismissed: Boolean = _dismissedMessages.contains(message.messageId) - val index: Int = _redisplayedInAppMessages.indexOf(message) + val messageDismissed: Boolean = dismissedMessages.contains(message.messageId) + val index: Int = redisplayedInAppMessages.indexOf(message) if (messageDismissed && index != -1) { - val savedIAM: InAppMessage = _redisplayedInAppMessages.get(index) + val savedIAM: InAppMessage = redisplayedInAppMessages.get(index) message.redisplayStats.setDisplayStats(savedIAM.redisplayStats) message.isDisplayedInSession = savedIAM.isDisplayedInSession @@ -285,12 +297,12 @@ internal class InAppMessagesManager( message.redisplayStats.shouldDisplayAgain() ) { Logging.debug("InAppMessagesManager.setDataForRedisplay message available for redisplay: " + message.messageId) - _dismissedMessages.remove(message.messageId) - _impressionedMessages.remove(message.messageId) + dismissedMessages.remove(message.messageId) + impressionedMessages.remove(message.messageId) // Pages from different IAMs should not impact each other so we can clear the entire // list when an IAM is dismissed or we are re-displaying the same one - _viewedPageIds.clear() - _prefs.viewPageImpressionedIds = _viewedPageIds + viewedPageIds.clear() + _prefs.viewPageImpressionedIds = viewedPageIds message.clearClickIds() } } @@ -312,11 +324,13 @@ internal class InAppMessagesManager( * Display message now or add it to the queue to be displayed. */ private suspend fun queueMessageForDisplay(message: InAppMessage) { - _messageDisplayQueueMutex.withLock { + messageDisplayQueueMutex.withLock { // Make sure no message is ever added to the queue more than once - if (!_messageDisplayQueue.contains(message) && _state.inAppMessageIdShowing != message.messageId) { - _messageDisplayQueue.add(message) - Logging.debug("InAppMessagesManager.queueMessageForDisplay: In app message with id: " + message.messageId + ", added to the queue") + if (!messageDisplayQueue.contains(message) && _state.inAppMessageIdShowing != message.messageId) { + messageDisplayQueue.add(message) + Logging.debug( + "InAppMessagesManager.queueMessageForDisplay: In app message with id: " + message.messageId + ", added to the queue", + ) } } @@ -332,18 +346,20 @@ internal class InAppMessagesManager( var messageToDisplay: InAppMessage? = null - _messageDisplayQueueMutex.withLock { - Logging.debug("InAppMessagesManager.attemptToShowInAppMessage: $_messageDisplayQueue") + messageDisplayQueueMutex.withLock { + Logging.debug("InAppMessagesManager.attemptToShowInAppMessage: $messageDisplayQueue") // If there are IAMs in the queue and nothing showing, show first in the queue if (paused) { - Logging.warn("InAppMessagesManager.attemptToShowInAppMessage: In app messaging is currently paused, in app messages will not be shown!") - } else if (_messageDisplayQueue.isEmpty()) { + Logging.warn( + "InAppMessagesManager.attemptToShowInAppMessage: In app messaging is currently paused, in app messages will not be shown!", + ) + } else if (messageDisplayQueue.isEmpty()) { Logging.debug("InAppMessagesManager.attemptToShowInAppMessage: There are no IAMs left in the queue!") } else if (_state.inAppMessageIdShowing != null) { Logging.debug("InAppMessagesManager.attemptToShowInAppMessage: There is an IAM currently showing!") } else { Logging.debug("InAppMessagesManager.attemptToShowInAppMessage: No IAM showing currently, showing first item in the queue!") - messageToDisplay = _messageDisplayQueue.removeAt(0) + messageToDisplay = messageDisplayQueue.removeAt(0) // set the state while the mutex is held so the next one coming in will pick up // the correct state. @@ -371,13 +387,16 @@ internal class InAppMessagesManager( /** * Called after an In-App message is closed and it's dismiss animation has completed */ - private suspend fun messageWasDismissed(message: InAppMessage, failed: Boolean = false) { + private suspend fun messageWasDismissed( + message: InAppMessage, + failed: Boolean = false, + ) { if (!message.isPreview) { - _dismissedMessages.add(message.messageId) + dismissedMessages.add(message.messageId) // If failed we will retry on next session if (!failed) { - _prefs.dismissedMessagesId = _dismissedMessages + _prefs.dismissedMessagesId = dismissedMessages // Don't keep track of last displayed time for a preview _state.lastTimeInAppDismissed = _time.currentTimeMillis @@ -385,26 +404,28 @@ internal class InAppMessagesManager( persistInAppMessage(message) } - Logging.debug("InAppMessagesManager.messageWasDismissed: dismissedMessages: $_dismissedMessages") + Logging.debug("InAppMessagesManager.messageWasDismissed: dismissedMessages: $dismissedMessages") } // Remove DIRECT influence due to ClickHandler of ClickAction outcomes _influenceManager.onInAppMessageDismissed() if (_state.currentPrompt != null) { - Logging.debug("InAppMessagesManager.messageWasDismissed: Stop evaluateMessageDisplayQueue because prompt is currently displayed") + Logging.debug( + "InAppMessagesManager.messageWasDismissed: Stop evaluateMessageDisplayQueue because prompt is currently displayed", + ) return } // fire the external callback - if (_lifecycleCallback.hasSubscribers) { - _lifecycleCallback.fireOnMain { it.onDidDismiss(InAppMessageLifecycleEvent(message)) } + if (lifecycleCallback.hasSubscribers) { + lifecycleCallback.fireOnMain { it.onDidDismiss(InAppMessageLifecycleEvent(message)) } } _state.inAppMessageIdShowing = null // Display the next message in the queue, or attempt to add more IAMs to the queue - if (_messageDisplayQueue.isNotEmpty()) { + if (messageDisplayQueue.isNotEmpty()) { Logging.debug("InAppMessagesManager.messageWasDismissed: In app message on queue available, attempting to show") attemptToShowInAppMessage() } else { @@ -422,8 +443,8 @@ internal class InAppMessagesManager( * - At least one Trigger has changed */ private fun makeRedisplayMessagesAvailableWithTriggers(newTriggersKeys: Collection) { - for (message in _messages) { - if (!message.isTriggerChanged && _redisplayedInAppMessages.contains(message) && + for (message in messages) { + if (!message.isTriggerChanged && redisplayedInAppMessages.contains(message) && _triggerController.isTriggerOnMessage(message, newTriggersKeys) ) { Logging.debug("InAppMessagesManager.makeRedisplayMessagesAvailableWithTriggers: Trigger changed for message: $message") @@ -444,14 +465,14 @@ internal class InAppMessagesManager( // Update the data to enable future re displays // Avoid calling the repository data again - val index = _redisplayedInAppMessages.indexOf(message) + val index = redisplayedInAppMessages.indexOf(message) if (index != -1) { - _redisplayedInAppMessages.set(index, message) + redisplayedInAppMessages.set(index, message) } else { - _redisplayedInAppMessages.add(message) + redisplayedInAppMessages.add(message) } - Logging.debug("InAppMessagesManager.persistInAppMessage: $message with msg array data: $_redisplayedInAppMessages") + Logging.debug("InAppMessagesManager.persistInAppMessage: $message with msg array data: $redisplayedInAppMessages") } override fun addTriggers(triggers: Map) { @@ -460,7 +481,10 @@ internal class InAppMessagesManager( triggers.forEach { addTrigger(it.key, it.value) } } - override fun addTrigger(key: String, value: String) { + override fun addTrigger( + key: String, + value: String, + ) { Logging.debug("InAppMessagesManager.addTrigger(key: $key, value: $value)") var triggerModel = _triggerModelStore.get(key) @@ -494,29 +518,29 @@ internal class InAppMessagesManager( // IAM LIFECYCLE CALLBACKS override fun onMessageWillDisplay(message: InAppMessage) { - if (!_lifecycleCallback.hasSubscribers) { + if (!lifecycleCallback.hasSubscribers) { Logging.verbose("InAppMessagesManager.onMessageWillDisplay: inAppMessageLifecycleHandler is null") return } - _lifecycleCallback.fireOnMain { it.onWillDisplay(InAppMessageLifecycleEvent(message)) } + lifecycleCallback.fireOnMain { it.onWillDisplay(InAppMessageLifecycleEvent(message)) } } override fun onMessageWasDisplayed(message: InAppMessage) { - if (!_lifecycleCallback.hasSubscribers) { + if (!lifecycleCallback.hasSubscribers) { Logging.verbose("InAppMessagesManager.onMessageWasDisplayed: inAppMessageLifecycleHandler is null") return } - _lifecycleCallback.fireOnMain { it.onDidDisplay(InAppMessageLifecycleEvent(message)) } + lifecycleCallback.fireOnMain { it.onDidDisplay(InAppMessageLifecycleEvent(message)) } if (message.isPreview) { return } // Check that the messageId is in impressioned messages so we return early without a second post being made - if (_impressionedMessages.contains(message.messageId)) return + if (impressionedMessages.contains(message.messageId)) return // Add the messageId to impressioned messages so no second request is made - _impressionedMessages.add(message.messageId) + impressionedMessages.add(message.messageId) val variantId = InAppHelper.variantIdForMessage(message, _languageContext) ?: return @@ -529,15 +553,18 @@ internal class InAppMessagesManager( message.messageId, ) - _prefs.impressionesMessagesId = _impressionedMessages + _prefs.impressionesMessagesId = impressionedMessages } catch (ex: BackendException) { // Post failed, impressioned messages should be removed and this way another post can be attempted - _impressionedMessages.remove(message.messageId) + impressionedMessages.remove(message.messageId) } } } - override fun onMessageActionOccurredOnPreview(message: InAppMessage, action: InAppMessageClickResult) { + override fun onMessageActionOccurredOnPreview( + message: InAppMessage, + action: InAppMessageClickResult, + ) { suspendifyOnThread { action.isFirstClick = message.takeActionAsUnique() @@ -548,7 +575,10 @@ internal class InAppMessagesManager( } } - override fun onMessageActionOccurredOnMessage(message: InAppMessage, action: InAppMessageClickResult) { + override fun onMessageActionOccurredOnMessage( + message: InAppMessage, + action: InAppMessageClickResult, + ) { suspendifyOnThread { action.isFirstClick = message.takeActionAsUnique() firePublicClickHandler(message, action) @@ -560,7 +590,10 @@ internal class InAppMessagesManager( } } - override fun onMessagePageChanged(message: InAppMessage, page: InAppMessagePage) { + override fun onMessagePageChanged( + message: InAppMessage, + page: InAppMessagePage, + ) { if (message.isPreview) { return } @@ -571,11 +604,11 @@ internal class InAppMessagesManager( } override fun onMessageWillDismiss(message: InAppMessage) { - if (!_lifecycleCallback.hasSubscribers) { + if (!lifecycleCallback.hasSubscribers) { Logging.verbose("InAppMessagesManager.onMessageWillDismiss: inAppMessageLifecycleHandler is null") return } - _lifecycleCallback.fireOnMain { it.onWillDismiss(InAppMessageLifecycleEvent(message)) } + lifecycleCallback.fireOnMain { it.onWillDismiss(InAppMessageLifecycleEvent(message)) } } override fun onMessageWasDismissed(message: InAppMessage) { @@ -586,6 +619,7 @@ internal class InAppMessagesManager( // END IAM LIFECYCLE CALLBACKS // TRIGGER FIRED CALLBACKS + /** * Part of redisplay logic * @@ -632,7 +666,10 @@ internal class InAppMessagesManager( // END TRIGGER FIRED CALLBACKS - private suspend fun beginProcessingPrompts(message: InAppMessage, prompts: List) { + private suspend fun beginProcessingPrompts( + message: InAppMessage, + prompts: List, + ) { if (prompts.isNotEmpty()) { Logging.debug("InAppMessagesManager.beginProcessingPrompts: IAM showing prompts from IAM: $message") @@ -642,7 +679,10 @@ internal class InAppMessagesManager( } } - private suspend fun fireOutcomesForClick(messageId: String, outcomes: List) { + private suspend fun fireOutcomesForClick( + messageId: String, + outcomes: List, + ) { _influenceManager.onDirectInfluenceFromIAM(messageId) for (outcome in outcomes) { @@ -672,7 +712,10 @@ internal class InAppMessagesManager( } } - private suspend fun showMultiplePrompts(inAppMessage: InAppMessage, prompts: List) { + private suspend fun showMultiplePrompts( + inAppMessage: InAppMessage, + prompts: List, + ) { for (prompt in prompts) { // Don't show prompt twice if (!prompt.hasPrompted()) { @@ -708,21 +751,28 @@ internal class InAppMessagesManager( } } - /* End IAM Lifecycle methods */ + // End IAM Lifecycle methods private fun logInAppMessagePreviewActions(action: InAppMessageClickResult) { if (action.tags != null) { - Logging.debug("InAppMessagesManager.logInAppMessagePreviewActions: Tags detected inside of the action click payload, ignoring because action came from IAM preview:: " + action.tags.toString()) + Logging.debug( + "InAppMessagesManager.logInAppMessagePreviewActions: Tags detected inside of the action click payload, ignoring because action came from IAM preview:: " + action.tags.toString(), + ) } if (action.outcomes.size > 0) { - Logging.debug("InAppMessagesManager.logInAppMessagePreviewActions: Outcomes detected inside of the action click payload, ignoring because action came from IAM preview: " + action.outcomes.toString()) + Logging.debug( + "InAppMessagesManager.logInAppMessagePreviewActions: Outcomes detected inside of the action click payload, ignoring because action came from IAM preview: " + action.outcomes.toString(), + ) } // TODO: Add more action payload preview logs here in future } - private suspend fun firePublicClickHandler(message: InAppMessage, action: InAppMessageClickResult) { - if (!_messageClickCallback.hasSubscribers) { + private suspend fun firePublicClickHandler( + message: InAppMessage, + action: InAppMessageClickResult, + ) { + if (!messageClickCallback.hasSubscribers) { return } @@ -731,20 +781,23 @@ internal class InAppMessagesManager( // Any outcome sent on this callback should count as DIRECT from this IAM _influenceManager.onDirectInfluenceFromIAM(message.messageId) val result = InAppMessageClickEvent(message, action) - _messageClickCallback.suspendingFireOnMain { it.onClick(result) } + messageClickCallback.suspendingFireOnMain { it.onClick(result) } } - private suspend fun fireRESTCallForPageChange(message: InAppMessage, page: InAppMessagePage) { + private suspend fun fireRESTCallForPageChange( + message: InAppMessage, + page: InAppMessagePage, + ) { val variantId = InAppHelper.variantIdForMessage(message, _languageContext) ?: return val pageId = page.pageId val messagePrefixedPageId = message.messageId + pageId // Never send multiple page impressions for the same message UUID unless that page change is from an IAM with redisplay - if (_viewedPageIds.contains(messagePrefixedPageId)) { + if (viewedPageIds.contains(messagePrefixedPageId)) { Logging.verbose("InAppMessagesManager: Already sent page impression for id: $pageId") return } - _viewedPageIds.add(messagePrefixedPageId) + viewedPageIds.add(messagePrefixedPageId) try { _backend.sendIAMPageImpression( @@ -755,14 +808,17 @@ internal class InAppMessagesManager( pageId, ) - _prefs.viewPageImpressionedIds = _viewedPageIds + _prefs.viewPageImpressionedIds = viewedPageIds } catch (ex: BackendException) { // Post failed, viewed page should be removed and this way another post can be attempted - _viewedPageIds.remove(messagePrefixedPageId) + viewedPageIds.remove(messagePrefixedPageId) } } - private suspend fun fireRESTCallForClick(message: InAppMessage, action: InAppMessageClickResult) { + private suspend fun fireRESTCallForClick( + message: InAppMessage, + action: InAppMessageClickResult, + ) { val variantId = InAppHelper.variantIdForMessage(message, _languageContext) ?: return val clickId = action.clickId @@ -770,12 +826,12 @@ internal class InAppMessagesManager( val clickAvailableByRedisplay = message.redisplayStats.isRedisplayEnabled && clickId != null && message.isClickAvailable(clickId) // Never count multiple clicks for the same click UUID unless that click is from an IAM with redisplay - if (!clickAvailableByRedisplay && _clickedClickIds.contains(clickId)) { + if (!clickAvailableByRedisplay && clickedClickIds.contains(clickId)) { return } if (clickId != null) { - _clickedClickIds.add(clickId) + clickedClickIds.add(clickId) // Track clickId per IAM message.addClickId(clickId) } @@ -791,9 +847,9 @@ internal class InAppMessagesManager( ) // Persist success click to disk. Id already added to set before making the network call - _prefs.clickedMessagesId = _clickedClickIds + _prefs.clickedMessagesId = clickedClickIds } catch (ex: BackendException) { - _clickedClickIds.remove(clickId) + clickedClickIds.remove(clickId) if (clickId != null) { message.removeClickId(clickId) @@ -801,7 +857,10 @@ internal class InAppMessagesManager( } } - private fun showAlertDialogMessage(inAppMessage: InAppMessage, prompts: List) { + private fun showAlertDialogMessage( + inAppMessage: InAppMessage, + prompts: List, + ) { val messageTitle = _applicationService.appContext.getString(R.string.location_permission_missing_title) val message = _applicationService.appContext.getString(R.string.location_permission_missing_message) AlertDialog.Builder(_applicationService.current) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/backend/IInAppBackendService.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/backend/IInAppBackendService.kt index 0bb4d31879..adafdce86f 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/backend/IInAppBackendService.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/backend/IInAppBackendService.kt @@ -8,7 +8,6 @@ import com.onesignal.inAppMessages.internal.InAppMessageContent * This backend service provides access to the In App Message endpoints */ internal interface IInAppBackendService { - /** * List the in app messages for a specific [appId]/[subscriptionId]. * @@ -17,7 +16,10 @@ internal interface IInAppBackendService { * * @return The list of IAMs associated to the subscription, or null if the IAMs could not be retrieved. */ - suspend fun listInAppMessages(appId: String, subscriptionId: String): List? + suspend fun listInAppMessages( + appId: String, + subscriptionId: String, + ): List? /** * Retrieve the data for a specific In App Message. @@ -27,7 +29,11 @@ internal interface IInAppBackendService { * @param variantId The optional ID of the variant that should be retrieved. If not specified, * the default variant will be used. */ - suspend fun getIAMData(appId: String, messageId: String, variantId: String?): GetIAMDataResponse + suspend fun getIAMData( + appId: String, + messageId: String, + variantId: String?, + ): GetIAMDataResponse /** * Retrieve the preview data for a specific In App Message. @@ -35,7 +41,10 @@ internal interface IInAppBackendService { * @param appId The ID of the application that the IAM will be retrieved from. * @param previewUUID THe ID of the preview IAM that should be retrieved. */ - suspend fun getIAMPreviewData(appId: String, previewUUID: String): InAppMessageContent? + suspend fun getIAMPreviewData( + appId: String, + previewUUID: String, + ): InAppMessageContent? /** * Indicate an IAM was clicked on by the user. @@ -100,7 +109,6 @@ internal class GetIAMDataResponse( * The content, when the response is successful */ val content: InAppMessageContent?, - /** * Whether the call should be retried, when [content] is null */ diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/backend/impl/InAppBackendService.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/backend/impl/InAppBackendService.kt index 19ada10644..c9b28eaa80 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/backend/impl/InAppBackendService.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/backend/impl/InAppBackendService.kt @@ -19,7 +19,10 @@ internal class InAppBackendService( ) : IInAppBackendService { private var htmlNetworkRequestAttemptCount = 0 - override suspend fun listInAppMessages(appId: String, subscriptionId: String): List? { + override suspend fun listInAppMessages( + appId: String, + subscriptionId: String, + ): List? { // Retrieve any in app messages that might exist val response = _httpClient.get("apps/$appId/subscriptions/$subscriptionId/iams") @@ -39,9 +42,14 @@ internal class InAppBackendService( return null } - override suspend fun getIAMData(appId: String, messageId: String, variantId: String?): GetIAMDataResponse { - val htmlPath = htmlPathForMessage(messageId, variantId, appId) - ?: return GetIAMDataResponse(null, false) + override suspend fun getIAMData( + appId: String, + messageId: String, + variantId: String?, + ): GetIAMDataResponse { + val htmlPath = + htmlPathForMessage(messageId, variantId, appId) + ?: return GetIAMDataResponse(null, false) val response = _httpClient.get(htmlPath, null) @@ -54,7 +62,7 @@ internal class InAppBackendService( printHttpErrorForInAppMessageRequest("html", response.statusCode, response.payload) return if (NetworkUtils.getResponseStatusType(response.statusCode) != NetworkUtils.ResponseStatusType.RETRYABLE || - htmlNetworkRequestAttemptCount >= NetworkUtils.MAX_NETWORK_REQUEST_ATTEMPT_COUNT + htmlNetworkRequestAttemptCount >= NetworkUtils.maxNetworkRequestAttemptCount ) { // Failure limit reached, reset htmlNetworkRequestAttemptCount = 0 @@ -67,7 +75,10 @@ internal class InAppBackendService( } } - override suspend fun getIAMPreviewData(appId: String, previewUUID: String): InAppMessageContent? { + override suspend fun getIAMPreviewData( + appId: String, + previewUUID: String, + ): InAppMessageContent? { val htmlPath = "in_app_messages/device_preview?preview_id=$previewUUID&app_id=$appId" val response = _httpClient.get(htmlPath, null) @@ -89,16 +100,17 @@ internal class InAppBackendService( clickId: String?, isFirstClick: Boolean, ) { - val json: JSONObject = object : JSONObject() { - init { - put("app_id", appId) - put("device_type", _deviceService.deviceType.value) - put("player_id", subscriptionId) - put("click_id", clickId) - put("variant_id", variantId) - if (isFirstClick) put("first_click", true) + val json: JSONObject = + object : JSONObject() { + init { + put("app_id", appId) + put("device_type", _deviceService.deviceType.value) + put("player_id", subscriptionId) + put("click_id", clickId) + put("variant_id", variantId) + if (isFirstClick) put("first_click", true) + } } - } val response = _httpClient.post("in_app_messages/$messageId/click", json) @@ -122,15 +134,16 @@ internal class InAppBackendService( messageId: String, pageId: String?, ) { - val json: JSONObject = object : JSONObject() { - init { - put("app_id", appId) - put("player_id", subscriptionId) - put("variant_id", variantId) - put("device_type", _deviceService.deviceType.value) - put("page_id", pageId) + val json: JSONObject = + object : JSONObject() { + init { + put("app_id", appId) + put("player_id", subscriptionId) + put("variant_id", variantId) + put("device_type", _deviceService.deviceType.value) + put("page_id", pageId) + } } - } val response = _httpClient.post("in_app_messages/$messageId/pageImpression", json) @@ -148,15 +161,16 @@ internal class InAppBackendService( variantId: String?, messageId: String, ) { - val json: JSONObject = object : JSONObject() { - init { - put("app_id", appId) - put("player_id", subscriptionId) - put("variant_id", variantId) - put("device_type", _deviceService.deviceType.value) - put("first_impression", true) + val json: JSONObject = + object : JSONObject() { + init { + put("app_id", appId) + put("player_id", subscriptionId) + put("variant_id", variantId) + put("device_type", _deviceService.deviceType.value) + put("first_impression", true) + } } - } val response = _httpClient.post("in_app_messages/$messageId/impression", json) @@ -168,7 +182,11 @@ internal class InAppBackendService( } } - private fun htmlPathForMessage(messageId: String, variantId: String?, appId: String): String? { + private fun htmlPathForMessage( + messageId: String, + variantId: String?, + appId: String, + ): String? { if (variantId == null) { Logging.error("Unable to find a variant for in-app message $messageId") return null @@ -177,7 +195,10 @@ internal class InAppBackendService( return "in_app_messages/$messageId/variants/$variantId/html?app_id=$appId" } - private fun printHttpSuccessForInAppMessageRequest(requestType: String, response: String) { + private fun printHttpSuccessForInAppMessageRequest( + requestType: String, + response: String, + ) { Logging.debug("Successful post for in-app message $requestType request: $response") } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/common/InAppHelper.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/common/InAppHelper.kt index 5acf194678..b2a6378acc 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/common/InAppHelper.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/common/InAppHelper.kt @@ -6,7 +6,10 @@ import com.onesignal.inAppMessages.internal.InAppMessage internal object InAppHelper { private val PREFERRED_VARIANT_ORDER: List = listOf("android", "app", "all") - fun variantIdForMessage(message: InAppMessage, languageContext: ILanguageContext): String? { + fun variantIdForMessage( + message: InAppMessage, + languageContext: ILanguageContext, + ): String? { val language: String = languageContext.language for (variant in PREFERRED_VARIANT_ORDER) { if (!message.variants.containsKey(variant)) continue diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/common/OneSignalChromeTab.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/common/OneSignalChromeTab.kt index 528f4691db..c29476ce02 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/common/OneSignalChromeTab.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/common/OneSignalChromeTab.kt @@ -45,7 +45,11 @@ internal object OneSignalChromeTab { } } - internal fun open(url: String, openActivity: Boolean, context: Context): Boolean { + internal fun open( + url: String, + openActivity: Boolean, + context: Context, + ): Boolean { if (!hasChromeTabLibrary()) return false val connection: CustomTabsServiceConnection = OneSignalCustomTabsServiceConnection(url, openActivity, context) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/IInAppDisplayer.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/IInAppDisplayer.kt index 2c60ec8fad..b07de4c6fb 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/IInAppDisplayer.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/IInAppDisplayer.kt @@ -6,7 +6,6 @@ import com.onesignal.inAppMessages.internal.InAppMessage * Handles the displaying of an IAM on the device. */ internal interface IInAppDisplayer { - /** * Displays the provided IAM on the device * diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/DraggableRelativeLayout.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/DraggableRelativeLayout.kt index 989fbc3b21..9a3b33ef87 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/DraggableRelativeLayout.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/DraggableRelativeLayout.kt @@ -16,6 +16,7 @@ internal class DraggableRelativeLayout(context: Context?) : RelativeLayout(conte // Callbacks for knowing when dragging has started and ended fun onDragStart() + fun onDragEnd() } @@ -45,6 +46,7 @@ internal class DraggableRelativeLayout(context: Context?) : RelativeLayout(conte } private var params: Params? = null + fun setListener(listener: DraggableListener?) { mListener = listener } @@ -64,66 +66,83 @@ internal class DraggableRelativeLayout(context: Context?) : RelativeLayout(conte } private fun createDragHelper() { - mDragHelper = ViewDragHelper.create( - this, - 1.0f, - object : ViewDragHelper.Callback() { - private var lastYPos = 0 - override fun tryCaptureView(child: View, pointerId: Int): Boolean { - return true - } - - override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int { - if (params!!.draggingDisabled) { - return params!!.maxYPos + mDragHelper = + ViewDragHelper.create( + this, + 1.0f, + object : ViewDragHelper.Callback() { + private var lastYPos = 0 + + override fun tryCaptureView( + child: View, + pointerId: Int, + ): Boolean { + return true } - lastYPos = top - if (params!!.dragDirection == Params.DRAGGABLE_DIRECTION_DOWN) { - // Dragging down - // If the top of the message is past the dragThresholdY trigger the onDragStart() callback - if (top >= params!!.dragThresholdY && mListener != null) mListener!!.onDragStart() - if (top < params!!.maxYPos) return params!!.maxYPos - } else { - // Dragging up - // If the top of the message is past the dragThresholdY trigger the onDragStart() callback - if (top <= params!!.dragThresholdY && mListener != null) mListener!!.onDragStart() - if (top > params!!.maxYPos) return params!!.maxYPos - } - return top - } - - override fun clampViewPositionHorizontal(child: View, right: Int, dy: Int): Int { - return params!!.maxXPos - } - // Base on position and scroll speed decide if we need to dismiss - override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) { - var settleDestY = params!!.maxYPos - if (!dismissing) { + override fun clampViewPositionVertical( + child: View, + top: Int, + dy: Int, + ): Int { + if (params!!.draggingDisabled) { + return params!!.maxYPos + } + lastYPos = top if (params!!.dragDirection == Params.DRAGGABLE_DIRECTION_DOWN) { - if (lastYPos > params!!.dismissingYPos || yvel > params!!.dismissingYVelocity) { - settleDestY = params!!.offScreenYPos - dismissing = true - if (mListener != null) mListener!!.onDismiss() - } + // Dragging down + // If the top of the message is past the dragThresholdY trigger the onDragStart() callback + if (top >= params!!.dragThresholdY && mListener != null) mListener!!.onDragStart() + if (top < params!!.maxYPos) return params!!.maxYPos } else { - if (lastYPos < params!!.dismissingYPos || yvel < params!!.dismissingYVelocity) { - settleDestY = params!!.offScreenYPos - dismissing = true - if (mListener != null) mListener!!.onDismiss() - } + // Dragging up + // If the top of the message is past the dragThresholdY trigger the onDragStart() callback + if (top <= params!!.dragThresholdY && mListener != null) mListener!!.onDragStart() + if (top > params!!.maxYPos) return params!!.maxYPos } + return top } - if (mDragHelper!!.settleCapturedViewAt( - params!!.maxXPos, - settleDestY, - ) + + override fun clampViewPositionHorizontal( + child: View, + right: Int, + dy: Int, + ): Int { + return params!!.maxXPos + } + + // Base on position and scroll speed decide if we need to dismiss + override fun onViewReleased( + releasedChild: View, + xvel: Float, + yvel: Float, ) { - ViewCompat.postInvalidateOnAnimation(this@DraggableRelativeLayout) + var settleDestY = params!!.maxYPos + if (!dismissing) { + if (params!!.dragDirection == Params.DRAGGABLE_DIRECTION_DOWN) { + if (lastYPos > params!!.dismissingYPos || yvel > params!!.dismissingYVelocity) { + settleDestY = params!!.offScreenYPos + dismissing = true + if (mListener != null) mListener!!.onDismiss() + } + } else { + if (lastYPos < params!!.dismissingYPos || yvel < params!!.dismissingYVelocity) { + settleDestY = params!!.offScreenYPos + dismissing = true + if (mListener != null) mListener!!.onDismiss() + } + } + } + if (mDragHelper!!.settleCapturedViewAt( + params!!.maxXPos, + settleDestY, + ) + ) { + ViewCompat.postInvalidateOnAnimation(this@DraggableRelativeLayout) + } } - } - }, - ) + }, + ) } override fun onInterceptTouchEvent(event: MotionEvent): Boolean { diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/InAppDisplayer.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/InAppDisplayer.kt index f535f30fe5..9c7115cad3 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/InAppDisplayer.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/InAppDisplayer.kt @@ -44,7 +44,12 @@ internal class InAppDisplayer( private var lastInstance: WebViewManager? = null override suspend fun displayMessage(message: InAppMessage): Boolean? { - var response = _backend.getIAMData(_configModelStore.model.appId, message.messageId, InAppHelper.variantIdForMessage(message, _languageContext)) + var response = + _backend.getIAMData( + _configModelStore.model.appId, + message.messageId, + InAppHelper.variantIdForMessage(message, _languageContext), + ) if (response.content != null) { message.displayDuration = response.content!!.displayDuration!! @@ -83,7 +88,10 @@ internal class InAppDisplayer( * @param message the message to show * @param content the html to display on the WebView */ - private suspend fun showMessageContent(message: InAppMessage, content: InAppMessageContent) { + private suspend fun showMessageContent( + message: InAppMessage, + content: InAppMessageContent, + ) { val currentActivity = _applicationService.current Logging.debug("InAppDisplayer.showMessageContent: in app message on currentActivity: $currentActivity") @@ -115,12 +123,17 @@ internal class InAppDisplayer( } } - private suspend fun initInAppMessage(currentActivity: Activity, message: InAppMessage, content: InAppMessageContent) { + private suspend fun initInAppMessage( + currentActivity: Activity, + message: InAppMessage, + content: InAppMessageContent, + ) { try { - val base64Str = Base64.encodeToString( - content.contentHtml!!.toByteArray(charset("UTF-8")), - Base64.NO_WRAP, - ) + val base64Str = + Base64.encodeToString( + content.contentHtml!!.toByteArray(charset("UTF-8")), + Base64.NO_WRAP, + ) val webViewManager = WebViewManager(message, currentActivity, content, _lifecycle, _applicationService, _promptFactory) lastInstance = webViewManager diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/InAppMessageView.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/InAppMessageView.kt index b1c2d8f8c0..abf94008b2 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/InAppMessageView.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/InAppMessageView.kt @@ -54,7 +54,9 @@ internal class InAppMessageView( internal interface InAppMessageViewListener { fun onMessageWasDisplayed() + fun onMessageWillDismiss() + fun onMessageWasDismissed() } @@ -159,10 +161,11 @@ internal class InAppMessageView( /* IMPORTANT * The only place where currentActivity should be assigned to InAppMessageView */ this.currentActivity = currentActivity - val webViewLayoutParams = RelativeLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - pageHeight, - ) + val webViewLayoutParams = + RelativeLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + pageHeight, + ) webViewLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT) val relativeLayoutParams = if (hasBackground) createParentRelativeLayoutParams() else null showDraggableView( @@ -188,9 +191,10 @@ internal class InAppMessageView( relativeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) relativeLayoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL) } - WebViewManager.Position.CENTER_MODAL, WebViewManager.Position.FULL_SCREEN -> relativeLayoutParams.addRule( - RelativeLayout.CENTER_IN_PARENT, - ) + WebViewManager.Position.CENTER_MODAL, WebViewManager.Position.FULL_SCREEN -> + relativeLayoutParams.addRule( + RelativeLayout.CENTER_IN_PARENT, + ) } return relativeLayoutParams } @@ -265,23 +269,25 @@ internal class InAppMessageView( * @param parentRelativeLayout root layout to attach to the pop up window */ private fun createPopupWindow(parentRelativeLayout: RelativeLayout) { - popupWindow = PopupWindow( - parentRelativeLayout, - if (hasBackground) WindowManager.LayoutParams.MATCH_PARENT else pageWidth, - if (hasBackground) WindowManager.LayoutParams.MATCH_PARENT else WindowManager.LayoutParams.WRAP_CONTENT, - true, - ) + popupWindow = + PopupWindow( + parentRelativeLayout, + if (hasBackground) WindowManager.LayoutParams.MATCH_PARENT else pageWidth, + if (hasBackground) WindowManager.LayoutParams.MATCH_PARENT else WindowManager.LayoutParams.WRAP_CONTENT, + true, + ) popupWindow!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) popupWindow!!.isTouchable = true // NOTE: This is required for getting fullscreen under notches working in portrait mode popupWindow!!.isClippingEnabled = false var gravity = 0 if (!hasBackground) { - gravity = when (displayPosition) { - WebViewManager.Position.TOP_BANNER -> Gravity.CENTER_HORIZONTAL or Gravity.TOP - WebViewManager.Position.BOTTOM_BANNER -> Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM - WebViewManager.Position.CENTER_MODAL, WebViewManager.Position.FULL_SCREEN -> Gravity.CENTER_HORIZONTAL - } + gravity = + when (displayPosition) { + WebViewManager.Position.TOP_BANNER -> Gravity.CENTER_HORIZONTAL or Gravity.TOP + WebViewManager.Position.BOTTOM_BANNER -> Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM + WebViewManager.Position.CENTER_MODAL, WebViewManager.Position.FULL_SCREEN -> Gravity.CENTER_HORIZONTAL + } } // Using panel for fullbleed IAMs and dialog for non-fullbleed. The attached dialog type @@ -320,25 +326,27 @@ internal class InAppMessageView( ) } draggableRelativeLayout!!.setParams(draggableParams) - draggableRelativeLayout!!.setListener(object : DraggableRelativeLayout.DraggableListener { - override fun onDismiss() { - if (messageController != null) { - messageController!!.onMessageWillDismiss() + draggableRelativeLayout!!.setListener( + object : DraggableRelativeLayout.DraggableListener { + override fun onDismiss() { + if (messageController != null) { + messageController!!.onMessageWillDismiss() + } + + suspendifyOnThread { + finishAfterDelay() + } } - suspendifyOnThread { - finishAfterDelay() + override fun onDragStart() { + isDragging = true } - } - - override fun onDragStart() { - isDragging = true - } - override fun onDragEnd() { - isDragging = false - } - }) + override fun onDragEnd() { + isDragging = false + } + }, + ) if (webView!!.parent != null) (webView!!.parent as ViewGroup).removeAllViews() val cardView = createCardView(context) cardView.tag = IN_APP_MESSAGE_CARD_VIEW_TAG @@ -362,10 +370,11 @@ internal class InAppMessageView( val cardView = CardView(context) val height = if (displayPosition == WebViewManager.Position.FULL_SCREEN) ViewGroup.LayoutParams.MATCH_PARENT else ViewGroup.LayoutParams.WRAP_CONTENT - val cardViewLayoutParams = RelativeLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - height, - ) + val cardViewLayoutParams = + RelativeLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + height, + ) cardViewLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT) cardView.layoutParams = cardViewLayoutParams @@ -495,33 +504,38 @@ internal class InAppMessageView( messageView: View, backgroundView: View, ) { - val messageViewCardView = messageView!!.findViewWithTag( - IN_APP_MESSAGE_CARD_VIEW_TAG, - ) + val messageViewCardView = + messageView!!.findViewWithTag( + IN_APP_MESSAGE_CARD_VIEW_TAG, + ) val cardViewAnimCallback = createAnimationListener(messageViewCardView) when (displayLocation) { - WebViewManager.Position.TOP_BANNER -> animateTop( - messageViewCardView, - webView!!.height, - cardViewAnimCallback, - ) - WebViewManager.Position.BOTTOM_BANNER -> animateBottom( - messageViewCardView, - webView!!.height, - cardViewAnimCallback, - ) - WebViewManager.Position.CENTER_MODAL, WebViewManager.Position.FULL_SCREEN -> animateCenter( - messageView, - backgroundView, - cardViewAnimCallback, - null, - ) + WebViewManager.Position.TOP_BANNER -> + animateTop( + messageViewCardView, + webView!!.height, + cardViewAnimCallback, + ) + WebViewManager.Position.BOTTOM_BANNER -> + animateBottom( + messageViewCardView, + webView!!.height, + cardViewAnimCallback, + ) + WebViewManager.Position.CENTER_MODAL, WebViewManager.Position.FULL_SCREEN -> + animateCenter( + messageView, + backgroundView, + cardViewAnimCallback, + null, + ) } } private fun createAnimationListener(messageViewCardView: CardView): Animation.AnimationListener { return object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation) {} + override fun onAnimationEnd(animation: Animation) { // For Android 6 API 23 devices, waits until end of animation to set elevation of CardView class if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) { @@ -546,7 +560,7 @@ internal class InAppMessageView( messageView, ( -height - marginPxSizeTop - ).toFloat(), + ).toFloat(), 0f, IN_APP_BANNER_ANIMATION_DURATION_MS, OneSignalBounceInterpolator(0.1, 8.0), @@ -565,7 +579,7 @@ internal class InAppMessageView( messageView, ( height + marginPxSizeBottom - ).toFloat(), + ).toFloat(), 0f, IN_APP_BANNER_ANIMATION_DURATION_MS, OneSignalBounceInterpolator(0.1, 8.0), @@ -581,33 +595,36 @@ internal class InAppMessageView( backgroundAnimCallback: Animator.AnimatorListener?, ) { // Animate the message view by scale since it settles at the center of the screen - val messageAnimation = OneSignalAnimate.animateViewSmallToLarge( - messageView, - IN_APP_CENTER_ANIMATION_DURATION_MS, - OneSignalBounceInterpolator(0.1, 8.0), - cardViewAnimCallback, - ) + val messageAnimation = + OneSignalAnimate.animateViewSmallToLarge( + messageView, + IN_APP_CENTER_ANIMATION_DURATION_MS, + OneSignalBounceInterpolator(0.1, 8.0), + cardViewAnimCallback, + ) // Animate background behind the message so it doesn't just show the dark transparency - val backgroundAnimation = animateBackgroundColor( - backgroundView, - IN_APP_BACKGROUND_ANIMATION_DURATION_MS, - ACTIVITY_BACKGROUND_COLOR_EMPTY, - ACTIVITY_BACKGROUND_COLOR_FULL, - backgroundAnimCallback, - ) + val backgroundAnimation = + animateBackgroundColor( + backgroundView, + IN_APP_BACKGROUND_ANIMATION_DURATION_MS, + ACTIVITY_BACKGROUND_COLOR_EMPTY, + ACTIVITY_BACKGROUND_COLOR_FULL, + backgroundAnimCallback, + ) messageAnimation.start() backgroundAnimation.start() } private suspend fun animateAndDismissLayout(backgroundView: View) { val waiter = Waiter() - val animCallback: Animator.AnimatorListener = object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - cleanupViewsAfterDismiss() - waiter.wake() + val animCallback: Animator.AnimatorListener = + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + cleanupViewsAfterDismiss() + waiter.wake() + } } - } // Animate background behind the message so it hides before being removed from the view animateBackgroundColor( diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OSWebView.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OSWebView.kt index 45468a0655..6e977f10b7 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OSWebView.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OSWebView.kt @@ -20,7 +20,10 @@ internal class OSWebView(context: Context?) : WebView(context!!) { return false } - override fun scrollTo(x: Int, y: Int) { + override fun scrollTo( + x: Int, + y: Int, + ) { // Do nothing } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OneSignalAnimate.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OneSignalAnimate.kt index 83a508f5ff..27e549810f 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OneSignalAnimate.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OneSignalAnimate.kt @@ -62,16 +62,17 @@ internal object OneSignalAnimate { interpolator: Interpolator?, animCallback: Animation.AnimationListener?, ): Animation { - val scaleAnimation: Animation = ScaleAnimation( - 0f, - 1f, - 0f, - 1f, - Animation.RELATIVE_TO_SELF, - 0.5f, - Animation.RELATIVE_TO_SELF, - 0.5f, - ) + val scaleAnimation: Animation = + ScaleAnimation( + 0f, + 1f, + 0f, + 1f, + Animation.RELATIVE_TO_SELF, + 0.5f, + Animation.RELATIVE_TO_SELF, + 0.5f, + ) scaleAnimation.duration = duration.toLong() scaleAnimation.interpolator = interpolator if (animCallback != null) scaleAnimation.setAnimationListener(animCallback) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OneSignalBounceInterpolator.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OneSignalBounceInterpolator.kt index 4a2fc9cf63..ee4c73da26 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OneSignalBounceInterpolator.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/OneSignalBounceInterpolator.kt @@ -5,13 +5,15 @@ import android.view.animation.Interpolator internal class OneSignalBounceInterpolator(amplitude: Double, frequency: Double) : Interpolator { private var mAmplitude = 1.0 private var mFrequency = 10.0 + override fun getInterpolation(time: Float): Float { return ( - -1 * Math.pow( - Math.E, - -time / mAmplitude, - ) * Math.cos(mFrequency * time) + 1 - ).toFloat() + -1 * + Math.pow( + Math.E, + -time / mAmplitude, + ) * Math.cos(mFrequency * time) + 1 + ).toFloat() } init { diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/WebViewManager.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/WebViewManager.kt index be750dbdae..d239ec875e 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/WebViewManager.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/display/impl/WebViewManager.kt @@ -46,17 +46,22 @@ internal class WebViewManager( private val _applicationService: IApplicationService, private val _promptFactory: IInAppMessagePromptFactory, ) : IActivityLifecycleHandler { - private val messageViewMutex: Mutex = Mutex() internal enum class Position { - TOP_BANNER, BOTTOM_BANNER, CENTER_MODAL, FULL_SCREEN; + TOP_BANNER, + BOTTOM_BANNER, + CENTER_MODAL, + FULL_SCREEN, + ; val isBanner: Boolean get() { when (this) { TOP_BANNER, BOTTOM_BANNER -> return true - else -> { return false } + else -> { + return false + } } return false } @@ -165,7 +170,10 @@ internal class WebViewManager( } } - private fun pageRectToViewHeight(activity: Activity, jsonObject: JSONObject): Int { + private fun pageRectToViewHeight( + activity: Activity, + jsonObject: JSONObject, + ): Int { return try { val pageHeight = jsonObject.getJSONObject("rect").getInt("height") var pxHeight = ViewUtils.dpToPx(pageHeight) @@ -185,17 +193,19 @@ internal class WebViewManager( private suspend fun updateSafeAreaInsets() { withContext(Dispatchers.Main) { val insets = ViewUtils.getCutoutAndStatusBarInsets(activity) - val safeAreaInsetsObject = String.format( - SAFE_AREA_JS_OBJECT, - insets[0], - insets[1], - insets[2], - insets[3], - ) - val safeAreaInsetsFunction = String.format( - SET_SAFE_AREA_INSETS_JS_FUNCTION, - safeAreaInsetsObject, - ) + val safeAreaInsetsObject = + String.format( + SAFE_AREA_JS_OBJECT, + insets[0], + insets[1], + insets[2], + insets[3], + ) + val safeAreaInsetsFunction = + String.format( + SET_SAFE_AREA_INSETS_JS_FUNCTION, + safeAreaInsetsObject, + ) webView!!.evaluateJavascript(safeAreaInsetsFunction, null) } } @@ -261,9 +271,9 @@ internal class WebViewManager( override fun onActivityStopped(activity: Activity) { Logging.debug( """ - In app message activity stopped, cleaning views, currentActivityName: $currentActivityName - activity: ${this.activity} - messageView: $messageView + In app message activity stopped, cleaning views, currentActivityName: $currentActivityName + activity: ${this.activity} + messageView: $messageView """.trimIndent(), ) if (messageView != null && activity.localClassName == currentActivityName) { @@ -352,20 +362,22 @@ internal class WebViewManager( val newView = InAppMessageView(webView!!, messageContent, dragToDismissDisabled) setMessageView(newView) val self = this - messageView!!.setMessageController(object : InAppMessageView.InAppMessageViewListener { - override fun onMessageWasDisplayed() { - _lifecycle.messageWasDisplayed(message) - } + messageView!!.setMessageController( + object : InAppMessageView.InAppMessageViewListener { + override fun onMessageWasDisplayed() { + _lifecycle.messageWasDisplayed(message) + } - override fun onMessageWillDismiss() { - _lifecycle.messageWillDismiss(message) - } + override fun onMessageWillDismiss() { + _lifecycle.messageWillDismiss(message) + } - override fun onMessageWasDismissed() { - _lifecycle.messageWasDismissed(message) - _applicationService.removeActivityLifecycleHandler(self) - } - }) + override fun onMessageWasDismissed() { + _lifecycle.messageWasDismissed(message) + _applicationService.removeActivityLifecycleHandler(self) + } + }, + ) // Fires event if available, which will call messageView.showInAppMessageView() for us. _applicationService.addActivityLifecycleHandler(self) @@ -408,17 +420,21 @@ internal class WebViewManager( setMessageView(null) } - fun setContentSafeAreaInsets(content: InAppMessageContent, activity: Activity) { + fun setContentSafeAreaInsets( + content: InAppMessageContent, + activity: Activity, + ) { var html = content.contentHtml var safeAreaInsetsScript = SET_SAFE_AREA_INSETS_SCRIPT val insets = ViewUtils.getCutoutAndStatusBarInsets(activity) - val safeAreaJSObject = String.format( - SAFE_AREA_JS_OBJECT, - insets[0], - insets[1], - insets[2], - insets[3], - ) + val safeAreaJSObject = + String.format( + SAFE_AREA_JS_OBJECT, + insets[0], + insets[1], + insets[2], + insets[3], + ) safeAreaInsetsScript = String.format(safeAreaInsetsScript, safeAreaJSObject) html += safeAreaInsetsScript content.contentHtml = html @@ -437,16 +453,18 @@ internal class WebViewManager( const val JS_OBJ_NAME = "OSAndroid" const val GET_PAGE_META_DATA_JS_FUNCTION = "getPageMetaData()" const val SET_SAFE_AREA_INSETS_JS_FUNCTION = "setSafeAreaInsets(%s)" - const val SAFE_AREA_JS_OBJECT = "{\n" + - " top: %d,\n" + - " bottom: %d,\n" + - " right: %d,\n" + - " left: %d,\n" + - "}" - const val SET_SAFE_AREA_INSETS_SCRIPT = "\n\n" + - "" + const val SAFE_AREA_JS_OBJECT = + "{\n" + + " top: %d,\n" + + " bottom: %d,\n" + + " right: %d,\n" + + " left: %d,\n" + + "}" + const val SET_SAFE_AREA_INSETS_SCRIPT = + "\n\n" + + "" const val EVENT_TYPE_KEY = "type" const val EVENT_TYPE_RENDERING_COMPLETE = "rendering_complete" const val EVENT_TYPE_RESIZE = "resize" diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/hydrators/InAppHydrator.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/hydrators/InAppHydrator.kt index 64fa52bb7c..0518dc5c72 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/hydrators/InAppHydrator.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/hydrators/InAppHydrator.kt @@ -13,7 +13,6 @@ internal class InAppHydrator( private val _time: ITime, private val _propertiesModelStore: PropertiesModelStore, ) { - fun hydrateIAMMessages(jsonArray: JSONArray): List { val newMessages = ArrayList() for (i in 0 until jsonArray.length()) { @@ -53,9 +52,10 @@ internal class InAppHydrator( } companion object { - private const val LIQUID_TAG_SCRIPT = "\n\n" + - "" + private const val LIQUID_TAG_SCRIPT = + "\n\n" + + "" } } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/IInAppLifecycleEventHandler.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/IInAppLifecycleEventHandler.kt index c00cc7eb4e..c4488a9b5c 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/IInAppLifecycleEventHandler.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/IInAppLifecycleEventHandler.kt @@ -6,10 +6,25 @@ import com.onesignal.inAppMessages.internal.InAppMessagePage internal interface IInAppLifecycleEventHandler { fun onMessageWillDisplay(message: InAppMessage) + fun onMessageWasDisplayed(message: InAppMessage) - fun onMessageActionOccurredOnPreview(message: InAppMessage, action: InAppMessageClickResult) - fun onMessageActionOccurredOnMessage(message: InAppMessage, action: InAppMessageClickResult) - fun onMessagePageChanged(message: InAppMessage, page: InAppMessagePage) + + fun onMessageActionOccurredOnPreview( + message: InAppMessage, + action: InAppMessageClickResult, + ) + + fun onMessageActionOccurredOnMessage( + message: InAppMessage, + action: InAppMessageClickResult, + ) + + fun onMessagePageChanged( + message: InAppMessage, + page: InAppMessagePage, + ) + fun onMessageWillDismiss(message: InAppMessage) + fun onMessageWasDismissed(message: InAppMessage) } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/IInAppLifecycleService.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/IInAppLifecycleService.kt index 25359f40b8..6388511dc3 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/IInAppLifecycleService.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/IInAppLifecycleService.kt @@ -7,10 +7,25 @@ import com.onesignal.inAppMessages.internal.InAppMessagePage internal interface IInAppLifecycleService : IEventNotifier { fun messageWillDisplay(message: InAppMessage) + fun messageWasDisplayed(message: InAppMessage) - fun messageActionOccurredOnPreview(message: InAppMessage, action: InAppMessageClickResult) - fun messageActionOccurredOnMessage(message: InAppMessage, action: InAppMessageClickResult) - fun messagePageChanged(message: InAppMessage, page: InAppMessagePage) + + fun messageActionOccurredOnPreview( + message: InAppMessage, + action: InAppMessageClickResult, + ) + + fun messageActionOccurredOnMessage( + message: InAppMessage, + action: InAppMessageClickResult, + ) + + fun messagePageChanged( + message: InAppMessage, + page: InAppMessagePage, + ) + fun messageWillDismiss(message: InAppMessage) + fun messageWasDismissed(message: InAppMessage) } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/impl/IAMLifecycleService.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/impl/IAMLifecycleService.kt index cc4dd18975..95602a3d42 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/impl/IAMLifecycleService.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/lifecycle/impl/IAMLifecycleService.kt @@ -10,7 +10,6 @@ import com.onesignal.inAppMessages.internal.lifecycle.IInAppLifecycleService internal class IAMLifecycleService() : EventProducer(), IInAppLifecycleService { - override fun messageWillDisplay(message: InAppMessage) { fire { it.onMessageWillDisplay(message) } } @@ -19,15 +18,24 @@ internal class IAMLifecycleService() : fire { it.onMessageWasDisplayed(message) } } - override fun messageActionOccurredOnPreview(message: InAppMessage, action: InAppMessageClickResult) { + override fun messageActionOccurredOnPreview( + message: InAppMessage, + action: InAppMessageClickResult, + ) { fire { it.onMessageActionOccurredOnPreview(message, action) } } - override fun messageActionOccurredOnMessage(message: InAppMessage, action: InAppMessageClickResult) { + override fun messageActionOccurredOnMessage( + message: InAppMessage, + action: InAppMessageClickResult, + ) { fire { it.onMessageActionOccurredOnMessage(message, action) } } - override fun messagePageChanged(message: InAppMessage, page: InAppMessagePage) { + override fun messagePageChanged( + message: InAppMessage, + page: InAppMessagePage, + ) { fire { it.onMessagePageChanged(message, page) } } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preferences/IInAppPreferencesController.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preferences/IInAppPreferencesController.kt index aa286c3e01..2b019b8847 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preferences/IInAppPreferencesController.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preferences/IInAppPreferencesController.kt @@ -21,5 +21,6 @@ internal interface IInAppPreferencesController { * @see InAppPreferencesController.cleanCachedInAppMessages */ fun cleanInAppMessageIds(oldMessageIds: Set?) + fun cleanInAppMessageClickedClickIds(oldClickedClickIds: Set?) } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preferences/impl/InAppPreferencesController.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preferences/impl/InAppPreferencesController.kt index 1c68e5b40c..7b4437ae78 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preferences/impl/InAppPreferencesController.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preferences/impl/InAppPreferencesController.kt @@ -20,8 +20,18 @@ internal class InAppPreferencesController( */ override fun cleanInAppMessageIds(oldMessageIds: Set?) { if (oldMessageIds != null && oldMessageIds.isNotEmpty()) { - val dismissedMessages: Set? = _prefs.getStringSet(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_DISMISSED_IAMS, null) - val impressionedMessages: Set? = _prefs.getStringSet(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_IMPRESSIONED_IAMS, null) + val dismissedMessages: Set? = + _prefs.getStringSet( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_DISMISSED_IAMS, + null, + ) + val impressionedMessages: Set? = + _prefs.getStringSet( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_IMPRESSIONED_IAMS, + null, + ) if (dismissedMessages != null && dismissedMessages.isNotEmpty()) { val mutDismissedMessages = dismissedMessages.toMutableSet() @@ -32,18 +42,31 @@ internal class InAppPreferencesController( if (impressionedMessages != null && impressionedMessages.isNotEmpty()) { val mutImpressionedMessages = impressionedMessages.toMutableSet() mutImpressionedMessages.removeAll(oldMessageIds) - _prefs.saveStringSet(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_IMPRESSIONED_IAMS, mutImpressionedMessages) + _prefs.saveStringSet( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_IMPRESSIONED_IAMS, + mutImpressionedMessages, + ) } } } override fun cleanInAppMessageClickedClickIds(oldClickedClickIds: Set?) { if (oldClickedClickIds != null && oldClickedClickIds.isNotEmpty()) { - val clickedClickIds: Set? = _prefs.getStringSet(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_CLICKED_CLICK_IDS_IAMS, null) + val clickedClickIds: Set? = + _prefs.getStringSet( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_CLICKED_CLICK_IDS_IAMS, + null, + ) if (clickedClickIds != null && clickedClickIds.isNotEmpty()) { val mutclickedClickIds = clickedClickIds.toMutableSet() mutclickedClickIds.removeAll(oldClickedClickIds) - _prefs.saveStringSet(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_CLICKED_CLICK_IDS_IAMS, mutclickedClickIds) + _prefs.saveStringSet( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_CLICKED_CLICK_IDS_IAMS, + mutclickedClickIds, + ) } } } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandler.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandler.kt index 5e85d9a84b..f0b45ddfbb 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandler.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandler.kt @@ -28,7 +28,6 @@ internal class InAppMessagePreviewHandler( private val _state: InAppStateService, private val _time: ITime, ) : IStartableService, INotificationLifecycleCallback { - override fun start() { _notificationLifeCycle.setInternalNotificationLifecycleCallback(this) } @@ -52,7 +51,10 @@ internal class InAppMessagePreviewHandler( return false } - override suspend fun canOpenNotification(activity: Activity, jsonData: JSONObject): Boolean { + override suspend fun canOpenNotification( + activity: Activity, + jsonData: JSONObject, + ): Boolean { val previewUUID = inAppPreviewPushUUID(jsonData) ?: return true _notificationActivityOpener.openDestinationActivity(activity, JSONArray().put(jsonData)) @@ -66,11 +68,12 @@ internal class InAppMessagePreviewHandler( } private fun inAppPreviewPushUUID(payload: JSONObject): String? { - val osCustom: JSONObject = try { - NotificationHelper.getCustomJSONObject(payload) - } catch (e: JSONException) { - return null - } + val osCustom: JSONObject = + try { + NotificationHelper.getCustomJSONObject(payload) + } catch (e: JSONException) { + return null + } if (!osCustom.has(NotificationConstants.PUSH_ADDITIONAL_DATA_KEY)) { return null diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/IInAppMessagePromptFactory.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/IInAppMessagePromptFactory.kt index b852927e5c..a1f06ac59c 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/IInAppMessagePromptFactory.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/IInAppMessagePromptFactory.kt @@ -7,7 +7,6 @@ import com.onesignal.inAppMessages.internal.prompt.impl.InAppMessagePrompt * the callers needs. */ internal interface IInAppMessagePromptFactory { - /** * Create a new prompt instance depending on the prompt type required. * diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/impl/InAppMessagePrompt.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/impl/InAppMessagePrompt.kt index c74c791969..405d821476 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/impl/InAppMessagePrompt.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/impl/InAppMessagePrompt.kt @@ -2,8 +2,11 @@ package com.onesignal.inAppMessages.internal.prompt.impl internal abstract class InAppMessagePrompt() { private var prompted = false + abstract suspend fun handlePrompt(): PromptActionResult? + abstract val promptKey: String + fun hasPrompted(): Boolean { return prompted } @@ -20,13 +23,16 @@ internal abstract class InAppMessagePrompt() { } /* - * End OneSignalOutcome module - */ + * End OneSignalOutcome module + */ internal interface OSPromptActionCompletionCallback { fun onCompleted(result: PromptActionResult?) } internal enum class PromptActionResult { - PERMISSION_GRANTED, PERMISSION_DENIED, LOCATION_PERMISSIONS_MISSING_MANIFEST, ERROR + PERMISSION_GRANTED, + PERMISSION_DENIED, + LOCATION_PERMISSIONS_MISSING_MANIFEST, + ERROR, } } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/impl/InAppMessagePromptFactory.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/impl/InAppMessagePromptFactory.kt index f884033d54..94aaa66806 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/impl/InAppMessagePromptFactory.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/prompt/impl/InAppMessagePromptFactory.kt @@ -9,7 +9,6 @@ internal class InAppMessagePromptFactory( private val _notificationsManager: INotificationsManager, private val _locationManager: ILocationManager, ) : IInAppMessagePromptFactory { - override fun createPrompt(promptType: String): InAppMessagePrompt? { return when (promptType) { InAppMessagePromptTypes.PUSH_PROMPT_KEY -> InAppMessagePushPrompt(_notificationsManager) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/repositories/impl/InAppRepository.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/repositories/impl/InAppRepository.kt index 91e74abb13..fb8d41d669 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/repositories/impl/InAppRepository.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/repositories/impl/InAppRepository.kt @@ -20,7 +20,6 @@ internal class InAppRepository( private val _time: ITime, private val _prefs: IInAppPreferencesController, ) : IInAppRepository { - override suspend fun saveInAppMessage(inAppMessage: InAppMessage) { val values = ContentValues() values.put( @@ -45,12 +44,13 @@ internal class InAppRepository( ) withContext(Dispatchers.IO) { - val rowsUpdated: Int = _databaseProvider.os.update( - OneSignalDbContract.InAppMessageTable.TABLE_NAME, - values, - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID.toString() + " = ?", - arrayOf(inAppMessage.messageId), - ) + val rowsUpdated: Int = + _databaseProvider.os.update( + OneSignalDbContract.InAppMessageTable.TABLE_NAME, + values, + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID.toString() + " = ?", + arrayOf(inAppMessage.messageId), + ) if (rowsUpdated == 0) { _databaseProvider.os.insert( @@ -83,13 +83,14 @@ internal class InAppRepository( val clickIdsSet: Set = JSONUtils.newStringSetFromJSONArray(JSONArray(clickIds)) - val inAppMessage = InAppMessage( - messageId, - clickIdsSet, - displayed, - InAppMessageRedisplayStats(displayQuantity, lastDisplay, _time), - _time, - ) + val inAppMessage = + InAppMessage( + messageId, + clickIdsSet, + displayed, + InAppMessageRedisplayStats(displayQuantity, lastDisplay, _time), + _time, + ) inAppMessages.add(inAppMessage) } while (it.moveToNext()) } @@ -105,10 +106,11 @@ internal class InAppRepository( override suspend fun cleanCachedInAppMessages() { withContext(Dispatchers.IO) { // 1. Query for all old message ids and old clicked click ids - val retColumns = arrayOf( - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID, - OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS, - ) + val retColumns = + arrayOf( + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID, + OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS, + ) val whereStr: String = OneSignalDbContract.InAppMessageTable.COLUMN_NAME_LAST_DISPLAY.toString() + " < ?" val sixMonthsAgoInSeconds = diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/ITriggerController.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/ITriggerController.kt index 9d63ad7c97..9bd9d0796e 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/ITriggerController.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/ITriggerController.kt @@ -29,7 +29,10 @@ internal interface ITriggerController : IEventNotifier { * * @return true if the provided message contains at least one of the [triggersKeys], false otherwise. */ - fun isTriggerOnMessage(message: InAppMessage, triggersKeys: Collection): Boolean + fun isTriggerOnMessage( + message: InAppMessage, + triggersKeys: Collection, + ): Boolean /** * Determine if the provided message only has dynamic triggers. diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/TriggerModel.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/TriggerModel.kt index 95e2f13f79..6871b19b29 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/TriggerModel.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/TriggerModel.kt @@ -8,12 +8,16 @@ class TriggerModel : Model() { */ var key: String get() = getStringProperty(::key.name) { "" } - set(value) { setStringProperty(::key.name, value) } + set(value) { + setStringProperty(::key.name, value) + } /** * The value of this trigger */ var value: Any get() = getAnyProperty(::value.name) { "" } - set(value) { setAnyProperty(::value.name, value) } + set(value) { + setAnyProperty(::value.name, value) + } } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/DynamicTriggerController.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/DynamicTriggerController.kt index 6ac6602dec..8f12b54575 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/DynamicTriggerController.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/DynamicTriggerController.kt @@ -18,9 +18,7 @@ internal class DynamicTriggerController( private val _state: InAppStateService, private val _session: ISessionService, private val _time: ITime, - ) : IEventNotifier { - val events = EventProducer() private val scheduledMessages: MutableList = mutableListOf() @@ -110,24 +108,30 @@ internal class DynamicTriggerController( ): Boolean { return when (operator) { Trigger.OSTriggerOperator.LESS_THAN -> currentTimeInterval < timeInterval - Trigger.OSTriggerOperator.LESS_THAN_OR_EQUAL_TO -> currentTimeInterval <= timeInterval || roughlyEqual( - timeInterval, - currentTimeInterval, - ) + Trigger.OSTriggerOperator.LESS_THAN_OR_EQUAL_TO -> + currentTimeInterval <= timeInterval || + roughlyEqual( + timeInterval, + currentTimeInterval, + ) Trigger.OSTriggerOperator.GREATER_THAN -> // Counting equal as greater. This way we don't need to schedule a Runnable for 1ms in the future. currentTimeInterval >= timeInterval - Trigger.OSTriggerOperator.GREATER_THAN_OR_EQUAL_TO -> currentTimeInterval >= timeInterval || roughlyEqual( - timeInterval, - currentTimeInterval, - ) - Trigger.OSTriggerOperator.EQUAL_TO -> roughlyEqual( - timeInterval, - currentTimeInterval, - ) - Trigger.OSTriggerOperator.NOT_EQUAL_TO -> !roughlyEqual( - timeInterval, - currentTimeInterval, - ) + Trigger.OSTriggerOperator.GREATER_THAN_OR_EQUAL_TO -> + currentTimeInterval >= timeInterval || + roughlyEqual( + timeInterval, + currentTimeInterval, + ) + Trigger.OSTriggerOperator.EQUAL_TO -> + roughlyEqual( + timeInterval, + currentTimeInterval, + ) + Trigger.OSTriggerOperator.NOT_EQUAL_TO -> + !roughlyEqual( + timeInterval, + currentTimeInterval, + ) else -> { Logging.error("Attempted to apply an invalid operator on a time-based in-app-message trigger: $operator") false @@ -135,7 +139,10 @@ internal class DynamicTriggerController( } } - private fun roughlyEqual(left: Double, right: Double): Boolean { + private fun roughlyEqual( + left: Double, + right: Double, + ): Boolean { return abs(left - right) < REQUIRED_ACCURACY } @@ -147,7 +154,9 @@ internal class DynamicTriggerController( } override fun subscribe(handler: ITriggerHandler) = events.subscribe(handler) + override fun unsubscribe(handler: ITriggerHandler) = events.unsubscribe(handler) + override val hasSubscribers: Boolean get() = events.hasSubscribers } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/DynamicTriggerTimer.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/DynamicTriggerTimer.kt index f2e3a8b056..918626525c 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/DynamicTriggerTimer.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/DynamicTriggerTimer.kt @@ -11,7 +11,11 @@ import java.util.TimerTask * that schedules the timer. */ internal object DynamicTriggerTimer { - fun scheduleTrigger(task: TimerTask?, triggerId: String, delay: Long) { + fun scheduleTrigger( + task: TimerTask?, + triggerId: String, + delay: Long, + ) { Logging.debug("scheduleTrigger: $triggerId delay: $delay") val timer = Timer("trigger_timer:$triggerId") timer.schedule(task, delay) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/TriggerController.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/TriggerController.kt index fc748227de..bb1496ae30 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/TriggerController.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/triggers/impl/TriggerController.kt @@ -16,7 +16,6 @@ internal class TriggerController( triggerModelStore: TriggerModelStore, private var _dynamicTriggerController: DynamicTriggerController, ) : ITriggerController, IModelStoreChangeHandler { - val triggers: ConcurrentHashMap = ConcurrentHashMap() init { @@ -60,11 +59,12 @@ internal class TriggerController( } val operatorType = trigger.operatorType - val deviceValue = triggers[trigger.property] - ?: // If we don't have a local value for this trigger, can only be true in two cases; - // 1. If operator is Not Exists - // 2. Checking to make sure the key doesn't equal a specific value, other than null of course. - return if (operatorType == Trigger.OSTriggerOperator.NOT_EXISTS) true else operatorType == Trigger.OSTriggerOperator.NOT_EQUAL_TO && trigger.value != null + val deviceValue = + triggers[trigger.property] + ?: // If we don't have a local value for this trigger, can only be true in two cases; + // 1. If operator is Not Exists + // 2. Checking to make sure the key doesn't equal a specific value, other than null of course. + return if (operatorType == Trigger.OSTriggerOperator.NOT_EXISTS) true else operatorType == Trigger.OSTriggerOperator.NOT_EQUAL_TO && trigger.value != null // We have local value at this point, we can evaluate existence checks if (operatorType == Trigger.OSTriggerOperator.EXISTS) { @@ -144,11 +144,12 @@ internal class TriggerController( deviceValue: String, operator: Trigger.OSTriggerOperator, ): Boolean { - val deviceDoubleValue: Double = try { - deviceValue.toDouble() - } catch (e: NumberFormatException) { - return false - } + val deviceDoubleValue: Double = + try { + deviceValue.toDouble() + } catch (e: NumberFormatException) { + return false + } return triggerMatchesNumericValue(triggerValue.toDouble(), deviceDoubleValue, operator) } @@ -173,7 +174,10 @@ internal class TriggerController( } } - override fun isTriggerOnMessage(message: InAppMessage, triggersKeys: Collection): Boolean { + override fun isTriggerOnMessage( + message: InAppMessage, + triggersKeys: Collection, + ): Boolean { if (message.triggers == null) { return false } @@ -206,22 +210,34 @@ internal class TriggerController( return true } - override fun onModelAdded(model: TriggerModel, tag: String) { + override fun onModelAdded( + model: TriggerModel, + tag: String, + ) { addTriggers(model.key, model.value) _dynamicTriggerController.events.fire { it.onTriggerChanged(model.key) } } - override fun onModelUpdated(args: ModelChangedArgs, tag: String) { + override fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) { val model = args.model as TriggerModel addTriggers(model.key, model.value) _dynamicTriggerController.events.fire { it.onTriggerChanged(model.key) } } - override fun onModelRemoved(model: TriggerModel, tag: String) { + override fun onModelRemoved( + model: TriggerModel, + tag: String, + ) { removeTriggersForKeys(model.key) } - private fun addTriggers(key: String, value: Any) { + private fun addTriggers( + key: String, + value: Any, + ) { synchronized(triggers) { triggers[key] = value } @@ -232,7 +248,9 @@ internal class TriggerController( } override fun subscribe(handler: ITriggerHandler) = _dynamicTriggerController.subscribe(handler) + override fun unsubscribe(handler: ITriggerHandler) = _dynamicTriggerController.unsubscribe(handler) + override val hasSubscribers: Boolean get() = _dynamicTriggerController.hasSubscribers } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/ContainedRobolectricRunner.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/ContainedRobolectricRunner.kt index 099db0bae7..123fe4a883 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/ContainedRobolectricRunner.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/ContainedRobolectricRunner.kt @@ -17,11 +17,13 @@ internal class ContainedRobolectricRunner( private val config: Config?, ) : RobolectricTestRunner(PlaceholderTest::class.java, injector) { private val placeHolderMethod: FrameworkMethod = children[0] - val sdkEnvironment = getSandbox(placeHolderMethod).also { - configureSandbox(it, placeHolderMethod) - } - private val bootStrapMethod = sdkEnvironment.bootstrappedClass(testClass.javaClass) - .getMethod(PlaceholderTest::bootStrapMethod.name) + val sdkEnvironment = + getSandbox(placeHolderMethod).also { + configureSandbox(it, placeHolderMethod) + } + private val bootStrapMethod = + sdkEnvironment.bootstrappedClass(testClass.javaClass) + .getMethod(PlaceholderTest::bootStrapMethod.name) fun containedBefore() { Thread.currentThread().contextClassLoader = sdkEnvironment.robolectricClassLoader @@ -41,8 +43,9 @@ internal class ContainedRobolectricRunner( } override fun getConfig(method: Method?): Config { - val defaultConfiguration = injector.getInstance(ConfigurationStrategy::class.java) - .getConfig(testClass.javaClass, method) + val defaultConfiguration = + injector.getInstance(ConfigurationStrategy::class.java) + .getConfig(testClass.javaClass, method) if (config != null) { val configConfigurer = injector.getInstance(ConfigConfigurer::class.java) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/RobolectricExtension.kt index f73d82cda8..5e02113ecd 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/RobolectricExtension.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/extensions/RobolectricExtension.kt @@ -30,9 +30,10 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { } private fun KClass<*>.getConfig(): Config { - val configAnnotations = listOf(this.java).plus(this.java.getParentClass()) - .mapNotNull { it.kotlin.findAnnotation() } - .asSequence() + val configAnnotations = + listOf(this.java).plus(this.java.getParentClass()) + .mapNotNull { it.kotlin.findAnnotation() } + .asSequence() val configAnnotation = configAnnotations.firstOrNull() @@ -40,12 +41,14 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { return Config.Builder(configAnnotation).build() } - val robolectricTestAnnotations = listOf(this.java).plus(this.java.getParentClass()) - .mapNotNull { it.kotlin.findAnnotation() } - .asSequence() + val robolectricTestAnnotations = + listOf(this.java).plus(this.java.getParentClass()) + .mapNotNull { it.kotlin.findAnnotation() } + .asSequence() - val application: KClass? = robolectricTestAnnotations - .firstOrNull { it.application != KotestDefaultApplication::class }?.application + val application: KClass? = + robolectricTestAnnotations + .firstOrNull { it.application != KotestDefaultApplication::class }?.application val sdk: Int? = robolectricTestAnnotations.firstOrNull { it.sdk != -1 }?.takeUnless { it.sdk == -1 }?.sdk return Config.Builder() @@ -72,9 +75,10 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { execute: suspend (TestCase) -> TestResult, ): TestResult { // FIXED: Updated code based on https://github.com/kotest/kotest/issues/2717 - val hasRobolectricAnnotation = testCase.spec::class.annotations.any { annotation -> - annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName - } + val hasRobolectricAnnotation = + testCase.spec::class.annotations.any { annotation -> + annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName + } if (!hasRobolectricAnnotation) { return execute(testCase) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/InAppMessagesManagerTests.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/InAppMessagesManagerTests.kt index 7bf609d69e..ac3768933d 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/InAppMessagesManagerTests.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/InAppMessagesManagerTests.kt @@ -28,7 +28,7 @@ import org.junit.runner.RunWith class InAppMessagesManagerTests : FunSpec({ test("triggers are backed by the trigger model store") { - /* Given */ + // Given val mockTriggerModelStore = mockk() val triggerModelSlots = mutableListOf() every { mockTriggerModelStore.get(any()) } returns null @@ -36,34 +36,35 @@ class InAppMessagesManagerTests : FunSpec({ every { mockTriggerModelStore.remove(any()) } just runs every { mockTriggerModelStore.clear() } just runs - val iamManager = InAppMessagesManager( - MockHelper.applicationService(), - mockk(), - mockk(), - mockk(), - mockk(), - mockk(), - mockk(), - mockk(), - mockk(), - mockk(), - mockk(), - mockk(), - mockTriggerModelStore, - mockk(), - mockk(), - MockHelper.languageContext(), - MockHelper.time(1000), - ) + val iamManager = + InAppMessagesManager( + MockHelper.applicationService(), + mockk(), + mockk(), + mockk(), + mockk(), + mockk(), + mockk(), + mockk(), + mockk(), + mockk(), + mockk(), + mockk(), + mockTriggerModelStore, + mockk(), + mockk(), + MockHelper.languageContext(), + MockHelper.time(1000), + ) - /* When */ + // When iamManager.addTrigger("trigger-key1", "trigger-value1") iamManager.addTriggers(mapOf("trigger-key2" to "trigger-value2", "trigger-key3" to "trigger-value3")) iamManager.removeTrigger("trigger-key4") iamManager.removeTriggers(listOf("trigger-key5", "trigger-key6")) iamManager.clearTriggers() - /* Then */ + // Then triggerModelSlots[0].key shouldBe "trigger-key1" triggerModelSlots[0].value shouldBe "trigger-value1" triggerModelSlots[1].key shouldBe "trigger-key2" diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/backend/InAppBackendServiceTests.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/backend/InAppBackendServiceTests.kt index 13b312580a..024922f06f 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/backend/InAppBackendServiceTests.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/backend/InAppBackendServiceTests.kt @@ -31,34 +31,36 @@ class InAppBackendServiceTests : FunSpec({ } test("listInAppMessages with no messages returns zero-lengthed array") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(200, "{ in_app_messages: [] }") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.listInAppMessages("appId", "subscriptionId") - /* Then */ + // Then response shouldNotBe null response!!.count() shouldBe 0 coVerify(exactly = 1) { mockHttpClient.get("apps/appId/subscriptions/subscriptionId/iams", any()) } } test("listInAppMessages with 1 message returns one-lengthed array") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() - coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(200, "{ in_app_messages: [{id: \"messageId1\", variants:{all: {en: \"content1\"}}, triggers:[[{id: \"triggerId1\", kind: \"custom\", property: \"property1\", operator: \"equal\", value: \"value1\"}]], end_time: \"2008-09-03T20:56:35.450686Z\", redisplay: { limit: 11111, delay: 22222}}] }") + coEvery { + mockHttpClient.get(any(), any()) + } returns HttpResponse(200, "{ in_app_messages: [{id: \"messageId1\", variants:{all: {en: \"content1\"}}, triggers:[[{id: \"triggerId1\", kind: \"custom\", property: \"property1\", operator: \"equal\", value: \"value1\"}]], end_time: \"2008-09-03T20:56:35.450686Z\", redisplay: { limit: 11111, delay: 22222}}] }") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.listInAppMessages("appId", "subscriptionId") - /* Then */ + // Then response shouldNotBe null response!!.count() shouldBe 1 response[0].messageId shouldBe "messageId1" @@ -81,33 +83,35 @@ class InAppBackendServiceTests : FunSpec({ } test("listInAppMessages returns null when non-success response") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(404, null) val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.listInAppMessages("appId", "subscriptionId") - /* Then */ + // Then response shouldBe null coVerify(exactly = 1) { mockHttpClient.get("apps/appId/subscriptions/subscriptionId/iams", any()) } } test("getIAMData successfully hydrates successful response") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() - coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(200, "{html: \"html1\", display_duration: 123, styles: {remove_height_margin: true, remove_width_margin: true}}") + coEvery { + mockHttpClient.get(any(), any()) + } returns HttpResponse(200, "{html: \"html1\", display_duration: 123, styles: {remove_height_margin: true, remove_width_margin: true}}") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.getIAMData("appId", "messageId", "variantId") - /* Then */ + // Then response shouldNotBe null response.shouldRetry shouldBe false response.content shouldNotBe null @@ -121,17 +125,17 @@ class InAppBackendServiceTests : FunSpec({ } test("getIAMData successfully hydrates successful response with no content") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(200, "{}") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.getIAMData("appId", "messageId", "variantId") - /* Then */ + // Then response shouldNotBe null response.shouldRetry shouldBe false response.content shouldBe null @@ -140,17 +144,17 @@ class InAppBackendServiceTests : FunSpec({ } test("getIAMData successfully hydrates successful response with no style") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(200, "{html: \"html1\", display_duration: 123 }") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.getIAMData("appId", "messageId", "variantId") - /* Then */ + // Then response shouldNotBe null response.shouldRetry shouldBe false response.content shouldNotBe null @@ -164,17 +168,17 @@ class InAppBackendServiceTests : FunSpec({ } test("getIAMData indicates retry when retryable response provided") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(500, null) val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.getIAMData("appId", "messageId", "variantId") - /* Then */ + // Then response shouldNotBe null response.shouldRetry shouldBe true response.content shouldBe null @@ -183,17 +187,17 @@ class InAppBackendServiceTests : FunSpec({ } test("getIAMData indicates no retry when non-retryable response provided") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(404, null) val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.getIAMData("appId", "messageId", "variantId") - /* Then */ + // Then response shouldNotBe null response.shouldRetry shouldBe false response.content shouldBe null @@ -202,20 +206,20 @@ class InAppBackendServiceTests : FunSpec({ } test("getIAMData indicates no retry when retryable response provided more than 3 times") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(500, null) val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response1 = inAppBackendService.getIAMData("appId", "messageId", "variantId") val response2 = inAppBackendService.getIAMData("appId", "messageId", "variantId") val response3 = inAppBackendService.getIAMData("appId", "messageId", "variantId") val response4 = inAppBackendService.getIAMData("appId", "messageId", "variantId") - /* Then */ + // Then response1 shouldNotBe null response1.shouldRetry shouldBe true response1.content shouldBe null @@ -233,17 +237,19 @@ class InAppBackendServiceTests : FunSpec({ } test("getIAMPreviewData successfully hydrates successful response") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() - coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(200, "{html: \"html1\", display_duration: 123, styles: {remove_height_margin: true, remove_width_margin: true}}") + coEvery { + mockHttpClient.get(any(), any()) + } returns HttpResponse(200, "{html: \"html1\", display_duration: 123, styles: {remove_height_margin: true, remove_width_margin: true}}") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.getIAMPreviewData("appId", "previewUUID") - /* Then */ + // Then response shouldNotBe null response!!.contentHtml shouldStartWith "html1" response!!.displayDuration shouldBe 123 @@ -255,34 +261,34 @@ class InAppBackendServiceTests : FunSpec({ } test("getIAMPreviewData returns no data when response is unsuccessful") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.get(any(), any()) } returns HttpResponse(404, null) val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When val response = inAppBackendService.getIAMPreviewData("appId", "previewUUID") - /* Then */ + // Then response shouldBe null coVerify(exactly = 1) { mockHttpClient.get("in_app_messages/device_preview?preview_id=previewUUID&app_id=appId", any()) } } test("sendIAMClick is successful when there is a successful response") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.post(any(), any()) } returns HttpResponse(200, "{}") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When inAppBackendService.sendIAMClick("appId", "subscriptionId", "variantId", "messageId", "clickId", isFirstClick = true) - /* Then */ + // Then coVerify(exactly = 1) { mockHttpClient.post( "in_app_messages/messageId/click", @@ -299,26 +305,27 @@ class InAppBackendServiceTests : FunSpec({ } test("sendIAMClick throws exception when there is an unsuccessful response") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.post(any(), any()) } returns HttpResponse(409, "{}") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ - val exception = shouldThrowUnit { - inAppBackendService.sendIAMClick( - "appId", - "subscriptionId", - "variantId", - "messageId", - "clickId", - isFirstClick = true, - ) - } - - /* Then */ + // When + val exception = + shouldThrowUnit { + inAppBackendService.sendIAMClick( + "appId", + "subscriptionId", + "variantId", + "messageId", + "clickId", + isFirstClick = true, + ) + } + + // Then exception.statusCode shouldBe 409 exception.response shouldBe "{}" coVerify(exactly = 1) { @@ -337,17 +344,17 @@ class InAppBackendServiceTests : FunSpec({ } test("sendIAMImpression is successful when there is a successful response") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.post(any(), any()) } returns HttpResponse(200, "{}") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When inAppBackendService.sendIAMImpression("appId", "subscriptionId", "variantId", "messageId") - /* Then */ + // Then coVerify(exactly = 1) { mockHttpClient.post( "in_app_messages/messageId/impression", @@ -363,19 +370,20 @@ class InAppBackendServiceTests : FunSpec({ } test("sendIAMImpression throws exception when there is an unsuccessful response") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.post(any(), any()) } returns HttpResponse(409, "{}") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ - val exception = shouldThrowUnit { - inAppBackendService.sendIAMImpression("appId", "subscriptionId", "variantId", "messageId") - } + // When + val exception = + shouldThrowUnit { + inAppBackendService.sendIAMImpression("appId", "subscriptionId", "variantId", "messageId") + } - /* Then */ + // Then exception.statusCode shouldBe 409 exception.response shouldBe "{}" coVerify(exactly = 1) { @@ -393,17 +401,17 @@ class InAppBackendServiceTests : FunSpec({ } test("sendIAMPageImpression is successful when there is a successful response") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.post(any(), any()) } returns HttpResponse(200, "{}") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ + // When inAppBackendService.sendIAMPageImpression("appId", "subscriptionId", "variantId", "messageId", "pageId") - /* Then */ + // Then coVerify(exactly = 1) { mockHttpClient.post( "in_app_messages/messageId/pageImpression", @@ -419,19 +427,20 @@ class InAppBackendServiceTests : FunSpec({ } test("sendIAMPageImpression throws exception when there is an unsuccessful response") { - /* Given */ + // Given val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore()) val mockHttpClient = mockk() coEvery { mockHttpClient.post(any(), any()) } returns HttpResponse(409, "{}") val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator) - /* When */ - val exception = shouldThrowUnit { - inAppBackendService.sendIAMPageImpression("appId", "subscriptionId", "variantId", "messageId", "pageId") - } + // When + val exception = + shouldThrowUnit { + inAppBackendService.sendIAMPageImpression("appId", "subscriptionId", "variantId", "messageId", "pageId") + } - /* Then */ + // Then exception.statusCode shouldBe 409 exception.response shouldBe "{}" coVerify(exactly = 1) { diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandlerTests.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandlerTests.kt index 14ab6beef1..572bba363b 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandlerTests.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/preview/InAppMessagePreviewHandlerTests.kt @@ -36,7 +36,7 @@ class InAppMessagePreviewHandlerTests : FunSpec({ } test("canReceiveNotification displays IAM and returns false when notification has a IAM preview id and in foreground") { - /* Given */ + // Given val mockInAppDisplayer = mockk() coEvery { mockInAppDisplayer.displayPreviewMessage(any()) } returns true @@ -48,37 +48,39 @@ class InAppMessagePreviewHandlerTests : FunSpec({ val stateService = InAppStateService() - val inAppMessagePreviewHandler = InAppMessagePreviewHandler( - mockInAppDisplayer, - mockApplicationService, - mockNotificationDisplayer, - mockNotificationActivityOpener, - mockNotificationLifecycleService, - stateService, - MockHelper.time(1111), - ) - - val jsonObject = JSONObject() - .put( - "custom", - JSONObject() - .put( - "a", - JSONObject() - .put("os_in_app_message_preview_id", "previewUUID"), - ), + val inAppMessagePreviewHandler = + InAppMessagePreviewHandler( + mockInAppDisplayer, + mockApplicationService, + mockNotificationDisplayer, + mockNotificationActivityOpener, + mockNotificationLifecycleService, + stateService, + MockHelper.time(1111), ) - /* When */ + val jsonObject = + JSONObject() + .put( + "custom", + JSONObject() + .put( + "a", + JSONObject() + .put("os_in_app_message_preview_id", "previewUUID"), + ), + ) + + // When val response = inAppMessagePreviewHandler.canReceiveNotification(jsonObject) - /* Then */ + // Then response shouldBe false coVerify(exactly = 1) { mockInAppDisplayer.displayPreviewMessage("previewUUID") } } test("canReceiveNotification displays notification and returns false when notification has a IAM preview id and in background") { - /* Given */ + // Given val mockInAppDisplayer = mockk() val mockNotificationDisplayer = mockk() coEvery { mockNotificationDisplayer.displayNotification(any()) } returns true @@ -89,37 +91,39 @@ class InAppMessagePreviewHandlerTests : FunSpec({ val stateService = InAppStateService() - val inAppMessagePreviewHandler = InAppMessagePreviewHandler( - mockInAppDisplayer, - mockApplicationService, - mockNotificationDisplayer, - mockNotificationActivityOpener, - mockNotificationLifecycleService, - stateService, - MockHelper.time(1111), - ) - - val jsonObject = JSONObject() - .put( - "custom", - JSONObject() - .put( - "a", - JSONObject() - .put("os_in_app_message_preview_id", "previewUUID"), - ), + val inAppMessagePreviewHandler = + InAppMessagePreviewHandler( + mockInAppDisplayer, + mockApplicationService, + mockNotificationDisplayer, + mockNotificationActivityOpener, + mockNotificationLifecycleService, + stateService, + MockHelper.time(1111), ) - /* When */ + val jsonObject = + JSONObject() + .put( + "custom", + JSONObject() + .put( + "a", + JSONObject() + .put("os_in_app_message_preview_id", "previewUUID"), + ), + ) + + // When val response = inAppMessagePreviewHandler.canReceiveNotification(jsonObject) - /* Then */ + // Then response shouldBe false coVerify(exactly = 1) { mockNotificationDisplayer.displayNotification(any()) } } test("canReceiveNotification returns true when notification does not have an IAM preview id") { - /* Given */ + // Given val mockInAppDisplayer = mockk() val mockNotificationDisplayer = mockk() val mockNotificationActivityOpener = mockk() @@ -128,35 +132,37 @@ class InAppMessagePreviewHandlerTests : FunSpec({ val stateService = InAppStateService() - val inAppMessagePreviewHandler = InAppMessagePreviewHandler( - mockInAppDisplayer, - mockApplicationService, - mockNotificationDisplayer, - mockNotificationActivityOpener, - mockNotificationLifecycleService, - stateService, - MockHelper.time(1111), - ) - - val jsonObject = JSONObject() - .put( - "custom", - JSONObject() - .put( - "a", - JSONObject(), - ), + val inAppMessagePreviewHandler = + InAppMessagePreviewHandler( + mockInAppDisplayer, + mockApplicationService, + mockNotificationDisplayer, + mockNotificationActivityOpener, + mockNotificationLifecycleService, + stateService, + MockHelper.time(1111), ) - /* When */ + val jsonObject = + JSONObject() + .put( + "custom", + JSONObject() + .put( + "a", + JSONObject(), + ), + ) + + // When val response = inAppMessagePreviewHandler.canReceiveNotification(jsonObject) - /* Then */ + // Then response shouldBe true } test("canOpenNotification displays IAM and returns false when notification has a IAM preview id") { - /* Given */ + // Given val mockInAppDisplayer = mockk() coEvery { mockInAppDisplayer.displayPreviewMessage(any()) } returns true val mockNotificationDisplayer = mockk() @@ -167,37 +173,39 @@ class InAppMessagePreviewHandlerTests : FunSpec({ val stateService = InAppStateService() - val inAppMessagePreviewHandler = InAppMessagePreviewHandler( - mockInAppDisplayer, - mockApplicationService, - mockNotificationDisplayer, - mockNotificationActivityOpener, - mockNotificationLifecycleService, - stateService, - MockHelper.time(1111), - ) - - val jsonObject = JSONObject() - .put( - "custom", - JSONObject() - .put( - "a", - JSONObject() - .put("os_in_app_message_preview_id", "previewUUID"), - ), + val inAppMessagePreviewHandler = + InAppMessagePreviewHandler( + mockInAppDisplayer, + mockApplicationService, + mockNotificationDisplayer, + mockNotificationActivityOpener, + mockNotificationLifecycleService, + stateService, + MockHelper.time(1111), ) + val jsonObject = + JSONObject() + .put( + "custom", + JSONObject() + .put( + "a", + JSONObject() + .put("os_in_app_message_preview_id", "previewUUID"), + ), + ) + val activity: Activity Robolectric.buildActivity(Activity::class.java).use { controller -> controller.setup() // Moves Activity to RESUMED state activity = controller.get() } - /* When */ + // When val response = inAppMessagePreviewHandler.canOpenNotification(activity, jsonObject) - /* Then */ + // Then response shouldBe false coVerify(exactly = 1) { mockNotificationActivityOpener.openDestinationActivity( @@ -212,7 +220,7 @@ class InAppMessagePreviewHandlerTests : FunSpec({ } test("canOpenNotification returns true when notification has no IAM preview id") { - /* Given */ + // Given val mockInAppDisplayer = mockk() val mockNotificationDisplayer = mockk() val mockNotificationActivityOpener = mockk() @@ -221,36 +229,38 @@ class InAppMessagePreviewHandlerTests : FunSpec({ val stateService = InAppStateService() - val inAppMessagePreviewHandler = InAppMessagePreviewHandler( - mockInAppDisplayer, - mockApplicationService, - mockNotificationDisplayer, - mockNotificationActivityOpener, - mockNotificationLifecycleService, - stateService, - MockHelper.time(1111), - ) - - val jsonObject = JSONObject() - .put( - "custom", - JSONObject() - .put( - "a", - JSONObject(), - ), + val inAppMessagePreviewHandler = + InAppMessagePreviewHandler( + mockInAppDisplayer, + mockApplicationService, + mockNotificationDisplayer, + mockNotificationActivityOpener, + mockNotificationLifecycleService, + stateService, + MockHelper.time(1111), ) + val jsonObject = + JSONObject() + .put( + "custom", + JSONObject() + .put( + "a", + JSONObject(), + ), + ) + val activity: Activity Robolectric.buildActivity(Activity::class.java).use { controller -> controller.setup() // Moves Activity to RESUMED state activity = controller.get() } - /* When */ + // When val response = inAppMessagePreviewHandler.canOpenNotification(activity, jsonObject) - /* Then */ + // Then response shouldBe true } }) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/repositories/InAppRepositoryTests.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/repositories/InAppRepositoryTests.kt index 0bc0cc5ee7..a510937b46 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/repositories/InAppRepositoryTests.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/internal/repositories/InAppRepositoryTests.kt @@ -24,46 +24,47 @@ class InAppRepositoryTests : FunSpec({ } test("listInAppMessages returns empty list when database is empty") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(OneSignalDbContract.InAppMessageTable.TABLE_NAME) val mockInAppPreferencesController = mockk() val inAppRepository = InAppRepository(mockDatabasePair.first, MockHelper.time(1111), mockInAppPreferencesController) - /* When */ + // When val response = inAppRepository.listInAppMessages() - /* Then */ + // Then response.count() shouldBe 0 } test("listInAppMessages returns list of in app messages in database") { - /* Given */ - val records = listOf( - mapOf( - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID to "messageId1", - OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS to "[clickId1, clickId2]", - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_DISPLAY_QUANTITY to 1, - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_LAST_DISPLAY to 1000L, - OneSignalDbContract.InAppMessageTable.COLUMN_DISPLAYED_IN_SESSION to 1, - ), - mapOf( - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID to "messageId2", - OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS to "[clickId3, clickId4]", - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_DISPLAY_QUANTITY to 2, - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_LAST_DISPLAY to 1100L, - OneSignalDbContract.InAppMessageTable.COLUMN_DISPLAYED_IN_SESSION to 0, - ), - ) + // Given + val records = + listOf( + mapOf( + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID to "messageId1", + OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS to "[clickId1, clickId2]", + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_DISPLAY_QUANTITY to 1, + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_LAST_DISPLAY to 1000L, + OneSignalDbContract.InAppMessageTable.COLUMN_DISPLAYED_IN_SESSION to 1, + ), + mapOf( + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID to "messageId2", + OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS to "[clickId3, clickId4]", + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_DISPLAY_QUANTITY to 2, + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_LAST_DISPLAY to 1100L, + OneSignalDbContract.InAppMessageTable.COLUMN_DISPLAYED_IN_SESSION to 0, + ), + ) val mockDatabasePair = DatabaseMockHelper.databaseProvider(OneSignalDbContract.InAppMessageTable.TABLE_NAME, records) val mockInAppPreferencesController = mockk() val inAppRepository = InAppRepository(mockDatabasePair.first, MockHelper.time(1111), mockInAppPreferencesController) - /* When */ + // When val response = inAppRepository.listInAppMessages() - /* Then */ + // Then response.count() shouldBe 2 response[0].messageId shouldBe "messageId1" response[0].clickedClickIds shouldBe setOf("clickId1", "clickId2") @@ -78,17 +79,17 @@ class InAppRepositoryTests : FunSpec({ } test("cleanCachedInAppMessages is a no-op when no older messages") { - /* Given */ + // Given val mockDatabasePair = DatabaseMockHelper.databaseProvider(OneSignalDbContract.InAppMessageTable.TABLE_NAME) val mockInAppPreferencesController = mockk() every { mockInAppPreferencesController.cleanInAppMessageIds(any()) } just runs every { mockInAppPreferencesController.cleanInAppMessageClickedClickIds(any()) } just runs val inAppRepository = InAppRepository(mockDatabasePair.first, MockHelper.time(1111), mockInAppPreferencesController) - /* When */ + // When inAppRepository.cleanCachedInAppMessages() - /* Then */ + // Then verify { mockInAppPreferencesController.cleanInAppMessageIds( withArg { @@ -107,27 +108,28 @@ class InAppRepositoryTests : FunSpec({ } test("cleanCachedInAppMessages cleans all old messages and clicks") { - /* Given */ - val records = listOf( - mapOf( - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID to "messageId1", - OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS to "[clickId1, clickId2]", - ), - mapOf( - OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID to "messageId2", - OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS to "[clickId3, clickId4]", - ), - ) + // Given + val records = + listOf( + mapOf( + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID to "messageId1", + OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS to "[clickId1, clickId2]", + ), + mapOf( + OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID to "messageId2", + OneSignalDbContract.InAppMessageTable.COLUMN_CLICK_IDS to "[clickId3, clickId4]", + ), + ) val mockDatabasePair = DatabaseMockHelper.databaseProvider(OneSignalDbContract.InAppMessageTable.TABLE_NAME, records) val mockInAppPreferencesController = mockk() every { mockInAppPreferencesController.cleanInAppMessageIds(any()) } just runs every { mockInAppPreferencesController.cleanInAppMessageClickedClickIds(any()) } just runs val inAppRepository = InAppRepository(mockDatabasePair.first, MockHelper.time(1111), mockInAppPreferencesController) - /* When */ + // When inAppRepository.cleanCachedInAppMessages() - /* Then */ + // Then verify { mockInAppPreferencesController.cleanInAppMessageIds( withArg { diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/AndroidMockHelper.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/AndroidMockHelper.kt index 0190de8bb9..7a1e4ebc6a 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/AndroidMockHelper.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/AndroidMockHelper.kt @@ -8,7 +8,6 @@ import io.mockk.every * Singleton which provides common mock services when running in an Android environment. */ internal object AndroidMockHelper { - fun applicationService(): IApplicationService { val mockAppService = MockHelper.applicationService() diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/DatabaseMockHelper.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/DatabaseMockHelper.kt index dde65a6405..b962ff6b25 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/DatabaseMockHelper.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/DatabaseMockHelper.kt @@ -11,7 +11,10 @@ import io.mockk.spyk * Singleton which provides common mock services. */ internal object DatabaseMockHelper { - fun databaseProvider(tableName: String, records: List>? = null): Pair { + fun databaseProvider( + tableName: String, + records: List>? = null, + ): Pair { val mockOneSignalDatabase = spyk() if (records != null) { @@ -33,8 +36,14 @@ internal object DatabaseMockHelper { val mockCursor = mockk() var index = 0 every { mockCursor.count } returns records.count() - every { mockCursor.moveToFirst() } answers { index = 0; true } - every { mockCursor.moveToNext() } answers { index++; index < records.count() } + every { mockCursor.moveToFirst() } answers { + index = 0 + true + } + every { mockCursor.moveToNext() } answers { + index++ + index < records.count() + } every { mockCursor.getString(any()) } answers { records[index][firstArg()] as String } every { mockCursor.getFloat(any()) } answers { records[index][firstArg()] as Float } every { mockCursor.getLong(any()) } answers { records[index][firstArg()] as Long } diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/MockHelper.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/MockHelper.kt index 9ed4c39753..55715596cc 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/MockHelper.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/MockHelper.kt @@ -40,6 +40,7 @@ object MockHelper { } const val DEFAULT_APP_ID = "appId" + fun configModelStore(action: ((ConfigModel) -> Unit)? = null): ConfigModelStore { val configModel = ConfigModel() diff --git a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/MockPreferencesService.kt b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/MockPreferencesService.kt index ccf0a13b5c..a5bf374599 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/MockPreferencesService.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/test/java/com/onesignal/inAppMessages/mocks/MockPreferencesService.kt @@ -7,17 +7,75 @@ import com.onesignal.core.internal.preferences.IPreferencesService * and will return any saved value in memory. */ internal class MockPreferencesService(map: Map? = null) : IPreferencesService { - private val _map: MutableMap = map?.toMutableMap() ?: mutableMapOf() - - override fun getString(store: String, key: String, defValue: String?): String? = (_map[key] as String?) ?: defValue - override fun getBool(store: String, key: String, defValue: Boolean?): Boolean? = (_map[key] as Boolean?) ?: defValue - override fun getInt(store: String, key: String, defValue: Int?): Int? = (_map[key] as Int?) ?: defValue - override fun getLong(store: String, key: String, defValue: Long?): Long? = (_map[key] as Long?) ?: defValue - override fun getStringSet(store: String, key: String, defValue: Set?): Set? = (_map[key] as Set?) ?: defValue - - override fun saveString(store: String, key: String, value: String?) { _map[key] = value } - override fun saveBool(store: String, key: String, value: Boolean?) { _map[key] = value } - override fun saveInt(store: String, key: String, value: Int?) { _map[key] = value } - override fun saveLong(store: String, key: String, value: Long?) { _map[key] = value } - override fun saveStringSet(store: String, key: String, value: Set?) { _map[key] = value } + private val map: MutableMap = map?.toMutableMap() ?: mutableMapOf() + + override fun getString( + store: String, + key: String, + defValue: String?, + ): String? = (map[key] as String?) ?: defValue + + override fun getBool( + store: String, + key: String, + defValue: Boolean?, + ): Boolean? = (map[key] as Boolean?) ?: defValue + + override fun getInt( + store: String, + key: String, + defValue: Int?, + ): Int? = (map[key] as Int?) ?: defValue + + override fun getLong( + store: String, + key: String, + defValue: Long?, + ): Long? = (map[key] as Long?) ?: defValue + + override fun getStringSet( + store: String, + key: String, + defValue: Set?, + ): Set? = (map[key] as Set?) ?: defValue + + override fun saveString( + store: String, + key: String, + value: String?, + ) { + map[key] = value + } + + override fun saveBool( + store: String, + key: String, + value: Boolean?, + ) { + map[key] = value + } + + override fun saveInt( + store: String, + key: String, + value: Int?, + ) { + map[key] = value + } + + override fun saveLong( + store: String, + key: String, + value: Long?, + ) { + map[key] = value + } + + override fun saveStringSet( + store: String, + key: String, + value: Set?, + ) { + map[key] = value + } } diff --git a/OneSignalSDK/onesignal/location/build.gradle b/OneSignalSDK/onesignal/location/build.gradle index ca18e76bda..00f31eb7bf 100644 --- a/OneSignalSDK/onesignal/location/build.gradle +++ b/OneSignalSDK/onesignal/location/build.gradle @@ -93,6 +93,9 @@ dependencies { ktlint { version = "$ktlintVersion" + additionalEditorconfig = [ + "max_line_length": "500", + ] } apply from: '../maven-push.gradle' \ No newline at end of file diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/LocationModule.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/LocationModule.kt index 2ea152c3ae..6a4a3bdcd4 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/LocationModule.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/LocationModule.kt @@ -27,13 +27,14 @@ internal class LocationModule : IModule { builder.register { val deviceService = it.getService(IDeviceService::class.java) - val service = if (deviceService.isAndroidDeviceType && LocationUtils.hasGMSLocationLibrary()) { - GmsLocationController(it.getService(IApplicationService::class.java)) - } else if (deviceService.isHuaweiDeviceType && LocationUtils.hasHMSLocationLibrary()) { - HmsLocationController(it.getService(IApplicationService::class.java)) - } else { - NullLocationController() - } + val service = + if (deviceService.isAndroidDeviceType && LocationUtils.hasGMSLocationLibrary()) { + GmsLocationController(it.getService(IApplicationService::class.java)) + } else if (deviceService.isHuaweiDeviceType && LocationUtils.hasHMSLocationLibrary()) { + HmsLocationController(it.getService(IApplicationService::class.java)) + } else { + NullLocationController() + } return@register service }.provides() diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/LocationManager.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/LocationManager.kt index b0996b6648..de25bbead8 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/LocationManager.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/LocationManager.kt @@ -23,7 +23,6 @@ internal class LocationManager( private val _locationController: ILocationController, private val _locationPermissionController: LocationPermissionController, ) : ILocationManager, IStartableService, ILocationPermissionChangedHandler { - private var _isShared: Boolean = false override var isShared get() = _isShared @@ -75,7 +74,12 @@ internal class LocationManager( return@withContext false } - val hasFinePermissionGranted = AndroidUtils.hasPermission(LocationConstants.ANDROID_FINE_LOCATION_PERMISSION_STRING, true, _applicationService) + val hasFinePermissionGranted = + AndroidUtils.hasPermission( + LocationConstants.ANDROID_FINE_LOCATION_PERMISSION_STRING, + true, + _applicationService, + ) var hasCoarsePermissionGranted: Boolean = false var hasBackgroundPermissionGranted: Boolean = false @@ -100,14 +104,15 @@ internal class LocationManager( } else { // Android 6.0+ if (!hasFinePermissionGranted) { var requestPermission: String? = null - var permissionList = AndroidUtils.filterManifestPermissions( - listOf( - LocationConstants.ANDROID_FINE_LOCATION_PERMISSION_STRING, - LocationConstants.ANDROID_COARSE_LOCATION_PERMISSION_STRING, - LocationConstants.ANDROID_BACKGROUND_LOCATION_PERMISSION_STRING, - ), - _applicationService, - ) + var permissionList = + AndroidUtils.filterManifestPermissions( + listOf( + LocationConstants.ANDROID_FINE_LOCATION_PERMISSION_STRING, + LocationConstants.ANDROID_COARSE_LOCATION_PERMISSION_STRING, + LocationConstants.ANDROID_BACKGROUND_LOCATION_PERMISSION_STRING, + ), + _applicationService, + ) if (permissionList.contains(LocationConstants.ANDROID_FINE_LOCATION_PERMISSION_STRING)) { // ACCESS_FINE_LOCATION permission defined on Manifest, prompt for permission @@ -133,11 +138,12 @@ internal class LocationManager( // 3 - If permission wasn't granted then trigger fail flow // // For each case, we call the prompt handlers - result = if (requestPermission != null) { - _locationPermissionController.prompt(true, requestPermission) - } else { - hasCoarsePermissionGranted - } + result = + if (requestPermission != null) { + _locationPermissionController.prompt(true, requestPermission) + } else { + hasCoarsePermissionGranted + } } else if (Build.VERSION.SDK_INT >= 29 && !hasBackgroundPermissionGranted) { result = backgroundLocationPermissionLogic(true) } else { @@ -156,7 +162,12 @@ internal class LocationManager( * If background permission is asked at the same time as fine and coarse then both permission request are ignored */ private suspend fun backgroundLocationPermissionLogic(fallbackToSettings: Boolean): Boolean { - val hasManifestPermission = AndroidUtils.hasPermission(LocationConstants.ANDROID_BACKGROUND_LOCATION_PERMISSION_STRING, false, _applicationService) + val hasManifestPermission = + AndroidUtils.hasPermission( + LocationConstants.ANDROID_BACKGROUND_LOCATION_PERMISSION_STRING, + false, + _applicationService, + ) return if (hasManifestPermission) { _locationPermissionController.prompt(fallbackToSettings, LocationConstants.ANDROID_BACKGROUND_LOCATION_PERMISSION_STRING) diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/capture/ILocationCapturer.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/capture/ILocationCapturer.kt index 6300498e8e..4dd893446d 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/capture/ILocationCapturer.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/capture/ILocationCapturer.kt @@ -2,5 +2,6 @@ package com.onesignal.location.internal.capture internal interface ILocationCapturer { var locationCoarse: Boolean + fun captureLastLocation() } diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/capture/impl/LocationCapturer.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/capture/impl/LocationCapturer.kt index 0b5d8c292b..7d1efdd2d5 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/capture/impl/LocationCapturer.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/capture/impl/LocationCapturer.kt @@ -20,7 +20,6 @@ internal class LocationCapturer( private val _propertiesModelStore: PropertiesModelStore, private val _controller: ILocationController, ) : ILocationUpdatedHandler, ILocationCapturer { - override var locationCoarse: Boolean = false init { diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/common/LocationPoint.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/common/LocationPoint.kt index 07f8cbe77f..5efc47a6af 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/common/LocationPoint.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/common/LocationPoint.kt @@ -7,6 +7,7 @@ internal class LocationPoint { var type: Int? = null var bg: Boolean? = null var timeStamp: Long? = null + override fun toString(): String { return "LocationPoint{" + "lat=" + lat + diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/common/LocationUtils.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/common/LocationUtils.kt index 4b159a492d..a69305bca8 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/common/LocationUtils.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/common/LocationUtils.kt @@ -28,6 +28,6 @@ internal object LocationUtils { return ( ContextCompat.checkSelfPermission(context, "android.permission.ACCESS_FINE_LOCATION") === PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(context, "android.permission.ACCESS_COARSE_LOCATION") === PackageManager.PERMISSION_GRANTED - ) + ) } } diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/ILocationController.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/ILocationController.kt index c038635038..4f45e53672 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/ILocationController.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/ILocationController.kt @@ -5,6 +5,7 @@ import com.onesignal.common.events.IEventNotifier internal interface ILocationController : IEventNotifier { suspend fun start(): Boolean + suspend fun stop() fun getLastLocation(): Location? diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt index 54a3ea8622..8a0645de09 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt @@ -30,26 +30,26 @@ import java.io.Closeable internal class GmsLocationController( private val _applicationService: IApplicationService, ) : ILocationController { - private val _locationHandlerThread = LocationHandlerThread() - private val _startStopMutex = Mutex() - private val _event = EventProducer() + private val locationHandlerThread = LocationHandlerThread() + private val startStopMutex = Mutex() + private val event = EventProducer() // exist after start and before stop. updates are protected by the startStopMutex - private var _googleApiClient: GoogleApiClientCompatProxy? = null - private var _locationUpdateListener: LocationUpdateListener? = null + private var googleApiClient: GoogleApiClientCompatProxy? = null + private var locationUpdateListener: LocationUpdateListener? = null // contains the last location received from location services - private var _lastLocation: Location? = null + private var lastLocation: Location? = null override suspend fun start(): Boolean { var self = this var wasSuccessful = false withContext(Dispatchers.IO) { - _startStopMutex.withLock { - if (_googleApiClient != null) { - if (_lastLocation != null) { - _event.fire { it.onLocationChanged(_lastLocation!!) } + startStopMutex.withLock { + if (googleApiClient != null) { + if (lastLocation != null) { + event.fire { it.onLocationChanged(lastLocation!!) } } else { val localLastLocation = getLastLocation() if (localLastLocation != null) { @@ -66,7 +66,7 @@ internal class GmsLocationController( .addApi(LocationServices.API) .addConnectionCallbacks(googleApiClientListener) .addOnConnectionFailedListener(googleApiClientListener) - .setHandler(_locationHandlerThread.mHandler) + .setHandler(locationHandlerThread.mHandler) .build() var proxyGoogleApiClient = GoogleApiClientCompatProxy(googleApiClient) @@ -74,7 +74,7 @@ internal class GmsLocationController( var result = proxyGoogleApiClient.blockingConnect() if (result?.isSuccess == true) { - if (_lastLocation == null) { + if (lastLocation == null) { var lastLocation = FusedLocationApiWrapper.getLastLocation(googleApiClient) if (lastLocation != null) { setLocationAndFire(lastLocation) @@ -82,15 +82,19 @@ internal class GmsLocationController( } // only after the connect do we save - self._locationUpdateListener = LocationUpdateListener(_applicationService, self, proxyGoogleApiClient.realInstance) - self._googleApiClient = proxyGoogleApiClient + self.locationUpdateListener = LocationUpdateListener(_applicationService, self, proxyGoogleApiClient.realInstance) + self.googleApiClient = proxyGoogleApiClient wasSuccessful = true } else { - Logging.debug("GMSLocationController connection to GoogleApiService failed: (${result?.errorCode}) ${result?.errorMessage}") + Logging.debug( + "GMSLocationController connection to GoogleApiService failed: (${result?.errorCode}) ${result?.errorMessage}", + ) } } } catch (e: TimeoutCancellationException) { - Logging.warn("Location permission exists but GoogleApiClient timed out. Maybe related to mismatch google-play aar versions.") + Logging.warn( + "Location permission exists but GoogleApiClient timed out. Maybe related to mismatch google-play aar versions.", + ) } } } @@ -100,37 +104,39 @@ internal class GmsLocationController( } override suspend fun stop() { - _startStopMutex.withLock { - if (_locationUpdateListener != null) { - _locationUpdateListener!!.close() - _locationUpdateListener = null + startStopMutex.withLock { + if (locationUpdateListener != null) { + locationUpdateListener!!.close() + locationUpdateListener = null } - if (_googleApiClient != null) { - _googleApiClient!!.disconnect() - _googleApiClient = null + if (googleApiClient != null) { + googleApiClient!!.disconnect() + googleApiClient = null } - _lastLocation = null + lastLocation = null } } override fun getLastLocation(): Location? { - val apiInstance = _googleApiClient?.realInstance ?: return null + val apiInstance = googleApiClient?.realInstance ?: return null return FusedLocationApiWrapper.getLastLocation(apiInstance) } - override fun subscribe(handler: ILocationUpdatedHandler) = _event.subscribe(handler) - override fun unsubscribe(handler: ILocationUpdatedHandler) = _event.unsubscribe(handler) + override fun subscribe(handler: ILocationUpdatedHandler) = event.subscribe(handler) + + override fun unsubscribe(handler: ILocationUpdatedHandler) = event.unsubscribe(handler) + override val hasSubscribers: Boolean - get() = _event.hasSubscribers + get() = event.hasSubscribers private fun setLocationAndFire(location: Location) { - Logging.debug("GMSLocationController lastLocation: $_lastLocation") + Logging.debug("GMSLocationController lastLocation: $lastLocation") - _lastLocation = location + lastLocation = location - _event.fire { it.onLocationChanged(location) } + event.fire { it.onLocationChanged(location) } } private class GoogleApiClientListener(private val _parent: GmsLocationController) : GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { @@ -157,7 +163,6 @@ internal class GmsLocationController( private val _parent: GmsLocationController, private val googleApiClient: GoogleApiClient, ) : LocationListener, IApplicationLifecycleHandler, Closeable { - private var hasExistingRequest = false init { @@ -197,17 +202,19 @@ internal class GmsLocationController( FusedLocationApiWrapper.cancelLocationUpdates(googleApiClient, this) } - val updateInterval = if (_applicationService.isInForeground) { - LocationConstants.FOREGROUND_UPDATE_TIME_MS - } else { - LocationConstants.BACKGROUND_UPDATE_TIME_MS - } + val updateInterval = + if (_applicationService.isInForeground) { + LocationConstants.FOREGROUND_UPDATE_TIME_MS + } else { + LocationConstants.BACKGROUND_UPDATE_TIME_MS + } - val locationRequest = LocationRequest.create() - .setFastestInterval(updateInterval) - .setInterval(updateInterval) - .setMaxWaitTime((updateInterval * 1.5).toLong()) - .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) + val locationRequest = + LocationRequest.create() + .setFastestInterval(updateInterval) + .setInterval(updateInterval) + .setMaxWaitTime((updateInterval * 1.5).toLong()) + .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) Logging.debug("GMSLocationController GoogleApiClient requestLocationUpdates!") FusedLocationApiWrapper.requestLocationUpdates(googleApiClient, locationRequest, this) hasExistingRequest = true @@ -220,11 +227,18 @@ internal class GmsLocationController( } internal object FusedLocationApiWrapper { - fun cancelLocationUpdates(googleApiClient: GoogleApiClient, locationListener: LocationListener) { + fun cancelLocationUpdates( + googleApiClient: GoogleApiClient, + locationListener: LocationListener, + ) { LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, locationListener) } - fun requestLocationUpdates(googleApiClient: GoogleApiClient, locationRequest: LocationRequest, locationListener: LocationListener) { + fun requestLocationUpdates( + googleApiClient: GoogleApiClient, + locationRequest: LocationRequest, + locationListener: LocationListener, + ) { try { if (Looper.myLooper() == null) { Looper.prepare() @@ -247,13 +261,13 @@ internal class GmsLocationController( protected class LocationHandlerThread internal constructor() : HandlerThread("OSH_LocationHandlerThread") { - var mHandler: Handler + var mHandler: Handler - init { - start() - mHandler = Handler(looper) + init { + start() + mHandler = Handler(looper) + } } - } companion object { val API_FALLBACK_TIME = 30000 diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GoogleApiClientCompatProxy.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GoogleApiClientCompatProxy.kt index f2be4ae52e..3464d62027 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GoogleApiClientCompatProxy.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GoogleApiClientCompatProxy.kt @@ -34,7 +34,6 @@ import com.google.android.gms.common.api.GoogleApiClient internal class GoogleApiClientCompatProxy( val realInstance: GoogleApiClient, ) { - private val googleApiClientListenerClass: Class<*> = realInstance.javaClass fun blockingConnect(): ConnectionResult? { diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/HmsLocationController.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/HmsLocationController.kt index 3a7c6237ed..19adab61d3 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/HmsLocationController.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/HmsLocationController.kt @@ -28,23 +28,23 @@ import java.io.Closeable internal class HmsLocationController( private val _applicationService: IApplicationService, ) : ILocationController { - private val _locationHandlerThread = LocationHandlerThread() - private val _startStopMutex = Mutex() - private val _event = EventProducer() + private val locationHandlerThread = LocationHandlerThread() + private val startStopMutex = Mutex() + private val event = EventProducer() // exist after start and before stop. updates are protected by the startStopMutex private var hmsFusedLocationClient: FusedLocationProviderClient? = null private var locationUpdateListener: LocationUpdateListener? = null // contains the last location received from location services - private var _lastLocation: Location? = null + private var lastLocation: Location? = null override suspend fun start(): Boolean { var self = this var wasSuccessful = false withContext(Dispatchers.IO) { - _startStopMutex.withLock { + startStopMutex.withLock { if (hmsFusedLocationClient == null) { try { hmsFusedLocationClient = @@ -56,8 +56,8 @@ internal class HmsLocationController( } } - if (_lastLocation != null) { - _event.fire { it.onLocationChanged(_lastLocation!!) } + if (lastLocation != null) { + event.fire { it.onLocationChanged(lastLocation!!) } } else { var waiter = WaiterWithValue() hmsFusedLocationClient!!.lastLocation @@ -70,7 +70,7 @@ internal class HmsLocationController( return@OnSuccessListener } - _lastLocation = location + lastLocation = location waiter.wake(true) }, ) @@ -81,12 +81,13 @@ internal class HmsLocationController( wasSuccessful = waiter.waitForWake() if (wasSuccessful) { - _event.fire { it.onLocationChanged(_lastLocation!!) } - locationUpdateListener = LocationUpdateListener( - self, - _applicationService, - hmsFusedLocationClient!!, - ) + event.fire { it.onLocationChanged(lastLocation!!) } + locationUpdateListener = + LocationUpdateListener( + self, + _applicationService, + hmsFusedLocationClient!!, + ) } } } @@ -96,7 +97,7 @@ internal class HmsLocationController( } override suspend fun stop() { - _startStopMutex.withLock { + startStopMutex.withLock { if (locationUpdateListener != null) { locationUpdateListener!!.close() locationUpdateListener = null @@ -106,7 +107,7 @@ internal class HmsLocationController( hmsFusedLocationClient = null } - _lastLocation = null + lastLocation = null } } @@ -141,17 +142,18 @@ internal class HmsLocationController( return retVal } - override fun subscribe(handler: ILocationUpdatedHandler) = _event.subscribe(handler) - override fun unsubscribe(handler: ILocationUpdatedHandler) = _event.unsubscribe(handler) + override fun subscribe(handler: ILocationUpdatedHandler) = event.subscribe(handler) + + override fun unsubscribe(handler: ILocationUpdatedHandler) = event.unsubscribe(handler) + override val hasSubscribers: Boolean - get() = _event.hasSubscribers + get() = event.hasSubscribers internal class LocationUpdateListener( private val _parent: HmsLocationController, private val _applicationService: IApplicationService, private val huaweiFusedLocationProviderClient: FusedLocationProviderClient, ) : LocationCallback(), IApplicationLifecycleHandler, Closeable { - private var hasExistingRequest = false init { @@ -179,7 +181,7 @@ internal class HmsLocationController( override fun onLocationResult(locationResult: LocationResult) { Logging.debug("HMSLocationController onLocationResult: $locationResult") - _parent._lastLocation = locationResult.lastLocation + _parent.lastLocation = locationResult.lastLocation } private fun refreshRequest() { @@ -192,16 +194,17 @@ internal class HmsLocationController( updateInterval = LocationConstants.FOREGROUND_UPDATE_TIME_MS } - val locationRequest = LocationRequest.create() - .setFastestInterval(updateInterval) - .setInterval(updateInterval) - .setMaxWaitTime((updateInterval * 1.5).toLong()) - .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) + val locationRequest = + LocationRequest.create() + .setFastestInterval(updateInterval) + .setInterval(updateInterval) + .setMaxWaitTime((updateInterval * 1.5).toLong()) + .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) Logging.debug("HMSLocationController Huawei LocationServices requestLocationUpdates!") huaweiFusedLocationProviderClient.requestLocationUpdates( locationRequest, this, - _parent._locationHandlerThread.looper, + _parent.locationHandlerThread.looper, ) hasExistingRequest = true } @@ -209,11 +212,11 @@ internal class HmsLocationController( class LocationHandlerThread internal constructor() : HandlerThread("OSH_LocationHandlerThread") { - var mHandler: Handler + var mHandler: Handler - init { - start() - mHandler = Handler(looper) + init { + start() + mHandler = Handler(looper) + } } - } } diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/NullLocationController.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/NullLocationController.kt index c5e3e6efe7..2aba863e81 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/NullLocationController.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/NullLocationController.kt @@ -8,11 +8,18 @@ import com.onesignal.location.internal.controller.ILocationUpdatedHandler * This location controller is used when the device doesn't support location services. */ internal class NullLocationController : ILocationController { - override suspend fun start(): Boolean { return false } + override suspend fun start(): Boolean { + return false + } + override suspend fun stop() {} + override fun getLastLocation(): Location? = null + override fun subscribe(handler: ILocationUpdatedHandler) {} + override fun unsubscribe(handler: ILocationUpdatedHandler) {} + override val hasSubscribers: Boolean get() = false } diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/permissions/LocationPermissionController.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/permissions/LocationPermissionController.kt index c2494b7b2c..4acc34278c 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/permissions/LocationPermissionController.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/permissions/LocationPermissionController.kt @@ -52,16 +52,19 @@ internal class LocationPermissionController( private const val PERMISSION_TYPE = "LOCATION" } - private val _waiter = WaiterWithValue() - private val _events = EventProducer() - private var _currPermission: String = "" + private val waiter = WaiterWithValue() + private val events = EventProducer() + private var currPermission: String = "" override fun start() { _requestPermission.registerAsCallback(PERMISSION_TYPE, this) } - suspend fun prompt(fallbackToSettings: Boolean, androidPermissionString: String): Boolean { - _currPermission = androidPermissionString + suspend fun prompt( + fallbackToSettings: Boolean, + androidPermissionString: String, + ): Boolean { + currPermission = androidPermissionString _requestPermission.startPrompt( fallbackToSettings, PERMISSION_TYPE, @@ -71,12 +74,12 @@ internal class LocationPermissionController( // this won't return until onAccept or onReject sends the response on the channel (either // through the native prompt or through the fallback) - return _waiter.waitForWake() + return waiter.waitForWake() } override fun onAccept() { - _waiter.wake(true) - _events.fire { it.onLocationPermissionChanged(true) } + waiter.wake(true) + events.fire { it.onLocationPermissionChanged(true) } } override fun onReject(fallbackToSettings: Boolean) { @@ -88,8 +91,8 @@ internal class LocationPermissionController( } if (!fallbackShown) { - _waiter.wake(false) - _events.fire { it.onLocationPermissionChanged(false) } + waiter.wake(false) + events.fire { it.onLocationPermissionChanged(false) } } } @@ -102,28 +105,33 @@ internal class LocationPermissionController( object : AlertDialogPrepromptForAndroidSettings.Callback { override fun onAccept() { // wait for focus to be regained, and check the current permission status. - _applicationService.addApplicationLifecycleHandler(object : ApplicationLifecycleHandlerBase() { - override fun onFocus() { - super.onFocus() - _applicationService.removeApplicationLifecycleHandler(this) - val hasPermission = AndroidUtils.hasPermission(_currPermission, true, _applicationService) - _waiter.wake(hasPermission) - _events.fire { it.onLocationPermissionChanged(hasPermission) } - } - }) + _applicationService.addApplicationLifecycleHandler( + object : ApplicationLifecycleHandlerBase() { + override fun onFocus() { + super.onFocus() + _applicationService.removeApplicationLifecycleHandler(this) + val hasPermission = AndroidUtils.hasPermission(currPermission, true, _applicationService) + waiter.wake(hasPermission) + events.fire { it.onLocationPermissionChanged(hasPermission) } + } + }, + ) NavigateToAndroidSettingsForLocation.show(activity) } + override fun onDecline() { - _waiter.wake(false) - _events.fire { it.onLocationPermissionChanged(false) } + waiter.wake(false) + events.fire { it.onLocationPermissionChanged(false) } } }, ) return true } - override fun subscribe(handler: ILocationPermissionChangedHandler) = _events.subscribe(handler) - override fun unsubscribe(handler: ILocationPermissionChangedHandler) = _events.subscribe(handler) + override fun subscribe(handler: ILocationPermissionChangedHandler) = events.subscribe(handler) + + override fun unsubscribe(handler: ILocationPermissionChangedHandler) = events.subscribe(handler) + override val hasSubscribers: Boolean - get() = _events.hasSubscribers + get() = events.hasSubscribers } diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/preferences/impl/LocationPreferencesService.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/preferences/impl/LocationPreferencesService.kt index d57fa6870c..509123b9c6 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/preferences/impl/LocationPreferencesService.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/preferences/impl/LocationPreferencesService.kt @@ -10,7 +10,12 @@ internal class LocationPreferencesService( private val _prefs: IPreferencesService, ) : ILocationPreferencesService { override var lastLocationTime: Long - get() = _prefs.getLong(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.PREFS_OS_LAST_LOCATION_TIME, LocationConstants.TIME_BACKGROUND_SEC * -1000)!! + get() = + _prefs.getLong( + PreferenceStores.ONESIGNAL, + PreferenceOneSignalKeys.PREFS_OS_LAST_LOCATION_TIME, + LocationConstants.TIME_BACKGROUND_SEC * -1000, + )!! set(time) { _prefs.saveLong( PreferenceStores.ONESIGNAL, diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/ContainedRobolectricRunner.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/ContainedRobolectricRunner.kt index ab3f0f4dd4..fa722e93ad 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/ContainedRobolectricRunner.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/ContainedRobolectricRunner.kt @@ -17,11 +17,13 @@ internal class ContainedRobolectricRunner( private val config: Config?, ) : RobolectricTestRunner(PlaceholderTest::class.java, injector) { private val placeHolderMethod: FrameworkMethod = children[0] - val sdkEnvironment = getSandbox(placeHolderMethod).also { - configureSandbox(it, placeHolderMethod) - } - private val bootStrapMethod = sdkEnvironment.bootstrappedClass(testClass.javaClass) - .getMethod(PlaceholderTest::bootStrapMethod.name) + val sdkEnvironment = + getSandbox(placeHolderMethod).also { + configureSandbox(it, placeHolderMethod) + } + private val bootStrapMethod = + sdkEnvironment.bootstrappedClass(testClass.javaClass) + .getMethod(PlaceholderTest::bootStrapMethod.name) fun containedBefore() { Thread.currentThread().contextClassLoader = sdkEnvironment.robolectricClassLoader @@ -41,8 +43,9 @@ internal class ContainedRobolectricRunner( } override fun getConfig(method: Method?): Config { - val defaultConfiguration = injector.getInstance(ConfigurationStrategy::class.java) - .getConfig(testClass.javaClass, method) + val defaultConfiguration = + injector.getInstance(ConfigurationStrategy::class.java) + .getConfig(testClass.javaClass, method) if (config != null) { val configConfigurer = injector.getInstance(ConfigConfigurer::class.java) diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/RobolectricExtension.kt index 570e7285eb..3250906490 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/RobolectricExtension.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/extensions/RobolectricExtension.kt @@ -30,9 +30,10 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { } private fun KClass<*>.getConfig(): Config { - val configAnnotations = listOf(this.java).plus(this.java.getParentClass()) - .mapNotNull { it.kotlin.findAnnotation() } - .asSequence() + val configAnnotations = + listOf(this.java).plus(this.java.getParentClass()) + .mapNotNull { it.kotlin.findAnnotation() } + .asSequence() val configAnnotation = configAnnotations.firstOrNull() @@ -40,12 +41,14 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { return Config.Builder(configAnnotation).build() } - val robolectricTestAnnotations = listOf(this.java).plus(this.java.getParentClass()) - .mapNotNull { it.kotlin.findAnnotation() } - .asSequence() + val robolectricTestAnnotations = + listOf(this.java).plus(this.java.getParentClass()) + .mapNotNull { it.kotlin.findAnnotation() } + .asSequence() - val application: KClass? = robolectricTestAnnotations - .firstOrNull { it.application != KotestDefaultApplication::class }?.application + val application: KClass? = + robolectricTestAnnotations + .firstOrNull { it.application != KotestDefaultApplication::class }?.application val sdk: Int? = robolectricTestAnnotations.firstOrNull { it.sdk != -1 }?.takeUnless { it.sdk == -1 }?.sdk return Config.Builder() @@ -72,9 +75,10 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { execute: suspend (TestCase) -> TestResult, ): TestResult { // FIXED: Updated code based on https://github.com/kotest/kotest/issues/2717 - val hasRobolectricAnnotation = testCase.spec::class.annotations.any { annotation -> - annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName - } + val hasRobolectricAnnotation = + testCase.spec::class.annotations.any { annotation -> + annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName + } if (!hasRobolectricAnnotation) { return execute(testCase) diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/background/LocationBackgroundServiceTests.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/background/LocationBackgroundServiceTests.kt index 5d5fa53b9c..eb65a886b0 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/background/LocationBackgroundServiceTests.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/background/LocationBackgroundServiceTests.kt @@ -31,53 +31,55 @@ class LocationBackgroundServiceTests : FunSpec({ } test("backgroundRun will capture current location") { - /* Given */ + // Given val mockLocationManager = mockk() val mockLocationPreferencesService = mockk() val mockLocationCapturer = mockk() every { mockLocationCapturer.captureLastLocation() } just runs - val locationBackgroundService = LocationBackgroundService( - AndroidMockHelper.applicationService(), - mockLocationManager, - mockLocationPreferencesService, - mockLocationCapturer, - MockHelper.time(1111), - ) + val locationBackgroundService = + LocationBackgroundService( + AndroidMockHelper.applicationService(), + mockLocationManager, + mockLocationPreferencesService, + mockLocationCapturer, + MockHelper.time(1111), + ) - /* When */ + // When locationBackgroundService.backgroundRun() - /* Then */ + // Then verify(exactly = 1) { mockLocationCapturer.captureLastLocation() } } test("scheduleBackgroundRunIn will return null when location services are disabled in SDK") { - /* Given */ + // Given val mockLocationManager = mockk() every { mockLocationManager.isShared } returns false val mockLocationPreferencesService = mockk() val mockLocationCapturer = mockk() - val locationBackgroundService = LocationBackgroundService( - AndroidMockHelper.applicationService(), - mockLocationManager, - mockLocationPreferencesService, - mockLocationCapturer, - MockHelper.time(1111), - ) + val locationBackgroundService = + LocationBackgroundService( + AndroidMockHelper.applicationService(), + mockLocationManager, + mockLocationPreferencesService, + mockLocationCapturer, + MockHelper.time(1111), + ) - /* When */ + // When val result = locationBackgroundService.scheduleBackgroundRunIn - /* Then */ + // Then result shouldBe null verify(exactly = 1) { mockLocationManager.isShared } } test("scheduleBackgroundRunIn will return null when no android permissions") { - /* Given */ + // Given val mockLocationManager = mockk() every { mockLocationManager.isShared } returns true @@ -90,18 +92,19 @@ class LocationBackgroundServiceTests : FunSpec({ val app = Shadows.shadowOf(application) app.grantPermissions(Manifest.permission.ACCESS_FINE_LOCATION) - val locationBackgroundService = LocationBackgroundService( - AndroidMockHelper.applicationService(), - mockLocationManager, - mockLocationPreferencesService, - mockLocationCapturer, - MockHelper.time(2222), - ) + val locationBackgroundService = + LocationBackgroundService( + AndroidMockHelper.applicationService(), + mockLocationManager, + mockLocationPreferencesService, + mockLocationCapturer, + MockHelper.time(2222), + ) - /* When */ + // When val result = locationBackgroundService.scheduleBackgroundRunIn - /* Then */ + // Then result shouldBe (1000 * LocationConstants.TIME_BACKGROUND_SEC) - (2222 - 1111) } }) diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/capture/LocationCapturerTests.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/capture/LocationCapturerTests.kt index 92ef70aec6..d7b5f3872d 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/capture/LocationCapturerTests.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/capture/LocationCapturerTests.kt @@ -24,7 +24,7 @@ class LocationCapturerTests : FunSpec({ } test("captureLastLocation will capture current location with fine") { - /* Given */ + // Given val mockLocation = mockk() every { mockLocation.accuracy } returns 1111F every { mockLocation.time } returns 2222 @@ -43,18 +43,19 @@ class LocationCapturerTests : FunSpec({ val mockApplicationService = MockHelper.applicationService() every { mockApplicationService.isInForeground } returns true - val locationCapturer = LocationCapturer( - mockApplicationService, - MockHelper.time(1111), - mockLocationPreferencesService, - mockPropertiesModelStore, - mockLocationController, - ) + val locationCapturer = + LocationCapturer( + mockApplicationService, + MockHelper.time(1111), + mockLocationPreferencesService, + mockPropertiesModelStore, + mockLocationController, + ) - /* When */ + // When locationCapturer.captureLastLocation() - /* Then */ + // Then mockPropertiesModelStore.model.locationAccuracy shouldBe 1111F mockPropertiesModelStore.model.locationBackground shouldBe false mockPropertiesModelStore.model.locationType shouldBe 1 @@ -66,7 +67,7 @@ class LocationCapturerTests : FunSpec({ } test("captureLastLocation will capture current location with coarse") { - /* Given */ + // Given val mockLocation = mockk() every { mockLocation.accuracy } returns 1111F every { mockLocation.time } returns 2222 @@ -85,19 +86,20 @@ class LocationCapturerTests : FunSpec({ val mockApplicationService = MockHelper.applicationService() every { mockApplicationService.isInForeground } returns true - val locationCapturer = LocationCapturer( - mockApplicationService, - MockHelper.time(1111), - mockLocationPreferencesService, - mockPropertiesModelStore, - mockLocationController, - ) + val locationCapturer = + LocationCapturer( + mockApplicationService, + MockHelper.time(1111), + mockLocationPreferencesService, + mockPropertiesModelStore, + mockLocationController, + ) - /* When */ + // When locationCapturer.locationCoarse = true locationCapturer.captureLastLocation() - /* Then */ + // Then mockPropertiesModelStore.model.locationAccuracy shouldBe 1111F mockPropertiesModelStore.model.locationBackground shouldBe false mockPropertiesModelStore.model.locationType shouldBe 0 @@ -109,7 +111,7 @@ class LocationCapturerTests : FunSpec({ } test("captureLastLocation will not capture current location when not available") { - /* Given */ + // Given val lastLocationTimeSlot = slot() val mockLocationPreferencesService = mockk() every { mockLocationPreferencesService.lastLocationTime = capture(lastLocationTimeSlot) } answers { } @@ -121,18 +123,19 @@ class LocationCapturerTests : FunSpec({ val mockApplicationService = MockHelper.applicationService() - val locationCapturer = LocationCapturer( - mockApplicationService, - MockHelper.time(1111), - mockLocationPreferencesService, - mockPropertiesModelStore, - mockLocationController, - ) + val locationCapturer = + LocationCapturer( + mockApplicationService, + MockHelper.time(1111), + mockLocationPreferencesService, + mockPropertiesModelStore, + mockLocationController, + ) - /* When */ + // When locationCapturer.captureLastLocation() - /* Then */ + // Then mockPropertiesModelStore.model.locationAccuracy shouldBe null mockPropertiesModelStore.model.locationBackground shouldBe null mockPropertiesModelStore.model.locationType shouldBe null diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt index b2e8bbba73..39cccfe6e8 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt @@ -33,7 +33,7 @@ class GmsLocationControllerTests : FunSpec({ } test("start will connect and fire locationChanged with location") { - /* Given */ + // Given val location = Location("TEST_PROVIDER") location.latitude = 123.45 location.longitude = 678.91 @@ -46,10 +46,10 @@ class GmsLocationControllerTests : FunSpec({ val spyLocationUpdateHandler = spyk() gmsLocationController.subscribe(spyLocationUpdateHandler) - /* When */ + // When val response = gmsLocationController.start() - /* Then */ + // Then response shouldBe true ShadowGoogleApiClient.connected shouldBe true verify(exactly = 1) { @@ -63,7 +63,7 @@ class GmsLocationControllerTests : FunSpec({ } test("start twice will return the initial location") { - /* Given */ + // Given val location1 = Location("TEST_PROVIDER") location1.latitude = 123.45 location1.longitude = 678.91 @@ -80,11 +80,11 @@ class GmsLocationControllerTests : FunSpec({ val spyLocationUpdateHandler = spyk() gmsLocationController.subscribe(spyLocationUpdateHandler) - /* When */ + // When val response1 = gmsLocationController.start() val response2 = gmsLocationController.start() - /* Then */ + // Then response1 shouldBe true response2 shouldBe true ShadowGoogleApiClient.connected shouldBe true @@ -105,7 +105,7 @@ class GmsLocationControllerTests : FunSpec({ } test("getLastLocation will retrieve a new location") { - /* Given */ + // Given val location1 = Location("TEST_PROVIDER") location1.latitude = 123.45 location1.longitude = 678.91 @@ -122,11 +122,11 @@ class GmsLocationControllerTests : FunSpec({ val spyLocationUpdateHandler = spyk() gmsLocationController.subscribe(spyLocationUpdateHandler) - /* When */ + // When val response = gmsLocationController.start() val lastLocation = gmsLocationController.getLastLocation() - /* Then */ + // Then response shouldBe true lastLocation shouldNotBe null lastLocation!!.latitude shouldBe 678.91 @@ -143,7 +143,7 @@ class GmsLocationControllerTests : FunSpec({ } test("stop will disconnect") { - /* Given */ + // Given val location1 = Location("TEST_PROVIDER") location1.latitude = 123.45 location1.longitude = 678.91 @@ -160,11 +160,11 @@ class GmsLocationControllerTests : FunSpec({ val spyLocationUpdateHandler = spyk() gmsLocationController.subscribe(spyLocationUpdateHandler) - /* When */ + // When val response = gmsLocationController.start() gmsLocationController.stop() - /* Then */ + // Then response shouldBe true ShadowGoogleApiClient.connected shouldBe false verifySequence { diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/permissions/LocationPermissionControllerTests.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/permissions/LocationPermissionControllerTests.kt index c8ee076741..1b5e132596 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/permissions/LocationPermissionControllerTests.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/permissions/LocationPermissionControllerTests.kt @@ -24,100 +24,104 @@ class LocationPermissionControllerTests : FunSpec({ } test("prompt will return true once permission is accepted by user") { - /* Given */ + // Given val mockRequestPermissionService = mockk() - val locationPermissionController = LocationPermissionController( - mockRequestPermissionService, - AndroidMockHelper.applicationService(), - ) + val locationPermissionController = + LocationPermissionController( + mockRequestPermissionService, + AndroidMockHelper.applicationService(), + ) every { mockRequestPermissionService.startPrompt(any(), any(), any(), any()) } coAnswers { delay(1000) locationPermissionController.onAccept() } - /* When */ + // When val beforeTime = System.currentTimeMillis() val response = locationPermissionController.prompt(false, "permission") val afterTime = System.currentTimeMillis() val deltaTime = afterTime - beforeTime - /* Then */ + // Then response shouldBe true deltaTime shouldBeGreaterThan 1000 verify(exactly = 1) { mockRequestPermissionService.startPrompt(false, any(), "permission", any()) } } test("prompt will return false once permission is rejected by user") { - /* Given */ + // Given val mockRequestPermissionService = mockk() - val locationPermissionController = LocationPermissionController( - mockRequestPermissionService, - AndroidMockHelper.applicationService(), - ) + val locationPermissionController = + LocationPermissionController( + mockRequestPermissionService, + AndroidMockHelper.applicationService(), + ) every { mockRequestPermissionService.startPrompt(any(), any(), any(), any()) } coAnswers { delay(1000) locationPermissionController.onReject(false) } - /* When */ + // When val beforeTime = System.currentTimeMillis() val response = locationPermissionController.prompt(false, "permission") val afterTime = System.currentTimeMillis() val deltaTime = afterTime - beforeTime - /* Then */ + // Then response shouldBe false deltaTime shouldBeGreaterThan 1000 verify(exactly = 1) { mockRequestPermissionService.startPrompt(false, any(), "permission", any()) } } test("prompt will notify subscribers as accepted once permission is accepted by user") { - /* Given */ + // Given val mockRequestPermissionService = mockk() - val locationPermissionController = LocationPermissionController( - mockRequestPermissionService, - AndroidMockHelper.applicationService(), - ) + val locationPermissionController = + LocationPermissionController( + mockRequestPermissionService, + AndroidMockHelper.applicationService(), + ) every { mockRequestPermissionService.startPrompt(any(), any(), any(), any()) } coAnswers { locationPermissionController.onAccept() } val spyLocationPermissionChangedHandler = spyk() - /* When */ + // When locationPermissionController.subscribe(spyLocationPermissionChangedHandler) locationPermissionController.prompt(false, "permission") - /* Then */ + // Then verify(exactly = 1) { spyLocationPermissionChangedHandler.onLocationPermissionChanged(true) } } test("prompt will notify subscribers as rejected once permission is rejected by user") { - /* Given */ + // Given val mockRequestPermissionService = mockk() - val locationPermissionController = LocationPermissionController( - mockRequestPermissionService, - AndroidMockHelper.applicationService(), - ) + val locationPermissionController = + LocationPermissionController( + mockRequestPermissionService, + AndroidMockHelper.applicationService(), + ) every { mockRequestPermissionService.startPrompt(any(), any(), any(), any()) } coAnswers { locationPermissionController.onReject(false) } val spyLocationPermissionChangedHandler = spyk() - /* When */ + // When locationPermissionController.subscribe(spyLocationPermissionChangedHandler) locationPermissionController.prompt(false, "permission") - /* Then */ + // Then verify(exactly = 1) { spyLocationPermissionChangedHandler.onLocationPermissionChanged(false) } } }) diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/AndroidMockHelper.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/AndroidMockHelper.kt index eff5fcc5b9..b2db452b6c 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/AndroidMockHelper.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/AndroidMockHelper.kt @@ -8,7 +8,6 @@ import io.mockk.every * Singleton which provides common mock services when running in an Android environment. */ internal object AndroidMockHelper { - fun applicationService(): IApplicationService { val mockAppService = MockHelper.applicationService() diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/DatabaseMockHelper.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/DatabaseMockHelper.kt index 90fcf42ae7..4a71a6474b 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/DatabaseMockHelper.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/DatabaseMockHelper.kt @@ -11,7 +11,10 @@ import io.mockk.spyk * Singleton which provides common mock services. */ internal object DatabaseMockHelper { - fun databaseProvider(tableName: String, records: List>? = null): Pair { + fun databaseProvider( + tableName: String, + records: List>? = null, + ): Pair { val mockOneSignalDatabase = spyk() if (records != null) { @@ -33,8 +36,14 @@ internal object DatabaseMockHelper { val mockCursor = mockk() var index = 0 every { mockCursor.count } returns records.count() - every { mockCursor.moveToFirst() } answers { index = 0; true } - every { mockCursor.moveToNext() } answers { index++; index < records.count() } + every { mockCursor.moveToFirst() } answers { + index = 0 + true + } + every { mockCursor.moveToNext() } answers { + index++ + index < records.count() + } every { mockCursor.getString(any()) } answers { records[index][firstArg()] as String } every { mockCursor.getFloat(any()) } answers { records[index][firstArg()] as Float } every { mockCursor.getLong(any()) } answers { records[index][firstArg()] as Long } diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/MockHelper.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/MockHelper.kt index aa65195613..9ad39bc898 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/MockHelper.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/mocks/MockHelper.kt @@ -39,6 +39,7 @@ object MockHelper { } const val DEFAULT_APP_ID = "appId" + fun configModelStore(action: ((ConfigModel) -> Unit)? = null): ConfigModelStore { val configModel = ConfigModel() diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowFusedLocationProviderApi.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowFusedLocationProviderApi.kt index 252bbe7148..395cb2b6e1 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowFusedLocationProviderApi.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowFusedLocationProviderApi.kt @@ -44,15 +44,28 @@ import java.lang.reflect.Modifier import java.util.concurrent.TimeUnit class ShadowFusedLocationProviderApi : FusedLocationProviderApi { + val pendingResult = + object : PendingResult() { + override fun await(): Status = Status.RESULT_SUCCESS + + override fun await( + p0: Long, + p1: TimeUnit, + ): Status = Status.RESULT_SUCCESS + + override fun cancel() { } + + override fun isCanceled(): Boolean = false + + override fun setResultCallback(p0: ResultCallback) { } + + override fun setResultCallback( + p0: ResultCallback, + p1: Long, + p2: TimeUnit, + ) {} + } - val pendingResult = object : PendingResult() { - override fun await(): Status = Status.RESULT_SUCCESS - override fun await(p0: Long, p1: TimeUnit): Status = Status.RESULT_SUCCESS - override fun cancel() { } - override fun isCanceled(): Boolean = false - override fun setResultCallback(p0: ResultCallback) { } - override fun setResultCallback(p0: ResultCallback, p1: Long, p2: TimeUnit) {} - } override fun getLastLocation(p0: GoogleApiClient): Location { if (locations != null) { val location = locations!![index] @@ -71,20 +84,64 @@ class ShadowFusedLocationProviderApi : FusedLocationProviderApi { } override fun getLocationAvailability(p0: GoogleApiClient): LocationAvailability = throw Exception() - override fun requestLocationUpdates(p0: GoogleApiClient, p1: LocationRequest, p2: LocationListener): PendingResult = pendingResult - override fun requestLocationUpdates(p0: GoogleApiClient, p1: LocationRequest, p2: LocationListener, p3: Looper): PendingResult = pendingResult - override fun requestLocationUpdates(p0: GoogleApiClient, p1: LocationRequest, p2: LocationCallback, p3: Looper): PendingResult = pendingResult - override fun requestLocationUpdates(p0: GoogleApiClient, p1: LocationRequest, p2: PendingIntent): PendingResult = pendingResult - override fun removeLocationUpdates(p0: GoogleApiClient, p1: LocationListener): PendingResult = pendingResult - override fun removeLocationUpdates(p0: GoogleApiClient, p1: PendingIntent): PendingResult = pendingResult - override fun removeLocationUpdates(p0: GoogleApiClient, p1: LocationCallback): PendingResult = pendingResult - override fun setMockMode(p0: GoogleApiClient, p1: Boolean): PendingResult = pendingResult - override fun setMockLocation(p0: GoogleApiClient, p1: Location): PendingResult = pendingResult + + override fun requestLocationUpdates( + p0: GoogleApiClient, + p1: LocationRequest, + p2: LocationListener, + ): PendingResult = pendingResult + + override fun requestLocationUpdates( + p0: GoogleApiClient, + p1: LocationRequest, + p2: LocationListener, + p3: Looper, + ): PendingResult = pendingResult + + override fun requestLocationUpdates( + p0: GoogleApiClient, + p1: LocationRequest, + p2: LocationCallback, + p3: Looper, + ): PendingResult = pendingResult + + override fun requestLocationUpdates( + p0: GoogleApiClient, + p1: LocationRequest, + p2: PendingIntent, + ): PendingResult = pendingResult + + override fun removeLocationUpdates( + p0: GoogleApiClient, + p1: LocationListener, + ): PendingResult = pendingResult + + override fun removeLocationUpdates( + p0: GoogleApiClient, + p1: PendingIntent, + ): PendingResult = pendingResult + + override fun removeLocationUpdates( + p0: GoogleApiClient, + p1: LocationCallback, + ): PendingResult = pendingResult + + override fun setMockMode( + p0: GoogleApiClient, + p1: Boolean, + ): PendingResult = pendingResult + + override fun setMockLocation( + p0: GoogleApiClient, + p1: Location, + ): PendingResult = pendingResult + override fun flushLocations(p0: GoogleApiClient): PendingResult = pendingResult companion object { private var locations: List? = null private var index: Int = 0 + fun injectToLocationServices(locations: List) { this.index = 0 this.locations = locations diff --git a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowGoogleApiClient.kt b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowGoogleApiClient.kt index 855b1531e3..a3ab00b90a 100644 --- a/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowGoogleApiClient.kt +++ b/OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/shadows/ShadowGoogleApiClient.kt @@ -56,7 +56,9 @@ class ShadowGoogleApiClientBuilder { class ShadowGoogleApiClient : GoogleApiClient() { override fun hasConnectedApi(p0: Api<*>): Boolean = connected + override fun getConnectionResult(p0: Api<*>): ConnectionResult = ConnectionResult(0) + override fun connect() { connected = true } @@ -64,24 +66,51 @@ class ShadowGoogleApiClient : GoogleApiClient() { override fun getClient(p0: Api.AnyClientKey): C { return object : Api.Client { override fun connect(p0: BaseGmsClient.ConnectionProgressReportCallbacks) { } + override fun disconnect(p0: String) {} + override fun disconnect() { } + override fun isConnected(): Boolean = true + override fun isConnecting(): Boolean = false - override fun getRemoteService(p0: IAccountAccessor?, p1: MutableSet?) {} + + override fun getRemoteService( + p0: IAccountAccessor?, + p1: MutableSet?, + ) {} + override fun requiresSignIn(): Boolean = false + override fun onUserSignOut(p0: BaseGmsClient.SignOutCallbacks) { } + override fun requiresAccount(): Boolean = false + override fun requiresGooglePlayServices(): Boolean = false + override fun providesSignIn(): Boolean = false + override fun getSignInIntent(): Intent = Intent() - override fun dump(p0: String, p1: FileDescriptor?, p2: PrintWriter, p3: Array?) { } + + override fun dump( + p0: String, + p1: FileDescriptor?, + p2: PrintWriter, + p3: Array?, + ) { } + override fun getServiceBrokerBinder(): IBinder? = null + override fun getRequiredFeatures(): Array = listOf().toArray() as Array + override fun getEndpointPackageName(): String = "" + override fun getMinApkVersion(): Int = 0 + override fun getAvailableFeatures(): Array = listOf().toArray() as Array + override fun getScopesForConnectionlessNonSignIn(): MutableSet = mutableSetOf() + override fun getLastDisconnectMessage(): String? = null } as C } @@ -90,38 +119,71 @@ class ShadowGoogleApiClient : GoogleApiClient() { connected = true return ConnectionResult(0) } - override fun blockingConnect(p0: Long, p1: TimeUnit): ConnectionResult { + + override fun blockingConnect( + p0: Long, + p1: TimeUnit, + ): ConnectionResult { connected = true return ConnectionResult(0) } + override fun disconnect() { connected = false } + override fun reconnect() { connected = true } + override fun clearDefaultAccountAndReconnect(): PendingResult { return object : PendingResult() { override fun await(): Status = Status.RESULT_SUCCESS - override fun await(p0: Long, p1: TimeUnit): Status = Status.RESULT_SUCCESS + + override fun await( + p0: Long, + p1: TimeUnit, + ): Status = Status.RESULT_SUCCESS + override fun cancel() { } + override fun isCanceled(): Boolean = false + override fun setResultCallback(p0: ResultCallback) { } - override fun setResultCallback(p0: ResultCallback, p1: Long, p2: TimeUnit) { + + override fun setResultCallback( + p0: ResultCallback, + p1: Long, + p2: TimeUnit, + ) { } } } override fun stopAutoManage(p0: FragmentActivity) { } + override fun isConnected(): Boolean = connected + override fun isConnecting(): Boolean = false + override fun registerConnectionCallbacks(p0: ConnectionCallbacks) { } + override fun isConnectionCallbacksRegistered(p0: ConnectionCallbacks): Boolean = true + override fun unregisterConnectionCallbacks(p0: ConnectionCallbacks) { } + override fun registerConnectionFailedListener(p0: OnConnectionFailedListener) { } + override fun isConnectionFailedListenerRegistered(p0: OnConnectionFailedListener): Boolean = false + override fun unregisterConnectionFailedListener(p0: OnConnectionFailedListener) { } - override fun dump(p0: String, p1: FileDescriptor, p2: PrintWriter, p3: Array) { } + + override fun dump( + p0: String, + p1: FileDescriptor, + p2: PrintWriter, + p3: Array, + ) { } companion object { var connected: Boolean = false diff --git a/OneSignalSDK/onesignal/notifications/build.gradle b/OneSignalSDK/onesignal/notifications/build.gradle index 56aa98c83b..23c082d6cd 100644 --- a/OneSignalSDK/onesignal/notifications/build.gradle +++ b/OneSignalSDK/onesignal/notifications/build.gradle @@ -115,6 +115,9 @@ dependencies { ktlint { version = "$ktlintVersion" + additionalEditorconfig = [ + "max_line_length": "500", + ] } apply from: '../maven-push.gradle' \ No newline at end of file diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/NotificationsModule.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/NotificationsModule.kt index 56f16a0f2a..a5a4679007 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/NotificationsModule.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/NotificationsModule.kt @@ -110,24 +110,25 @@ internal class NotificationsModule : IModule { builder.register { val deviceService = it.getService(IDeviceService::class.java) - val service = if (deviceService.isFireOSDeviceType) { - PushRegistratorADM(it.getService(IApplicationService::class.java)) - } else if (deviceService.isAndroidDeviceType) { - if (deviceService.hasFCMLibrary) { - PushRegistratorFCM( - it.getService(ConfigModelStore::class.java), - it.getService( - IApplicationService::class.java, - ), - it.getService(GooglePlayServicesUpgradePrompt::class.java), - deviceService, - ) + val service = + if (deviceService.isFireOSDeviceType) { + PushRegistratorADM(it.getService(IApplicationService::class.java)) + } else if (deviceService.isAndroidDeviceType) { + if (deviceService.hasFCMLibrary) { + PushRegistratorFCM( + it.getService(ConfigModelStore::class.java), + it.getService( + IApplicationService::class.java, + ), + it.getService(GooglePlayServicesUpgradePrompt::class.java), + deviceService, + ) + } else { + PushRegistratorNone() + } } else { - PushRegistratorNone() + PushRegistratorHMS(deviceService, it.getService(IApplicationService::class.java)) } - } else { - PushRegistratorHMS(deviceService, it.getService(IApplicationService::class.java)) - } return@register service }.provides() .provides() diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/bridges/OneSignalHmsEventBridge.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/bridges/OneSignalHmsEventBridge.kt index c6a87119eb..7a9a8fef54 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/bridges/OneSignalHmsEventBridge.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/bridges/OneSignalHmsEventBridge.kt @@ -31,7 +31,11 @@ object OneSignalHmsEventBridge { /** * Method used by last HMS push version 5.3.0.304 and upper */ - fun onNewToken(context: Context, token: String, bundle: Bundle?) { + fun onNewToken( + context: Context, + token: String, + bundle: Bundle?, + ) { if (firstToken.compareAndSet(true, false)) { Logging.info("OneSignalHmsEventBridge onNewToken - HMS token: $token Bundle: $bundle") var registerer = OneSignal.getService() @@ -48,11 +52,17 @@ object OneSignalHmsEventBridge { * @see OneSignalHmsEventBridge.onNewToken */ @Deprecated("") - fun onNewToken(context: Context, token: String) { + fun onNewToken( + context: Context, + token: String, + ) { onNewToken(context, token, null) } - fun onMessageReceived(context: Context, message: RemoteMessage) { + fun onMessageReceived( + context: Context, + message: RemoteMessage, + ) { if (!OneSignal.initWithContext(context)) { return } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/Notification.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/Notification.kt index 5050b2a9d8..b8e41c1bff 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/Notification.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/Notification.kt @@ -65,32 +65,38 @@ class Notification : IDisplayableMutableNotification { this.androidNotificationId = androidNotificationId } - private fun initPayloadData(currentJsonPayload: JSONObject, time: ITime) { - val customJson: JSONObject = try { - NotificationHelper.getCustomJSONObject(currentJsonPayload) - } catch (t: Throwable) { - Logging.error("Error assigning OSNotificationReceivedEvent payload values!", t) - return - } + private fun initPayloadData( + currentJsonPayload: JSONObject, + time: ITime, + ) { + val customJson: JSONObject = + try { + NotificationHelper.getCustomJSONObject(currentJsonPayload) + } catch (t: Throwable) { + Logging.error("Error assigning OSNotificationReceivedEvent payload values!", t) + return + } val currentTime = time.currentTimeMillis if (currentJsonPayload.has(NotificationConstants.GOOGLE_TTL_KEY)) { sentTime = currentJsonPayload.optLong( NotificationConstants.GOOGLE_SENT_TIME_KEY, currentTime, ) / 1000 - ttl = currentJsonPayload.optInt( - NotificationConstants.GOOGLE_TTL_KEY, - NotificationConstants.DEFAULT_TTL_IF_NOT_IN_PAYLOAD, - ) + ttl = + currentJsonPayload.optInt( + NotificationConstants.GOOGLE_TTL_KEY, + NotificationConstants.DEFAULT_TTL_IF_NOT_IN_PAYLOAD, + ) } else if (currentJsonPayload.has(NotificationConstants.HMS_TTL_KEY)) { sentTime = currentJsonPayload.optLong( NotificationConstants.HMS_SENT_TIME_KEY, currentTime, ) / 1000 - ttl = currentJsonPayload.optInt( - NotificationConstants.HMS_TTL_KEY, - NotificationConstants.DEFAULT_TTL_IF_NOT_IN_PAYLOAD, - ) + ttl = + currentJsonPayload.optInt( + NotificationConstants.HMS_TTL_KEY, + NotificationConstants.DEFAULT_TTL_IF_NOT_IN_PAYLOAD, + ) } else { sentTime = currentTime / 1000 ttl = NotificationConstants.DEFAULT_TTL_IF_NOT_IN_PAYLOAD @@ -136,11 +142,12 @@ class Notification : IDisplayableMutableNotification { val actionBtns = mutableListOf() for (i in 0 until jsonActionButtons.length()) { val jsonActionButton = jsonActionButtons.getJSONObject(i) - val actionButton = ActionButton( - jsonActionButton.safeString("id"), - jsonActionButton.safeString("text"), - jsonActionButton.safeString("icon"), - ) + val actionButton = + ActionButton( + jsonActionButton.safeString("id"), + jsonActionButton.safeString("text"), + jsonActionButton.safeString("icon"), + ) actionBtns.add(actionButton) } actionButtons = actionBtns @@ -154,11 +161,12 @@ class Notification : IDisplayableMutableNotification { val jsonStrBgImage = currentJsonPayload.safeString("bg_img") if (jsonStrBgImage != null) { val jsonBgImage = JSONObject(jsonStrBgImage) - backgroundImageLayout = BackgroundImageLayout( - jsonBgImage.safeString("img"), - jsonBgImage.safeString("tc"), - jsonBgImage.safeString("bc"), - ) + backgroundImageLayout = + BackgroundImageLayout( + jsonBgImage.safeString("img"), + jsonBgImage.safeString("tc"), + jsonBgImage.safeString("bc"), + ) } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationClickEvent.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationClickEvent.kt index d99185260e..cd16393d07 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationClickEvent.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationClickEvent.kt @@ -14,7 +14,6 @@ internal class NotificationClickEvent( private val _notification: Notification, private val _result: NotificationClickResult, ) : INotificationClickEvent { - /** The notification that was opened by the user. **/ override val notification: INotification get() = _notification diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationClickResult.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationClickResult.kt index 39b62beaf5..e4281d893e 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationClickResult.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationClickResult.kt @@ -32,7 +32,7 @@ import org.json.JSONObject internal class NotificationClickResult( override val actionId: String?, - override val url: String? + override val url: String?, ) : INotificationClickResult { fun toJSONObject(): JSONObject { return JSONObject() diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationReceivedEvent.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationReceivedEvent.kt index 3494c3daac..66c4bfb75d 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationReceivedEvent.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationReceivedEvent.kt @@ -8,7 +8,6 @@ internal class NotificationReceivedEvent( override val context: Context, override val notification: Notification, ) : INotificationReceivedEvent { - var isPreventDefault: Boolean = false override fun preventDefault() { diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationWillDisplayEvent.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationWillDisplayEvent.kt index ebe3b198b1..d3e91fe342 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationWillDisplayEvent.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationWillDisplayEvent.kt @@ -6,7 +6,6 @@ import com.onesignal.notifications.INotificationWillDisplayEvent internal class NotificationWillDisplayEvent( override val notification: Notification, ) : INotificationWillDisplayEvent { - var isPreventDefault: Boolean = false override fun preventDefault() { diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationsManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationsManager.kt index 98c18c0f40..99fe9d3dc1 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationsManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationsManager.kt @@ -24,7 +24,10 @@ import org.json.JSONArray import org.json.JSONException interface INotificationActivityOpener { - suspend fun openDestinationActivity(activity: Activity, pushPayloads: JSONArray) + suspend fun openDestinationActivity( + activity: Activity, + pushPayloads: JSONArray, + ) } /** @@ -42,13 +45,12 @@ internal class NotificationsManager( INotificationActivityOpener, INotificationPermissionChangedHandler, IApplicationLifecycleHandler { - override var permission: Boolean = NotificationHelper.areNotificationsEnabled(_applicationService.appContext) override val canRequestPermission: Boolean get() = _notificationPermissionController.canRequestPermission - private val _permissionChangedNotifier = EventProducer() + private val permissionChangedNotifier = EventProducer() init { _applicationService.addApplicationLifecycleHandler(this) @@ -98,7 +100,7 @@ internal class NotificationsManager( if (oldPermissionStatus != isEnabled) { // switch over to the main thread for the firing of the event - _permissionChangedNotifier.fireOnMain { it.onNotificationPermissionChange(isEnabled) } + permissionChangedNotifier.fireOnMain { it.onNotificationPermissionChange(isEnabled) } } } @@ -130,12 +132,12 @@ internal class NotificationsManager( override fun addPermissionObserver(observer: IPermissionObserver) { Logging.debug("NotificationsManager.addPermissionObserver(observer: $observer)") - _permissionChangedNotifier.subscribe(observer) + permissionChangedNotifier.subscribe(observer) } override fun removePermissionObserver(observer: IPermissionObserver) { Logging.debug("NotificationsManager.removePermissionObserver(observer: $observer)") - _permissionChangedNotifier.unsubscribe(observer) + permissionChangedNotifier.unsubscribe(observer) } override fun addForegroundLifecycleListener(listener: INotificationLifecycleListener) { @@ -158,7 +160,10 @@ internal class NotificationsManager( _notificationLifecycleService.removeExternalClickListener(listener) } - override suspend fun openDestinationActivity(activity: Activity, pushPayloads: JSONArray) { + override suspend fun openDestinationActivity( + activity: Activity, + pushPayloads: JSONArray, + ) { try { // Always use the top most notification if user tapped on the summary notification val firstPayloadItem = pushPayloads.getJSONObject(0) diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/IAnalyticsTracker.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/IAnalyticsTracker.kt index 4571d87ffb..45d3f45e50 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/IAnalyticsTracker.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/IAnalyticsTracker.kt @@ -28,6 +28,14 @@ package com.onesignal.notifications.internal.analytics internal interface IAnalyticsTracker { fun trackInfluenceOpenEvent() - fun trackOpenedEvent(notificationId: String, campaign: String) - fun trackReceivedEvent(notificationId: String, campaign: String) + + fun trackOpenedEvent( + notificationId: String, + campaign: String, + ) + + fun trackReceivedEvent( + notificationId: String, + campaign: String, + ) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/impl/FirebaseAnalyticsTracker.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/impl/FirebaseAnalyticsTracker.kt index 9f769bd38e..e37b53f62c 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/impl/FirebaseAnalyticsTracker.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/impl/FirebaseAnalyticsTracker.kt @@ -40,7 +40,6 @@ internal class FirebaseAnalyticsTracker( private val _configModelStore: ConfigModelStore, private val _time: ITime, ) : IAnalyticsTracker { - private val isEnabled: Boolean get() { return _configModelStore.model.firebaseAnalytics @@ -66,7 +65,7 @@ internal class FirebaseAnalyticsTracker( if (lastOpenedTime != null && now - lastOpenedTime!!.get() < 1000 * 30) return try { val firebaseAnalyticsInstance = getFirebaseAnalyticsInstance() - val trackMethod = getTrackMethod(FirebaseAnalyticsClass) + val trackMethod = getTrackMethod(firebaseAnalyticsClass) val event = EVENT_NOTIFICATION_INFLUENCE_OPEN // construct the firebase analytics event bundle @@ -81,7 +80,10 @@ internal class FirebaseAnalyticsTracker( } } - override fun trackOpenedEvent(notificationId: String, campaign: String) { + override fun trackOpenedEvent( + notificationId: String, + campaign: String, + ) { if (!isEnabled) { return } @@ -94,7 +96,7 @@ internal class FirebaseAnalyticsTracker( try { // get the source, medium, campaign params from the openResult val firebaseAnalyticsInstance = getFirebaseAnalyticsInstance() - val trackMethod = getTrackMethod(FirebaseAnalyticsClass) + val trackMethod = getTrackMethod(firebaseAnalyticsClass) // construct the firebase analytics event bundle val bundle = Bundle() @@ -108,7 +110,10 @@ internal class FirebaseAnalyticsTracker( } } - override fun trackReceivedEvent(notificationId: String, campaign: String) { + override fun trackReceivedEvent( + notificationId: String, + campaign: String, + ) { if (!isEnabled) { return } @@ -116,7 +121,7 @@ internal class FirebaseAnalyticsTracker( try { // get the source, medium, campaign params from the openResult val firebaseAnalyticsInstance = getFirebaseAnalyticsInstance() - val trackMethod = getTrackMethod(FirebaseAnalyticsClass) + val trackMethod = getTrackMethod(firebaseAnalyticsClass) // construct the firebase analytics event bundle val bundle = Bundle() bundle.putString("source", "OneSignal") @@ -135,26 +140,27 @@ internal class FirebaseAnalyticsTracker( private fun getFirebaseAnalyticsInstance(): Any? { if (mFirebaseAnalyticsInstance == null) { - val getInstanceMethod = getInstanceMethod(FirebaseAnalyticsClass) - mFirebaseAnalyticsInstance = try { - getInstanceMethod!!.invoke(null, _applicationService.appContext) - } catch (e: Throwable) { - e.printStackTrace() - return null - } + val getInstanceMethod = getInstanceMethod(firebaseAnalyticsClass) + mFirebaseAnalyticsInstance = + try { + getInstanceMethod!!.invoke(null, _applicationService.appContext) + } catch (e: Throwable) { + e.printStackTrace() + return null + } } return mFirebaseAnalyticsInstance } companion object { - private var FirebaseAnalyticsClass: Class<*>? = null + private var firebaseAnalyticsClass: Class<*>? = null private const val EVENT_NOTIFICATION_OPENED = "os_notification_opened" private const val EVENT_NOTIFICATION_INFLUENCE_OPEN = "os_notification_influence_open" private const val EVENT_NOTIFICATION_RECEIVED = "os_notification_received" fun canTrack(): Boolean { return try { - FirebaseAnalyticsClass = + firebaseAnalyticsClass = Class.forName("com.google.firebase.analytics.FirebaseAnalytics") true } catch (e: ClassNotFoundException) { diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/impl/NoAnalyticsTracker.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/impl/NoAnalyticsTracker.kt index 3a97ee079b..e8b6ffaf73 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/impl/NoAnalyticsTracker.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/analytics/impl/NoAnalyticsTracker.kt @@ -36,9 +36,15 @@ internal class NoAnalyticsTracker : IAnalyticsTracker { override fun trackInfluenceOpenEvent() { } - override fun trackOpenedEvent(notificationId: String, campaign: String) { + override fun trackOpenedEvent( + notificationId: String, + campaign: String, + ) { } - override fun trackReceivedEvent(notificationId: String, campaign: String) { + override fun trackReceivedEvent( + notificationId: String, + campaign: String, + ) { } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/backend/INotificationBackendService.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/backend/INotificationBackendService.kt index 7135746a56..6ed0d936e2 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/backend/INotificationBackendService.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/backend/INotificationBackendService.kt @@ -7,7 +7,6 @@ import com.onesignal.core.internal.device.IDeviceService * This backend service provides access to the Notification endpoints */ internal interface INotificationBackendService { - /** * Update the provided notification as received by a specific subscription. * @@ -18,7 +17,12 @@ internal interface INotificationBackendService { * @param subscriptionId The specific subscription within the [appId] the notification has been received for. * @param deviceType The type of device the notification was received at. */ - suspend fun updateNotificationAsReceived(appId: String, notificationId: String, subscriptionId: String, deviceType: IDeviceService.DeviceType) + suspend fun updateNotificationAsReceived( + appId: String, + notificationId: String, + subscriptionId: String, + deviceType: IDeviceService.DeviceType, + ) /** * Update the provided notification as opened by a specific subscription. @@ -30,5 +34,10 @@ internal interface INotificationBackendService { * @param subscriptionId The specific subscription within the [appId] the notification has been received for. * @param deviceType The type of device the notification was received at. */ - suspend fun updateNotificationAsOpened(appId: String, notificationId: String, subscriptionId: String, deviceType: IDeviceService.DeviceType) + suspend fun updateNotificationAsOpened( + appId: String, + notificationId: String, + subscriptionId: String, + deviceType: IDeviceService.DeviceType, + ) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/backend/impl/NotificationBackendService.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/backend/impl/NotificationBackendService.kt index e055314ec4..09f36aa9e1 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/backend/impl/NotificationBackendService.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/backend/impl/NotificationBackendService.kt @@ -9,12 +9,17 @@ import org.json.JSONObject internal class NotificationBackendService( private val _httpClient: IHttpClient, ) : INotificationBackendService { - - override suspend fun updateNotificationAsReceived(appId: String, notificationId: String, subscriptionId: String, deviceType: IDeviceService.DeviceType) { - val jsonBody: JSONObject = JSONObject() - .put("app_id", appId) - .put("player_id", subscriptionId) - .put("device_type", deviceType.value) + override suspend fun updateNotificationAsReceived( + appId: String, + notificationId: String, + subscriptionId: String, + deviceType: IDeviceService.DeviceType, + ) { + val jsonBody: JSONObject = + JSONObject() + .put("app_id", appId) + .put("player_id", subscriptionId) + .put("device_type", deviceType.value) var response = _httpClient.put("notifications/$notificationId/report_received", jsonBody) @@ -23,7 +28,12 @@ internal class NotificationBackendService( } } - override suspend fun updateNotificationAsOpened(appId: String, notificationId: String, subscriptionId: String, deviceType: IDeviceService.DeviceType) { + override suspend fun updateNotificationAsOpened( + appId: String, + notificationId: String, + subscriptionId: String, + deviceType: IDeviceService.DeviceType, + ) { val jsonBody = JSONObject() jsonBody.put("app_id", appId) jsonBody.put("player_id", subscriptionId) diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/badges/impl/BadgeCountUpdater.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/badges/impl/BadgeCountUpdater.kt index 8c990df4da..6f2f8f0f05 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/badges/impl/BadgeCountUpdater.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/badges/impl/BadgeCountUpdater.kt @@ -21,13 +21,15 @@ internal class BadgeCountUpdater( ) : IBadgeCountUpdater { // Cache for manifest setting. private var badgesEnabled = -1 + private fun areBadgeSettingsEnabled(): Boolean { if (badgesEnabled != -1) return badgesEnabled == 1 try { - val ai = _applicationService.appContext.packageManager.getApplicationInfo( - _applicationService.appContext.packageName, - PackageManager.GET_META_DATA, - ) + val ai = + _applicationService.appContext.packageManager.getApplicationInfo( + _applicationService.appContext.packageName, + PackageManager.GET_META_DATA, + ) val bundle = ai.metaData if (bundle != null) { val defaultStr = bundle.getString("com.onesignal.BadgeCount") diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/bundle/INotificationBundleProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/bundle/INotificationBundleProcessor.kt index c65dc519a7..6c3d19576b 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/bundle/INotificationBundleProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/bundle/INotificationBundleProcessor.kt @@ -4,11 +4,13 @@ import android.content.Context import android.os.Bundle internal interface INotificationBundleProcessor { - /** * Process bundle passed from FCM / HMS / ADM broadcast receiver */ - fun processBundleFromReceiver(context: Context, bundle: Bundle): ProcessedBundleResult? + fun processBundleFromReceiver( + context: Context, + bundle: Bundle, + ): ProcessedBundleResult? class ProcessedBundleResult { private var isOneSignalPayload = false diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/bundle/impl/NotificationBundleProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/bundle/impl/NotificationBundleProcessor.kt index 7e1a85cdaa..9e95d4115e 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/bundle/impl/NotificationBundleProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/bundle/impl/NotificationBundleProcessor.kt @@ -16,7 +16,6 @@ internal class NotificationBundleProcessor( private val _workManager: INotificationGenerationWorkManager, private val _time: ITime, ) : INotificationBundleProcessor { - // Format our short keys into more readable ones. private fun maximizeButtonsFromBundle(fcmBundle: Bundle) { if (!fcmBundle.containsKey("o")) return @@ -68,7 +67,10 @@ internal class NotificationBundleProcessor( /** * Process bundle passed from FCM / HMS / ADM broadcast receiver */ - override fun processBundleFromReceiver(context: Context, bundle: Bundle): INotificationBundleProcessor.ProcessedBundleResult? { + override fun processBundleFromReceiver( + context: Context, + bundle: Bundle, + ): INotificationBundleProcessor.ProcessedBundleResult? { val bundleResult = INotificationBundleProcessor.ProcessedBundleResult() // Not a OneSignal FCM message @@ -93,15 +95,16 @@ internal class NotificationBundleProcessor( ) } - val processed = _workManager.beginEnqueueingWork( - context, - osNotificationId!!, - androidNotificationId, - jsonPayload, - timestamp, - isRestoring, - isHighPriority, - ) + val processed = + _workManager.beginEnqueueingWork( + context, + osNotificationId!!, + androidNotificationId, + jsonPayload, + timestamp, + isRestoring, + isHighPriority, + ) bundleResult.isWorkManagerProcessing = processed diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/channels/INotificationChannelManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/channels/INotificationChannelManager.kt index 62aa8e5890..3d9b8c8f69 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/channels/INotificationChannelManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/channels/INotificationChannelManager.kt @@ -7,7 +7,6 @@ import org.json.JSONArray * Manager of the notification channels on the current device. */ internal interface INotificationChannelManager { - /** * Create a notification channel, returning it's identifier to post notifications to. */ diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/channels/impl/NotificationChannelManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/channels/impl/NotificationChannelManager.kt index 3b6cb3d760..f5e9fe6e74 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/channels/impl/NotificationChannelManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/channels/impl/NotificationChannelManager.kt @@ -72,36 +72,37 @@ internal class NotificationChannelManager( // a cold start sync. val objChannelPayload = payload.opt("chnl") var channelPayload: JSONObject? = null - channelPayload = if (objChannelPayload is String) { - JSONObject( - objChannelPayload, - ) - } else { - objChannelPayload as JSONObject - } - var channel_id = channelPayload!!.optString("id", DEFAULT_CHANNEL_ID) + channelPayload = + if (objChannelPayload is String) { + JSONObject( + objChannelPayload, + ) + } else { + objChannelPayload as JSONObject + } + var channelId = channelPayload!!.optString("id", DEFAULT_CHANNEL_ID) // Ensure we don't try to use the system reserved id - if (channel_id == NotificationChannel.DEFAULT_CHANNEL_ID) channel_id = DEFAULT_CHANNEL_ID + if (channelId == NotificationChannel.DEFAULT_CHANNEL_ID) channelId = DEFAULT_CHANNEL_ID var payloadWithText = channelPayload if (channelPayload.has("langs")) { val langList = channelPayload.getJSONObject("langs") val language = _languageContext.language if (langList.has(language)) payloadWithText = langList.optJSONObject(language) } - val channel_name = payloadWithText!!.optString("nm", "Miscellaneous") + val channelName = payloadWithText!!.optString("nm", "Miscellaneous") val importance = priorityToImportance(payload.optInt("pri", 6)) - val channel = NotificationChannel(channel_id, channel_name, importance) + val channel = NotificationChannel(channelId, channelName, importance) channel.description = payloadWithText.optString("dscr", null) if (channelPayload.has("grp_id")) { - val group_id = channelPayload.optString("grp_id") - val group_name: CharSequence = payloadWithText.optString("grp_nm") + val groupId = channelPayload.optString("grp_id") + val groupName: CharSequence = payloadWithText.optString("grp_nm") notificationManager.createNotificationChannelGroup( NotificationChannelGroup( - group_id, - group_name, + groupId, + groupName, ), ) - channel.group = group_id + channel.group = groupId } if (payload.has("ledc")) { var ledc = payload.optString("ledc") @@ -133,7 +134,9 @@ internal class NotificationChannelManager( uri, null, ) - } else if ("null" == sound || "nil" == sound) channel.setSound(null, null) + } else if ("null" == sound || "nil" == sound) { + channel.setSound(null, null) + } // null = None for a sound. } // Setting sound to null makes it 'None' in the Settings. @@ -153,16 +156,17 @@ internal class NotificationChannelManager( // https://github.com/OneSignal/OneSignal-Android-SDK/issues/895 e.printStackTrace() } - return channel_id + return channelId } @RequiresApi(api = Build.VERSION_CODES.O) private fun createDefaultChannel(notificationManager: NotificationManager): String { - val channel = NotificationChannel( - DEFAULT_CHANNEL_ID, - "Miscellaneous", - NotificationManager.IMPORTANCE_DEFAULT, - ) + val channel = + NotificationChannel( + DEFAULT_CHANNEL_ID, + "Miscellaneous", + NotificationManager.IMPORTANCE_DEFAULT, + ) channel.enableLights(true) channel.enableVibration(true) notificationManager.createNotificationChannel(channel) @@ -171,11 +175,12 @@ internal class NotificationChannelManager( @RequiresApi(api = Build.VERSION_CODES.O) private fun createRestoreChannel(notificationManager: NotificationManager): String { - val channel = NotificationChannel( - RESTORE_CHANNEL_ID, - "Restored", - NotificationManager.IMPORTANCE_LOW, - ) + val channel = + NotificationChannel( + RESTORE_CHANNEL_ID, + "Restored", + NotificationManager.IMPORTANCE_LOW, + ) notificationManager.createNotificationChannel(channel) return RESTORE_CHANNEL_ID } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/GenerateNotificationOpenIntentFromPushPayload.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/GenerateNotificationOpenIntentFromPushPayload.kt index ab0529b811..8f519e0f06 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/GenerateNotificationOpenIntentFromPushPayload.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/GenerateNotificationOpenIntentFromPushPayload.kt @@ -12,15 +12,18 @@ import org.json.JSONObject * * Payload */ internal object GenerateNotificationOpenIntentFromPushPayload { - /** * Create a new [GenerateNotificationOpenIntent] from the FCM payload */ - fun create(context: Context, fcmPayload: JSONObject): GenerateNotificationOpenIntent { - val behavior = OSNotificationOpenBehaviorFromPushPayload( - context, - fcmPayload, - ) + fun create( + context: Context, + fcmPayload: JSONObject, + ): GenerateNotificationOpenIntent { + val behavior = + OSNotificationOpenBehaviorFromPushPayload( + context, + fcmPayload, + ) return GenerateNotificationOpenIntent( context, @@ -29,9 +32,7 @@ internal object GenerateNotificationOpenIntentFromPushPayload { ) } - private fun openBrowserIntent( - uri: Uri?, - ): Intent? { + private fun openBrowserIntent(uri: Uri?): Intent? { if (uri == null) return null return AndroidUtils.openURLInBrowserIntent(uri) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/NotificationGenerationJob.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/NotificationGenerationJob.kt index 33d1e8f494..71f3ccc1d2 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/NotificationGenerationJob.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/NotificationGenerationJob.kt @@ -12,12 +12,13 @@ class NotificationGenerationJob( ) { val notification: Notification = inNotification.setAndroidNotificationId() - private fun Notification.setAndroidNotificationId() = this.also { - // If there is no android ID on the notification coming in, generate a new one. - if (it != null && !it.hasNotificationId()) { - it.androidNotificationId = SecureRandom().nextInt() + private fun Notification.setAndroidNotificationId() = + this.also { + // If there is no android ID on the notification coming in, generate a new one. + if (it != null && !it.hasNotificationId()) { + it.androidNotificationId = SecureRandom().nextInt() + } } - } var isRestoring = false var isNotificationToDisplay = false diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/NotificationHelper.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/NotificationHelper.kt index c662b2350a..742c08c261 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/NotificationHelper.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/NotificationHelper.kt @@ -14,7 +14,6 @@ import com.onesignal.common.AndroidUtils import com.onesignal.core.internal.time.ITime import com.onesignal.debug.internal.logging.Logging import com.onesignal.notifications.INotification -import com.onesignal.notifications.INotificationClickResult import com.onesignal.notifications.internal.NotificationClickEvent import com.onesignal.notifications.internal.NotificationClickResult import org.json.JSONArray @@ -23,8 +22,8 @@ import org.json.JSONObject import kotlin.math.min object NotificationHelper { - const val grouplessSummaryKey = "os_group_undefined" - const val grouplessSummaryId = -718463522 + const val GROUPLESS_SUMMARY_KEY = "os_group_undefined" + const val GROUPLESS_SUMMARY_ID = -718463522 /** * Getter for obtaining all active notifications @@ -53,7 +52,7 @@ object NotificationHelper { var groupCount = 0 for (statusBarNotification in statusBarNotifications) { if (!NotificationCompat.isGroupSummary(statusBarNotification.notification) && - grouplessSummaryKey == statusBarNotification.notification.group + GROUPLESS_SUMMARY_KEY == statusBarNotification.notification.group ) { groupCount++ } @@ -79,8 +78,8 @@ object NotificationHelper { val isGroupSummary = isGroupSummary(statusBarNotification) val isGroupless = ( notification.group == null || - notification.group == grouplessSummaryKey - ) + notification.group == GROUPLESS_SUMMARY_KEY + ) if (!isGroupSummary && isGroupless) { grouplessStatusBarNotifications.add( statusBarNotification, @@ -108,10 +107,11 @@ object NotificationHelper { Notification.Builder.recoverBuilder(context, grouplessNotif.notification) // Recreate the notification but with the groupless key instead - val notif = grouplessNotifBuilder - .setGroup(grouplessSummaryKey) - .setOnlyAlertOnce(true) - .build() + val notif = + grouplessNotifBuilder + .setGroup(GROUPLESS_SUMMARY_KEY) + .setOnlyAlertOnce(true) + .build() NotificationManagerCompat.from(context!!).notify(grouplessNotif.id, notif) } } @@ -124,7 +124,10 @@ object NotificationHelper { * @param context The app context to check notification enablement against. * @param channelId The optional channel ID to check enablement for. */ - fun areNotificationsEnabled(context: Context, channelId: String? = null): Boolean { + fun areNotificationsEnabled( + context: Context, + channelId: String? = null, + ): Boolean { try { val notificationsEnabled = NotificationManagerCompat.from(context).areNotificationsEnabled() if (!notificationsEnabled) { @@ -182,7 +185,10 @@ object NotificationHelper { return null } - fun getSoundUri(context: Context, sound: String?): Uri? { + fun getSoundUri( + context: Context, + sound: String?, + ): Uri? { val resources = context.resources val packageName = context.packageName var soundId: Int @@ -203,11 +209,15 @@ object NotificationHelper { return "" } - internal fun generateNotificationOpenedResult(jsonArray: JSONArray, time: ITime): NotificationClickEvent { + internal fun generateNotificationOpenedResult( + jsonArray: JSONArray, + time: ITime, + ): NotificationClickEvent { val jsonArraySize = jsonArray.length() var firstMessage = true - val androidNotificationId = jsonArray.optJSONObject(0) - .optInt(NotificationConstants.BUNDLE_KEY_ANDROID_NOTIFICATION_ID) + val androidNotificationId = + jsonArray.optJSONObject(0) + .optInt(NotificationConstants.BUNDLE_KEY_ANDROID_NOTIFICATION_ID) val groupedNotifications: MutableList = ArrayList() var actionSelected: String? = null var payload: JSONObject? = null @@ -234,12 +244,13 @@ object NotificationHelper { } } - val notification = com.onesignal.notifications.internal.Notification( - groupedNotifications, - payload!!, - androidNotificationId, - time, - ) + val notification = + com.onesignal.notifications.internal.Notification( + groupedNotifications, + payload!!, + androidNotificationId, + time, + ) val notificationResult = NotificationClickResult(actionSelected, notification.launchURL) diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/OSNotificationOpenAppSettings.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/OSNotificationOpenAppSettings.kt index 0e15d74f28..8cf4f04f7d 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/OSNotificationOpenAppSettings.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/OSNotificationOpenAppSettings.kt @@ -7,16 +7,16 @@ import com.onesignal.common.AndroidUtils * Settings that effect the OneSignal notification open behavior at the app level. */ internal object OSNotificationOpenAppSettings { - /*** * When the notification is tapped on should it show an Activity? * This could be resuming / opening the app or opening the URL on the notification. */ fun getShouldOpenActivity(context: Context): Boolean { - return "DISABLE" != AndroidUtils.getManifestMeta( - context, - "com.onesignal.NotificationOpened.DEFAULT", - ) + return "DISABLE" != + AndroidUtils.getManifestMeta( + context, + "com.onesignal.NotificationOpened.DEFAULT", + ) } /*** diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/OSNotificationOpenBehaviorFromPushPayload.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/OSNotificationOpenBehaviorFromPushPayload.kt index fbd0199a58..3811349c2f 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/OSNotificationOpenBehaviorFromPushPayload.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/common/OSNotificationOpenBehaviorFromPushPayload.kt @@ -8,7 +8,6 @@ internal class OSNotificationOpenBehaviorFromPushPayload( private val context: Context, private val fcmPayload: JSONObject, ) { - val shouldOpenApp: Boolean get() { return OSNotificationOpenAppSettings.getShouldOpenActivity(context) && diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/INotificationRepository.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/INotificationRepository.kt index 1690d735f3..f89ce42902 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/INotificationRepository.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/INotificationRepository.kt @@ -1,8 +1,10 @@ package com.onesignal.notifications.internal.data internal interface INotificationRepository { - - suspend fun createSummaryNotification(androidId: Int, groupId: String) + suspend fun createSummaryNotification( + androidId: Int, + groupId: String, + ) /** * Create a new notification. @@ -57,7 +59,10 @@ internal interface INotificationRepository { * * @return the Android ID, or null if there are no notifications with that group identifier. */ - suspend fun getAndroidIdForGroup(group: String, getSummaryNotification: Boolean): Int? + suspend fun getAndroidIdForGroup( + group: String, + getSummaryNotification: Boolean, + ): Int? /** * Retrieve the Android ID for the collapse key provided. @@ -86,7 +91,12 @@ internal interface INotificationRepository { */ suspend fun listNotificationsForOutstanding(excludeAndroidIds: List? = null): List - suspend fun markAsConsumed(androidId: Int, dismissed: Boolean, summaryGroup: String? = null, clearGroupOnSummaryClick: Boolean = true) + suspend fun markAsConsumed( + androidId: Int, + dismissed: Boolean, + summaryGroup: String? = null, + clearGroupOnSummaryClick: Boolean = true, + ) /** * Mark as dismissed the notification with the Android ID provided @@ -96,10 +106,15 @@ internal interface INotificationRepository { * @return true if a notification was marked as dismissed, false otherwise. */ suspend fun markAsDismissed(androidId: Int): Boolean + suspend fun markAsDismissedForGroup(group: String) + suspend fun markAsDismissedForOutstanding() - suspend fun clearOldestOverLimitFallback(notificationsToMakeRoomFor: Int, maxNumberOfNotificationsInt: Int) + suspend fun clearOldestOverLimitFallback( + notificationsToMakeRoomFor: Int, + maxNumberOfNotificationsInt: Int, + ) /** * Deletes notifications in the database that have expired. An expired notification diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/impl/NotificationQueryHelper.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/impl/NotificationQueryHelper.kt index 17867fac3c..e676006033 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/impl/NotificationQueryHelper.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/impl/NotificationQueryHelper.kt @@ -9,16 +9,16 @@ internal class NotificationQueryHelper( private val _configModelStore: ConfigModelStore, private val _time: ITime, ) : INotificationQueryHelper { - override fun recentUninteractedWithNotificationsWhere(): StringBuilder { val currentTimeSec = _time.currentTimeMillis / 1000L val createdAtCutoff = currentTimeSec - 604800L // 1 Week back - val where = StringBuilder( - OneSignalDbContract.NotificationTable.COLUMN_NAME_CREATED_TIME + " > " + createdAtCutoff + " AND " + - OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED + " = 0 AND " + - OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + " = 0 AND " + - OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + " = 0", - ) + val where = + StringBuilder( + OneSignalDbContract.NotificationTable.COLUMN_NAME_CREATED_TIME + " > " + createdAtCutoff + " AND " + + OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED + " = 0 AND " + + OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + " = 0 AND " + + OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + " = 0", + ) val useTtl = _configModelStore.model.restoreTTLFilter if (useTtl) { val expireTimeWhere = diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/impl/NotificationRepository.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/impl/NotificationRepository.kt index fe9b23d76b..b09bc4e157 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/impl/NotificationRepository.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/data/impl/NotificationRepository.kt @@ -33,9 +33,10 @@ internal class NotificationRepository( override suspend fun deleteExpiredNotifications() { withContext(Dispatchers.IO) { val whereStr: String = OneSignalDbContract.NotificationTable.COLUMN_NAME_CREATED_TIME.toString() + " < ?" - val sevenDaysAgoInSeconds: String = java.lang.String.valueOf( - _time.currentTimeMillis / 1000L - NOTIFICATION_CACHE_DATA_LIFETIME, - ) + val sevenDaysAgoInSeconds: String = + java.lang.String.valueOf( + _time.currentTimeMillis / 1000L - NOTIFICATION_CACHE_DATA_LIFETIME, + ) val whereArgs = arrayOf(sevenDaysAgoInSeconds) _databaseProvider.os.delete( @@ -54,8 +55,9 @@ internal class NotificationRepository( _databaseProvider.os.query( OneSignalDbContract.NotificationTable.TABLE_NAME, columns = retColumn, - whereClause = OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED.toString() + " = 0 AND " + - OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + " = 0", + whereClause = + OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED.toString() + " = 0 AND " + + OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + " = 0", ) { if (it.moveToFirst()) { do { @@ -164,13 +166,16 @@ internal class NotificationRepository( _databaseProvider.os.query( OneSignalDbContract.NotificationTable.TABLE_NAME, columns = retColumn, - whereClause = OneSignalDbContract.NotificationTable.COLUMN_NAME_NOTIFICATION_ID + " = ?", // Where String + // Where String + whereClause = OneSignalDbContract.NotificationTable.COLUMN_NAME_NOTIFICATION_ID + " = ?", whereArgs = whereArgs, ) { val exists = it.moveToFirst() if (exists) { - Logging.debug("Notification notValidOrDuplicated with id duplicated, duplicate FCM message received, skip processing of $id") + Logging.debug( + "Notification notValidOrDuplicated with id duplicated, duplicate FCM message received, skip processing of $id", + ) result = true } } @@ -179,7 +184,10 @@ internal class NotificationRepository( return result } - override suspend fun createSummaryNotification(androidId: Int, groupId: String) { + override suspend fun createSummaryNotification( + androidId: Int, + groupId: String, + ) { withContext(Dispatchers.IO) { // There currently isn't a visible notification from for this group_id. // Save the group summary notification id so it can be updated later. @@ -288,12 +296,17 @@ internal class NotificationRepository( } } - override suspend fun markAsConsumed(androidId: Int, dismissed: Boolean, summaryGroup: String?, clearGroupOnSummaryClick: Boolean) { + override suspend fun markAsConsumed( + androidId: Int, + dismissed: Boolean, + summaryGroup: String?, + clearGroupOnSummaryClick: Boolean, + ) { withContext(Dispatchers.IO) { var whereStr: String var whereArgs: Array? = null if (summaryGroup != null) { - val isGroupless = summaryGroup == NotificationHelper.grouplessSummaryKey + val isGroupless = summaryGroup == NotificationHelper.GROUPLESS_SUMMARY_KEY if (isGroupless) { whereStr = OneSignalDbContract.NotificationTable.COLUMN_NAME_GROUP_ID + " IS NULL" @@ -305,17 +318,18 @@ internal class NotificationRepository( // Make sure when a notification is not being dismissed it is handled through the dashboard setting if (!clearGroupOnSummaryClick) { /* If the open event shouldn't clear all summary notifications then the SQL query - * will look for the most recent notification instead of all grouped notifications */ + * will look for the most recent notification instead of all grouped notifications */ val mostRecentId = getAndroidIdForGroup(summaryGroup, false).toString() whereStr += " AND " + OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID + " = ?" - whereArgs = if (isGroupless) { - arrayOf(mostRecentId) - } else { - arrayOf( - summaryGroup, - mostRecentId, - ) - } + whereArgs = + if (isGroupless) { + arrayOf(mostRecentId) + } else { + arrayOf( + summaryGroup, + mostRecentId, + ) + } } } } else { @@ -347,7 +361,8 @@ internal class NotificationRepository( withContext(Dispatchers.IO) { _databaseProvider.os.query( OneSignalDbContract.NotificationTable.TABLE_NAME, - columns = arrayOf(OneSignalDbContract.NotificationTable.COLUMN_NAME_GROUP_ID), // retColumn + // retColumn + columns = arrayOf(OneSignalDbContract.NotificationTable.COLUMN_NAME_GROUP_ID), whereClause = OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID + " = " + androidId, ) { if (it.moveToFirst()) { @@ -366,10 +381,12 @@ internal class NotificationRepository( withContext(Dispatchers.IO) { _databaseProvider.os.query( OneSignalDbContract.NotificationTable.TABLE_NAME, - columns = arrayOf(OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID), // retColumn - whereClause = OneSignalDbContract.NotificationTable.COLUMN_NAME_COLLAPSE_ID + " = ? AND " + - OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED + " = 0 AND " + - OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + " = 0 ", + // retColumn + columns = arrayOf(OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID), + whereClause = + OneSignalDbContract.NotificationTable.COLUMN_NAME_COLLAPSE_ID + " = ? AND " + + OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED + " = 0 AND " + + OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + " = 0 ", whereArgs = arrayOf(collapseKey), ) { if (it.moveToFirst()) { @@ -381,7 +398,10 @@ internal class NotificationRepository( return androidId } - override suspend fun clearOldestOverLimitFallback(notificationsToMakeRoomFor: Int, maxNumberOfNotificationsInt: Int) { + override suspend fun clearOldestOverLimitFallback( + notificationsToMakeRoomFor: Int, + maxNumberOfNotificationsInt: Int, + ) { withContext(Dispatchers.IO) { val maxNumberOfNotificationsString = maxNumberOfNotificationsInt.toString() @@ -390,8 +410,10 @@ internal class NotificationRepository( OneSignalDbContract.NotificationTable.TABLE_NAME, columns = arrayOf(OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID), whereClause = _queryHelper.recentUninteractedWithNotificationsWhere().toString(), - orderBy = BaseColumns._ID, // sort order, old to new - limit = maxNumberOfNotificationsString + notificationsToMakeRoomFor, // limit + // sort order, old to new + orderBy = BaseColumns._ID, + // limit + limit = maxNumberOfNotificationsString + notificationsToMakeRoomFor, ) { var notificationsToClear = it.count - maxNumberOfNotificationsInt + notificationsToMakeRoomFor @@ -421,12 +443,14 @@ internal class NotificationRepository( _databaseProvider.os.query( OneSignalDbContract.NotificationTable.TABLE_NAME, columns = COLUMNS_FOR_LIST_NOTIFICATIONS, - whereClause = OneSignalDbContract.NotificationTable.COLUMN_NAME_GROUP_ID + " = ? AND " + // Where String - OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED + " = 0 AND " + - OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + " = 0 AND " + - OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + " = 0", + whereClause = + OneSignalDbContract.NotificationTable.COLUMN_NAME_GROUP_ID + " = ? AND " + // Where String + OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED + " = 0 AND " + + OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + " = 0 AND " + + OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + " = 0", whereArgs = whereArgs, - orderBy = BaseColumns._ID + " DESC", // sort order, new to old); + // sort order, new to old); + orderBy = BaseColumns._ID + " DESC", ) { if (it.moveToFirst()) { do { @@ -462,9 +486,12 @@ internal class NotificationRepository( /** * Query SQLiteDatabase by group to find the most recent created notification id */ - override suspend fun getAndroidIdForGroup(group: String, getSummaryNotification: Boolean): Int? { + override suspend fun getAndroidIdForGroup( + group: String, + getSummaryNotification: Boolean, + ): Int? { var recentId: Int? = null - val isGroupless = group == NotificationHelper.grouplessSummaryKey + val isGroupless = group == NotificationHelper.GROUPLESS_SUMMARY_KEY /* Beginning of the query string changes based on being groupless or not * since the groupless notifications will have a null group key in the db */ @@ -476,11 +503,12 @@ internal class NotificationRepository( OneSignalDbContract.NotificationTable.COLUMN_NAME_DISMISSED + " = 0 AND " + OneSignalDbContract.NotificationTable.COLUMN_NAME_OPENED + " = 0 AND " - whereStr += if (getSummaryNotification) { - OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + " = 1" - } else { - OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + " = 0" - } + whereStr += + if (getSummaryNotification) { + OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + " = 1" + } else { + OneSignalDbContract.NotificationTable.COLUMN_NAME_IS_SUMMARY + " = 0" + } val whereArgs = if (isGroupless) null else arrayOf(group) @@ -495,12 +523,13 @@ internal class NotificationRepository( limit = "1", ) { val hasRecord = it.moveToFirst() - recentId = if (!hasRecord) { - null - } else { - // Get more recent notification id from Cursor - it.getInt(OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID) - } + recentId = + if (!hasRecord) { + null + } else { + // Get more recent notification id from Cursor + it.getInt(OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID) + } } } @@ -523,8 +552,10 @@ internal class NotificationRepository( OneSignalDbContract.NotificationTable.TABLE_NAME, columns = COLUMNS_FOR_LIST_NOTIFICATIONS, whereClause = dbQuerySelection.toString(), - orderBy = BaseColumns._ID + " DESC", // sort order, new to old - limit = INotificationLimitManager.Constants.maxNumberOfNotifications.toString(), // limit + // sort order, new to old + orderBy = BaseColumns._ID + " DESC", + // limit + limit = INotificationLimitManager.Constants.maxNumberOfNotifications.toString(), ) { while (it.moveToNext()) { val title = @@ -560,13 +591,14 @@ internal class NotificationRepository( companion object { private const val NOTIFICATION_CACHE_DATA_LIFETIME = 604800L // 7 days in second - val COLUMNS_FOR_LIST_NOTIFICATIONS = arrayOf( - OneSignalDbContract.NotificationTable.COLUMN_NAME_TITLE, - OneSignalDbContract.NotificationTable.COLUMN_NAME_MESSAGE, - OneSignalDbContract.NotificationTable.COLUMN_NAME_NOTIFICATION_ID, - OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID, - OneSignalDbContract.NotificationTable.COLUMN_NAME_FULL_DATA, - OneSignalDbContract.NotificationTable.COLUMN_NAME_CREATED_TIME, - ) + val COLUMNS_FOR_LIST_NOTIFICATIONS = + arrayOf( + OneSignalDbContract.NotificationTable.COLUMN_NAME_TITLE, + OneSignalDbContract.NotificationTable.COLUMN_NAME_MESSAGE, + OneSignalDbContract.NotificationTable.COLUMN_NAME_NOTIFICATION_ID, + OneSignalDbContract.NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID, + OneSignalDbContract.NotificationTable.COLUMN_NAME_FULL_DATA, + OneSignalDbContract.NotificationTable.COLUMN_NAME_CREATED_TIME, + ) } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/INotificationDisplayBuilder.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/INotificationDisplayBuilder.kt index 314705facb..6f60eb4a79 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/INotificationDisplayBuilder.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/INotificationDisplayBuilder.kt @@ -21,10 +21,18 @@ internal interface INotificationDisplayBuilder { // Android 6.0 - No Sound or heads-up // Android 5.0 - Sound, but no heads-up fun getGroupAlertBehavior(): Int + fun getTitle(fcmJson: JSONObject): CharSequence - fun getNewDismissActionPendingIntent(requestCode: Int, intent: Intent): PendingIntent + + fun getNewDismissActionPendingIntent( + requestCode: Int, + intent: Intent, + ): PendingIntent + fun getNewBaseDismissIntent(notificationId: Int): Intent + fun getBaseOneSignalNotificationBuilder(notificationJob: NotificationGenerationJob): NotificationDisplayBuilder.OneSignalNotificationBuilder + fun removeNotifyOptions(builder: NotificationCompat.Builder?) // Xiaomi requires the following to show a custom notification icons. diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/ISummaryNotificationDisplayer.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/ISummaryNotificationDisplayer.kt index 2d7234c4f3..9dc7f83970 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/ISummaryNotificationDisplayer.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/ISummaryNotificationDisplayer.kt @@ -13,7 +13,9 @@ internal interface ISummaryNotificationDisplayer { notifBuilder: NotificationDisplayBuilder.OneSignalNotificationBuilder?, groupAlertBehavior: Int, ) + suspend fun updateSummaryNotification(notificationJob: NotificationGenerationJob) + fun createGenericPendingIntentsForGroup( notifBuilder: NotificationCompat.Builder?, intentGenerator: IntentGeneratorForAttachingToNotifications, @@ -21,10 +23,12 @@ internal interface ISummaryNotificationDisplayer { group: String, notificationId: Int, ) + fun createSingleNotificationBeforeSummaryBuilder( notificationJob: NotificationGenerationJob, notifBuilder: NotificationCompat.Builder?, ): Notification + suspend fun createGrouplessSummaryNotification( notificationJob: NotificationGenerationJob, intentGenerator: IntentGeneratorForAttachingToNotifications, diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/IntentGeneratorForAttachingToNotifications.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/IntentGeneratorForAttachingToNotifications.kt index c30c539b43..45cf497d39 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/IntentGeneratorForAttachingToNotifications.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/IntentGeneratorForAttachingToNotifications.kt @@ -14,9 +14,7 @@ internal class IntentGeneratorForAttachingToNotifications( private val notificationOpenedClassAndroid23Plus: Class<*> = NotificationOpenedActivity::class.java private val notificationOpenedClassAndroid22AndOlder: Class<*> = NotificationOpenedActivityAndroid22AndOlder::class.java - fun getNewBaseIntent( - notificationId: Int, - ): Intent { + fun getNewBaseIntent(notificationId: Int): Intent { val intent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { getNewBaseIntentAndroidAPI23Plus() @@ -48,10 +46,11 @@ internal class IntentGeneratorForAttachingToNotifications( // See NotificationOpenedReceiverAndroid22AndOlder.kt for details @Deprecated("Use getNewBaseIntentAndroidAPI23Plus instead for Android 6+") private fun getNewBaseIntentAndroidAPI22AndOlder(): Intent { - val intent = Intent( - context, - notificationOpenedClassAndroid22AndOlder, - ) + val intent = + Intent( + context, + notificationOpenedClassAndroid22AndOlder, + ) intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/NotificationDisplayBuilder.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/NotificationDisplayBuilder.kt index 425196a44d..72d92bb8a1 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/NotificationDisplayBuilder.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/NotificationDisplayBuilder.kt @@ -31,7 +31,6 @@ import java.util.Arrays internal class NotificationDisplayBuilder( private val _applicationService: IApplicationService, private val _notificationChannelManager: INotificationChannelManager, - ) : INotificationDisplayBuilder { private val notificationDismissedClass: Class<*> = NotificationDismissReceiver::class.java @@ -62,7 +61,10 @@ internal class NotificationDisplayBuilder( ) } - override fun getNewDismissActionPendingIntent(requestCode: Int, intent: Intent): PendingIntent { + override fun getNewDismissActionPendingIntent( + requestCode: Int, + intent: Intent, + ): PendingIntent { return PendingIntent.getBroadcast( currentContext, requestCode, @@ -81,14 +83,15 @@ internal class NotificationDisplayBuilder( val fcmJson: JSONObject = notificationJob.jsonPayload!! val oneSignalNotificationBuilder = OneSignalNotificationBuilder() val notificationBuilder: NotificationCompat.Builder - notificationBuilder = try { - val channelId: String = - _notificationChannelManager.createNotificationChannel(notificationJob) - // Will throw if app is using 26.0.0-beta1 or older of the support library. - NotificationCompat.Builder(currentContext!!, channelId) - } catch (t: Throwable) { - NotificationCompat.Builder(currentContext!!) - } + notificationBuilder = + try { + val channelId: String = + _notificationChannelManager.createNotificationChannel(notificationJob) + // Will throw if app is using 26.0.0-beta1 or older of the support library. + NotificationCompat.Builder(currentContext!!, channelId) + } catch (t: Throwable) { + NotificationCompat.Builder(currentContext!!) + } val message = fcmJson.optString("alert", null) notificationBuilder .setAutoCancel(true) @@ -138,7 +141,10 @@ internal class NotificationDisplayBuilder( } // Sets visibility options including; Priority, LED, Sounds, and Vibration. - private fun setAlertnessOptions(fcmJson: JSONObject, notifBuilder: NotificationCompat.Builder) { + private fun setAlertnessOptions( + fcmJson: JSONObject, + notifBuilder: NotificationCompat.Builder, + ) { val payloadPriority = fcmJson.optInt("pri", 6) val androidPriority = convertOSToAndroidPriority(payloadPriority) notifBuilder.priority = androidPriority @@ -263,8 +269,8 @@ internal class NotificationDisplayBuilder( } catch (t: Throwable) { } if (bitmap != null) return bitmap - val image_extensions = Arrays.asList(".png", ".webp", ".jpg", ".gif", ".bmp") - for (extension in image_extensions) { + val imageExtensions = Arrays.asList(".png", ".webp", ".jpg", ".gif", ".bmp") + for (extension in imageExtensions) { try { bitmap = BitmapFactory.decodeStream(currentContext!!.assets.open(bitmapStr + extension)) @@ -361,7 +367,11 @@ internal class NotificationDisplayBuilder( // Get accent color from Manifest try { - val defaultColor: String? = AndroidUtils.getManifestMeta(_applicationService.appContext, "com.onesignal.NotificationAccentColor.DEFAULT") + val defaultColor: String? = + AndroidUtils.getManifestMeta( + _applicationService.appContext, + "com.onesignal.NotificationAccentColor.DEFAULT", + ) if (defaultColor != null) { return BigInteger(defaultColor, 16) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/NotificationDisplayer.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/NotificationDisplayer.kt index 50cc812edb..5e6e8e4c91 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/NotificationDisplayer.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/NotificationDisplayer.kt @@ -39,7 +39,6 @@ internal class NotificationDisplayer( private val _notificationLimitManager: INotificationLimitManager, private val _summaryNotificationDisplayer: ISummaryNotificationDisplayer, private val _notificationDisplayBuilder: INotificationDisplayBuilder, - ) : INotificationDisplayer { private val contextResources: Resources? get() = _applicationService.appContext.resources @@ -65,7 +64,11 @@ internal class NotificationDisplayer( val isRunningOnMainThreadCheck: Unit get() { // Runtime check against showing the notification from the main thread - if (AndroidUtils.isRunningOnMainThread()) throw MainThreadException("Process for showing a notification should never been done on Main Thread!") + if (AndroidUtils.isRunningOnMainThread()) { + throw MainThreadException( + "Process for showing a notification should never been done on Main Thread!", + ) + } } // Put the message into a notification and post it. @@ -78,12 +81,12 @@ internal class NotificationDisplayer( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { /* Android 7.0 auto groups 4 or more notifications so we find these groupless active - * notifications and add a generic group to them */ + * notifications and add a generic group to them */ grouplessNotifs = NotificationHelper.getActiveGrouplessNotifications(currentContext) // If the null this makes the 4th notification and we want to check that 3 or more active groupless exist if (group == null && grouplessNotifs.size >= 3) { - group = NotificationHelper.grouplessSummaryKey + group = NotificationHelper.GROUPLESS_SUMMARY_KEY NotificationHelper.assignGrouplessNotifications( currentContext, grouplessNotifs, @@ -130,7 +133,7 @@ internal class NotificationDisplayer( notification = _summaryNotificationDisplayer.createSingleNotificationBeforeSummaryBuilder(notificationJob, notifBuilder) // Create PendingIntents for notifications in a groupless or defined summary - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && group == NotificationHelper.grouplessSummaryKey) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && group == NotificationHelper.GROUPLESS_SUMMARY_KEY) { _summaryNotificationDisplayer.createGrouplessSummaryNotification( notificationJob, intentGenerator, @@ -138,15 +141,20 @@ internal class NotificationDisplayer( _notificationDisplayBuilder.getGroupAlertBehavior(), ) } else { - _summaryNotificationDisplayer.createSummaryNotification(notificationJob, oneSignalNotificationBuilder, _notificationDisplayBuilder.getGroupAlertBehavior()) + _summaryNotificationDisplayer.createSummaryNotification( + notificationJob, + oneSignalNotificationBuilder, + _notificationDisplayBuilder.getGroupAlertBehavior(), + ) } } else { - notification = createGenericPendingIntentsForNotif( - notifBuilder, - intentGenerator, - fcmJson, - notificationId, - ) + notification = + createGenericPendingIntentsForNotif( + notifBuilder, + intentGenerator, + fcmJson, + notificationId, + ) } // NotificationManagerCompat does not auto omit the individual notification on the device when using @@ -174,16 +182,18 @@ internal class NotificationDisplayer( notificationId: Int, ): Notification { val random: Random = SecureRandom() - val contentIntent: PendingIntent? = intentGenerator.getNewActionPendingIntent( - random.nextInt(), - intentGenerator.getNewBaseIntent(notificationId) - .putExtra(NotificationConstants.BUNDLE_KEY_ONESIGNAL_DATA, gcmBundle.toString()), - ) + val contentIntent: PendingIntent? = + intentGenerator.getNewActionPendingIntent( + random.nextInt(), + intentGenerator.getNewBaseIntent(notificationId) + .putExtra(NotificationConstants.BUNDLE_KEY_ONESIGNAL_DATA, gcmBundle.toString()), + ) notifBuilder!!.setContentIntent(contentIntent) - val deleteIntent = _notificationDisplayBuilder.getNewDismissActionPendingIntent( - random.nextInt(), - _notificationDisplayBuilder.getNewBaseDismissIntent(notificationId), - ) + val deleteIntent = + _notificationDisplayBuilder.getNewDismissActionPendingIntent( + random.nextInt(), + _notificationDisplayBuilder.getNewBaseDismissIntent(notificationId), + ) notifBuilder.setDeleteIntent(deleteIntent) return notifBuilder.build() } @@ -224,7 +234,10 @@ internal class NotificationDisplayer( // Keep 'throws Throwable' as 'onesignal_bgimage_notif_layout' may not be available // This maybe the case if a jar is used instead of an aar. @Throws(Throwable::class) - private fun addBackgroundImage(fcmJson: JSONObject, notifBuilder: NotificationCompat.Builder?) { + private fun addBackgroundImage( + fcmJson: JSONObject, + notifBuilder: NotificationCompat.Builder?, + ) { // Not adding Background Images to API Versions < 16 or >= 31 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN || Build.VERSION.SDK_INT >= Build.VERSION_CODES.S @@ -232,18 +245,18 @@ internal class NotificationDisplayer( Logging.verbose("Cannot use background images in notifications for device on version: " + Build.VERSION.SDK_INT) return } - var bg_image: Bitmap? = null + var bgImage: Bitmap? = null var jsonBgImage: JSONObject? = null val jsonStrBgImage = fcmJson.optString("bg_img", null) if (jsonStrBgImage != null) { jsonBgImage = JSONObject(jsonStrBgImage) - bg_image = getBitmap(jsonBgImage.optString("img", null)) + bgImage = getBitmap(jsonBgImage.optString("img", null)) } - if (bg_image == null) { - bg_image = + if (bgImage == null) { + bgImage = getBitmapFromAssetsOrResourceName("onesignal_bgimage_default_image") } - if (bg_image != null) { + if (bgImage != null) { val customView = RemoteViews(currentContext!!.packageName, R.layout.onesignal_bgimage_notif_layout) customView.setTextViewText(R.id.os_bgimage_notif_title, _notificationDisplayBuilder.getTitle(fcmJson)) @@ -267,11 +280,12 @@ internal class NotificationDisplayer( alignSetting = jsonBgImage.getString("img_align") } else { - val iAlignSetting = contextResources!!.getIdentifier( - "onesignal_bgimage_notif_image_align", - "string", - packageName, - ) + val iAlignSetting = + contextResources!!.getIdentifier( + "onesignal_bgimage_notif_image_align", + "string", + packageName, + ) if (iAlignSetting != 0) alignSetting = contextResources!!.getString(iAlignSetting) } if ("right" == alignSetting) { @@ -285,14 +299,14 @@ internal class NotificationDisplayer( 0, 0, ) - customView.setImageViewBitmap(R.id.os_bgimage_notif_bgimage_right_aligned, bg_image) + customView.setImageViewBitmap(R.id.os_bgimage_notif_bgimage_right_aligned, bgImage) customView.setViewVisibility( R.id.os_bgimage_notif_bgimage_right_aligned, View.VISIBLE, ) // visible customView.setViewVisibility(R.id.os_bgimage_notif_bgimage, View.GONE) // gone } else { - customView.setImageViewBitmap(R.id.os_bgimage_notif_bgimage, bg_image) + customView.setImageViewBitmap(R.id.os_bgimage_notif_bgimage, bgImage) } notifBuilder!!.setContent(customView) @@ -327,7 +341,10 @@ internal class NotificationDisplayer( } } - private fun safeGetColorFromHex(fcmJson: JSONObject?, colorKey: String): Int? { + private fun safeGetColorFromHex( + fcmJson: JSONObject?, + colorKey: String, + ): Int? { try { if (fcmJson != null && fcmJson.has(colorKey)) { return BigInteger(fcmJson.optString(colorKey), 16).toInt() @@ -345,8 +362,8 @@ internal class NotificationDisplayer( } catch (t: Throwable) { } if (bitmap != null) return bitmap - val image_extensions = Arrays.asList(".png", ".webp", ".jpg", ".gif", ".bmp") - for (extension in image_extensions) { + val imageExtensions = Arrays.asList(".png", ".webp", ".jpg", ".gif", ".bmp") + for (extension in imageExtensions) { try { bitmap = BitmapFactory.decodeStream(currentContext!!.assets.open(bitmapStr + extension)) diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/SummaryNotificationDisplayer.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/SummaryNotificationDisplayer.kt index 53344bee35..807844e94d 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/SummaryNotificationDisplayer.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/display/impl/SummaryNotificationDisplayer.kt @@ -39,16 +39,18 @@ internal class SummaryNotificationDisplayer( notificationId: Int, ) { val random: Random = SecureRandom() - val contentIntent: PendingIntent? = intentGenerator.getNewActionPendingIntent( - random.nextInt(), - intentGenerator.getNewBaseIntent(notificationId) - .putExtra(NotificationConstants.BUNDLE_KEY_ONESIGNAL_DATA, gcmBundle.toString()).putExtra("grp", group), - ) + val contentIntent: PendingIntent? = + intentGenerator.getNewActionPendingIntent( + random.nextInt(), + intentGenerator.getNewBaseIntent(notificationId) + .putExtra(NotificationConstants.BUNDLE_KEY_ONESIGNAL_DATA, gcmBundle.toString()).putExtra("grp", group), + ) notifBuilder!!.setContentIntent(contentIntent) - val deleteIntent = _notificationDisplayBuilder.getNewDismissActionPendingIntent( - random.nextInt(), - _notificationDisplayBuilder.getNewBaseDismissIntent(notificationId).putExtra("grp", group), - ) + val deleteIntent = + _notificationDisplayBuilder.getNewDismissActionPendingIntent( + random.nextInt(), + _notificationDisplayBuilder.getNewBaseDismissIntent(notificationId).putExtra("grp", group), + ) notifBuilder.setDeleteIntent(deleteIntent) notifBuilder.setGroup(group) try { @@ -69,7 +71,8 @@ internal class SummaryNotificationDisplayer( val singleNotifWorkArounds = Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.N && !notificationJob.isRestoring if (singleNotifWorkArounds) { - if ((notificationJob.overriddenSound != null) && !notificationJob.overriddenSound!! + if ((notificationJob.overriddenSound != null) && + !notificationJob.overriddenSound!! .equals(notificationJob.orgSound) ) { notifBuilder!!.setSound(null) @@ -95,10 +98,11 @@ internal class SummaryNotificationDisplayer( val intentGenerator = IntentGeneratorForAttachingToNotifications(currentContext!!) val group = fcmJson.optString("grp", null) val random = SecureRandom() - val summaryDeleteIntent = _notificationDisplayBuilder.getNewDismissActionPendingIntent( - random.nextInt(), - _notificationDisplayBuilder.getNewBaseDismissIntent(0).putExtra("summary", group), - ) + val summaryDeleteIntent = + _notificationDisplayBuilder.getNewDismissActionPendingIntent( + random.nextInt(), + _notificationDisplayBuilder.getNewBaseDismissIntent(0).putExtra("summary", group), + ) val summaryNotification: Notification var summaryNotificationId: Int? = null var firstFullData: String? = null @@ -134,10 +138,11 @@ internal class SummaryNotificationDisplayer( } } - val summaryContentIntent: PendingIntent? = intentGenerator.getNewActionPendingIntent( - random.nextInt(), - createBaseSummaryIntent(summaryNotificationId!!, intentGenerator, fcmJson, group), - ) + val summaryContentIntent: PendingIntent? = + intentGenerator.getNewActionPendingIntent( + random.nextInt(), + createBaseSummaryIntent(summaryNotificationId!!, intentGenerator, fcmJson, group), + ) // 2 or more notifications with a group received, group them together as a single notification. if (updateSummary && summaryList.size > 1 || @@ -256,18 +261,20 @@ internal class SummaryNotificationDisplayer( val fcmJson: JSONObject = notificationJob.jsonPayload!! val summaryNotification: Notification val random = SecureRandom() - val group: String = NotificationHelper.grouplessSummaryKey + val group: String = NotificationHelper.GROUPLESS_SUMMARY_KEY val summaryMessage = "$grouplessNotifCount new messages" - val summaryNotificationId: Int = NotificationHelper.grouplessSummaryId + val summaryNotificationId: Int = NotificationHelper.GROUPLESS_SUMMARY_ID _dataController.createSummaryNotification(summaryNotificationId!!, group) - val summaryContentIntent: PendingIntent? = intentGenerator.getNewActionPendingIntent( - random.nextInt(), - createBaseSummaryIntent(summaryNotificationId, intentGenerator, fcmJson, group), - ) - val summaryDeleteIntent = _notificationDisplayBuilder.getNewDismissActionPendingIntent( - random.nextInt(), - _notificationDisplayBuilder.getNewBaseDismissIntent(0).putExtra("summary", group), - ) + val summaryContentIntent: PendingIntent? = + intentGenerator.getNewActionPendingIntent( + random.nextInt(), + createBaseSummaryIntent(summaryNotificationId, intentGenerator, fcmJson, group), + ) + val summaryDeleteIntent = + _notificationDisplayBuilder.getNewDismissActionPendingIntent( + random.nextInt(), + _notificationDisplayBuilder.getNewBaseDismissIntent(0).putExtra("summary", group), + ) val summaryBuilder = _notificationDisplayBuilder.getBaseOneSignalNotificationBuilder(notificationJob).compatBuilder if (notificationJob.overriddenSound != null) summaryBuilder!!.setSound(notificationJob.overriddenSound) if (notificationJob.overriddenFlags != null) { diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationProcessor.kt index f66883522d..5277fb9def 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationProcessor.kt @@ -39,7 +39,6 @@ internal class NotificationGenerationProcessor( private val _lifecycleService: INotificationLifecycleService, private val _time: ITime, ) : INotificationGenerationProcessor { - override suspend fun processNotificationData( context: Context, androidNotificationId: Int, @@ -90,8 +89,9 @@ internal class NotificationGenerationProcessor( Logging.error("remoteNotificationReceived threw an exception. Displaying normal OneSignal notification.", t) } - var shouldDisplay = processHandlerResponse(notificationJob, wantsToDisplay, isRestoring) - ?: return + var shouldDisplay = + processHandlerResponse(notificationJob, wantsToDisplay, isRestoring) + ?: return if (shouldDisplay) { if (shouldFireForegroundHandlers(notificationJob)) { @@ -118,7 +118,10 @@ internal class NotificationGenerationProcessor( } catch (to: TimeoutCancellationException) { Logging.info("notificationWillShowInForegroundHandler timed out, continuing with wantsToDisplay=$wantsToDisplay.", to) } catch (t: Throwable) { - Logging.error("notificationWillShowInForegroundHandler threw an exception. Displaying normal OneSignal notification.", t) + Logging.error( + "notificationWillShowInForegroundHandler threw an exception. Displaying normal OneSignal notification.", + t, + ) } shouldDisplay = processHandlerResponse(notificationJob, wantsToDisplay, isRestoring) @@ -153,7 +156,11 @@ internal class NotificationGenerationProcessor( * * @return true if the job should continue display, false if the job should continue but not display, null if processing should stop. */ - private suspend fun processHandlerResponse(notificationJob: NotificationGenerationJob, wantsToDisplay: Boolean, isRestoring: Boolean): Boolean? { + private suspend fun processHandlerResponse( + notificationJob: NotificationGenerationJob, + wantsToDisplay: Boolean, + isRestoring: Boolean, + ): Boolean? { if (wantsToDisplay) { val canDisplay = AndroidUtils.isStringNotEmpty(notificationJob.notification.body) val withinTtl: Boolean = isNotificationWithinTTL(notificationJob.notification) @@ -204,9 +211,10 @@ internal class NotificationGenerationProcessor( } private fun shouldDisplayNotification(notificationJob: NotificationGenerationJob): Boolean { - return notificationJob.hasExtender() || AndroidUtils.isStringNotEmpty( - notificationJob.jsonPayload.optString("alert"), - ) + return notificationJob.hasExtender() || + AndroidUtils.isStringNotEmpty( + notificationJob.jsonPayload.optString("alert"), + ) } /** @@ -234,31 +242,44 @@ internal class NotificationGenerationProcessor( // * Collapse key / id support - Used to lookup the android notification id later // * Redisplay notifications after reboot, upgrade of app, or cold boot after a force kill. // * Future - Public API to get a list of notifications - private suspend fun saveNotification(notificationJob: NotificationGenerationJob, opened: Boolean) { + private suspend fun saveNotification( + notificationJob: NotificationGenerationJob, + opened: Boolean, + ) { Logging.debug("Saving Notification job: $notificationJob") val jsonPayload = notificationJob.jsonPayload try { val customJSON = getCustomJSONObject(jsonPayload) - val collapseKey: String? = if (jsonPayload.has("collapse_key") && "do_not_collapse" != jsonPayload.optString("collapse_key")) jsonPayload.optString("collapse_key") else null + val collapseKey: String? = + if (jsonPayload.has("collapse_key") && "do_not_collapse" != jsonPayload.optString("collapse_key")) { + jsonPayload.optString( + "collapse_key", + ) + } else { + null + } // Set expire_time - val sentTime = jsonPayload.optLong( - NotificationConstants.GOOGLE_SENT_TIME_KEY, - _time.currentTimeMillis, - ) / 1000L - val ttl = jsonPayload.optInt( - NotificationConstants.GOOGLE_TTL_KEY, - NotificationConstants.DEFAULT_TTL_IF_NOT_IN_PAYLOAD, - ) + val sentTime = + jsonPayload.optLong( + NotificationConstants.GOOGLE_SENT_TIME_KEY, + _time.currentTimeMillis, + ) / 1000L + val ttl = + jsonPayload.optInt( + NotificationConstants.GOOGLE_TTL_KEY, + NotificationConstants.DEFAULT_TTL_IF_NOT_IN_PAYLOAD, + ) val expireTime = sentTime + ttl _dataController.createNotification( customJSON.optString("i"), jsonPayload.safeString("grp"), collapseKey, - notificationJob.isNotificationToDisplay, // When notification was displayed, count any notifications with duplicated android notification ids as dismissed. + // When notification was displayed, count any notifications with duplicated android notification ids as dismissed. + notificationJob.isNotificationToDisplay, opened, notificationJob.androidId, if (notificationJob.title != null) notificationJob.title.toString() else null, diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationWorkManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationWorkManager.kt index 574fc4d3e3..cf60d362ac 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationWorkManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/generation/impl/NotificationGenerationWorkManager.kt @@ -18,7 +18,6 @@ import org.json.JSONObject import java.util.concurrent.ConcurrentHashMap internal class NotificationGenerationWorkManager : INotificationGenerationWorkManager { - override fun beginEnqueueingWork( context: Context, osNotificationId: String, @@ -41,17 +40,21 @@ internal class NotificationGenerationWorkManager : INotificationGenerationWorkMa } // TODO: Need to figure out how to implement the isHighPriority param - val inputData = Data.Builder() - .putString(OS_ID_DATA_PARAM, id) - .putInt(ANDROID_NOTIF_ID_WORKER_DATA_PARAM, androidNotificationId) - .putString(JSON_PAYLOAD_WORKER_DATA_PARAM, jsonPayload.toString()) - .putLong(TIMESTAMP_WORKER_DATA_PARAM, timestamp) - .putBoolean(IS_RESTORING_WORKER_DATA_PARAM, isRestoring) - .build() - val workRequest = OneTimeWorkRequest.Builder(NotificationGenerationWorker::class.java) - .setInputData(inputData) - .build() - Logging.debug("NotificationWorkManager enqueueing notification work with notificationId: $osNotificationId and jsonPayload: $jsonPayload") + val inputData = + Data.Builder() + .putString(OS_ID_DATA_PARAM, id) + .putInt(ANDROID_NOTIF_ID_WORKER_DATA_PARAM, androidNotificationId) + .putString(JSON_PAYLOAD_WORKER_DATA_PARAM, jsonPayload.toString()) + .putLong(TIMESTAMP_WORKER_DATA_PARAM, timestamp) + .putBoolean(IS_RESTORING_WORKER_DATA_PARAM, isRestoring) + .build() + val workRequest = + OneTimeWorkRequest.Builder(NotificationGenerationWorker::class.java) + .setInputData(inputData) + .build() + Logging.debug( + "NotificationWorkManager enqueueing notification work with notificationId: $osNotificationId and jsonPayload: $jsonPayload", + ) WorkManager.getInstance(context) .enqueueUniqueWork(osNotificationId, ExistingWorkPolicy.KEEP, workRequest) @@ -75,7 +78,13 @@ internal class NotificationGenerationWorkManager : INotificationGenerationWorkMa val timestamp = inputData.getLong(TIMESTAMP_WORKER_DATA_PARAM, System.currentTimeMillis() / 1000L) val isRestoring = inputData.getBoolean(IS_RESTORING_WORKER_DATA_PARAM, false) - notificationProcessor.processNotificationData(applicationContext, androidNotificationId, jsonPayload, isRestoring, timestamp) + notificationProcessor.processNotificationData( + applicationContext, + androidNotificationId, + jsonPayload, + isRestoring, + timestamp, + ) } catch (e: JSONException) { Logging.error("Error occurred doing work for job with id: $id", e) return Result.failure() diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleCallback.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleCallback.kt index e0ce7f2967..1c6f8150c2 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleCallback.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleCallback.kt @@ -15,5 +15,9 @@ interface INotificationLifecycleCallback { * @return True if the callback does *not* want the bundle processor to process the bundle, false otherwise. */ suspend fun canReceiveNotification(jsonPayload: JSONObject): Boolean - suspend fun canOpenNotification(activity: Activity, jsonData: JSONObject): Boolean + + suspend fun canOpenNotification( + activity: Activity, + jsonData: JSONObject, + ): Boolean } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleEventHandler.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleEventHandler.kt index 7ac047cc2a..96a111c297 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleEventHandler.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleEventHandler.kt @@ -9,5 +9,10 @@ interface INotificationLifecycleEventHandler { * Called *after* the notification has been generated and processed by the SDK. */ suspend fun onNotificationReceived(notificationJob: NotificationGenerationJob) - suspend fun onNotificationOpened(activity: Activity, data: JSONArray, notificationId: String) + + suspend fun onNotificationOpened( + activity: Activity, + data: JSONArray, + notificationId: String, + ) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleService.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleService.kt index 1a6dd0cb69..f4175b758e 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleService.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/INotificationLifecycleService.kt @@ -40,17 +40,35 @@ import org.json.JSONObject */ interface INotificationLifecycleService { fun addInternalNotificationLifecycleEventHandler(handler: INotificationLifecycleEventHandler) + fun removeInternalNotificationLifecycleEventHandler(handler: INotificationLifecycleEventHandler) + fun setInternalNotificationLifecycleCallback(callback: INotificationLifecycleCallback?) + fun addExternalForegroundLifecycleListener(listener: INotificationLifecycleListener) + fun removeExternalForegroundLifecycleListener(listener: INotificationLifecycleListener) + fun addExternalClickListener(listener: INotificationClickListener) + fun removeExternalClickListener(listener: INotificationClickListener) suspend fun canReceiveNotification(jsonPayload: JSONObject): Boolean + fun externalRemoteNotificationReceived(notificationReceivedEvent: INotificationReceivedEvent) + fun externalNotificationWillShowInForeground(willDisplayEvent: INotificationWillDisplayEvent) + suspend fun notificationReceived(notificationJob: NotificationGenerationJob) - suspend fun canOpenNotification(activity: Activity, data: JSONObject): Boolean - suspend fun notificationOpened(activity: Activity, data: JSONArray, notificationId: String) + + suspend fun canOpenNotification( + activity: Activity, + data: JSONObject, + ): Boolean + + suspend fun notificationOpened( + activity: Activity, + data: JSONArray, + notificationId: String, + ) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/impl/NotificationLifecycleService.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/impl/NotificationLifecycleService.kt index e5fb55290d..3c8d022c6f 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/impl/NotificationLifecycleService.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/lifecycle/impl/NotificationLifecycleService.kt @@ -26,32 +26,48 @@ internal class NotificationLifecycleService( applicationService: IApplicationService, private val _time: ITime, ) : INotificationLifecycleService { + private val intLifecycleHandler = EventProducer() + private val intLifecycleCallback = CallbackProducer() + private val extRemoteReceivedCallback = CallbackProducer() + private val extWillShowInForegroundCallback = EventProducer() + private val extOpenedCallback = EventProducer() + private val unprocessedOpenedNotifs: ArrayDeque = ArrayDeque() + + override fun addInternalNotificationLifecycleEventHandler(handler: INotificationLifecycleEventHandler) = + intLifecycleHandler.subscribe( + handler, + ) + + override fun removeInternalNotificationLifecycleEventHandler(handler: INotificationLifecycleEventHandler) = + intLifecycleHandler.unsubscribe( + handler, + ) + + override fun setInternalNotificationLifecycleCallback(callback: INotificationLifecycleCallback?) = intLifecycleCallback.set(callback) + + override fun addExternalForegroundLifecycleListener(listener: INotificationLifecycleListener) = + extWillShowInForegroundCallback.subscribe( + listener, + ) + + override fun removeExternalForegroundLifecycleListener(listener: INotificationLifecycleListener) = + extWillShowInForegroundCallback.unsubscribe( + listener, + ) - private val _intLifecycleHandler = EventProducer() - private val _intLifecycleCallback = CallbackProducer() - private val _extRemoteReceivedCallback = CallbackProducer() - private val _extWillShowInForegroundCallback = EventProducer() - private val _extOpenedCallback = EventProducer() - private val _unprocessedOpenedNotifs: ArrayDeque = ArrayDeque() - - override fun addInternalNotificationLifecycleEventHandler(handler: INotificationLifecycleEventHandler) = _intLifecycleHandler.subscribe(handler) - override fun removeInternalNotificationLifecycleEventHandler(handler: INotificationLifecycleEventHandler) = _intLifecycleHandler.unsubscribe(handler) - override fun setInternalNotificationLifecycleCallback(callback: INotificationLifecycleCallback?) = _intLifecycleCallback.set(callback) - override fun addExternalForegroundLifecycleListener(listener: INotificationLifecycleListener) = _extWillShowInForegroundCallback.subscribe(listener) - override fun removeExternalForegroundLifecycleListener(listener: INotificationLifecycleListener) = _extWillShowInForegroundCallback.unsubscribe(listener) override fun addExternalClickListener(callback: INotificationClickListener) { - _extOpenedCallback.subscribe(callback) + extOpenedCallback.subscribe(callback) // Ensure we process any queued up notifications that came in prior to this being set. - if (_extOpenedCallback.hasSubscribers && _unprocessedOpenedNotifs.any()) { - for (data in _unprocessedOpenedNotifs) { + if (extOpenedCallback.hasSubscribers && unprocessedOpenedNotifs.any()) { + for (data in unprocessedOpenedNotifs) { val openedResult = NotificationHelper.generateNotificationOpenedResult(data, _time) - _extOpenedCallback.fireOnMain { it.onClick(openedResult) } + extOpenedCallback.fireOnMain { it.onClick(openedResult) } } } } - override fun removeExternalClickListener(listener: INotificationClickListener) = _extOpenedCallback.unsubscribe(listener) + override fun removeExternalClickListener(listener: INotificationClickListener) = extOpenedCallback.unsubscribe(listener) init { setupNotificationServiceExtension(applicationService.appContext) @@ -59,39 +75,46 @@ internal class NotificationLifecycleService( override suspend fun canReceiveNotification(jsonPayload: JSONObject): Boolean { var canReceive = true - _intLifecycleCallback.suspendingFire { canReceive = it.canReceiveNotification(jsonPayload) } + intLifecycleCallback.suspendingFire { canReceive = it.canReceiveNotification(jsonPayload) } return canReceive } override suspend fun notificationReceived(notificationJob: NotificationGenerationJob) { - _intLifecycleHandler.suspendingFire { it.onNotificationReceived(notificationJob) } + intLifecycleHandler.suspendingFire { it.onNotificationReceived(notificationJob) } } - override suspend fun canOpenNotification(activity: Activity, data: JSONObject): Boolean { + override suspend fun canOpenNotification( + activity: Activity, + data: JSONObject, + ): Boolean { var canOpen = false - _intLifecycleCallback.suspendingFire { canOpen = it.canOpenNotification(activity, data) } + intLifecycleCallback.suspendingFire { canOpen = it.canOpenNotification(activity, data) } return canOpen } - override suspend fun notificationOpened(activity: Activity, data: JSONArray, notificationId: String) { - _intLifecycleHandler.suspendingFire { it.onNotificationOpened(activity, data, notificationId) } + override suspend fun notificationOpened( + activity: Activity, + data: JSONArray, + notificationId: String, + ) { + intLifecycleHandler.suspendingFire { it.onNotificationOpened(activity, data, notificationId) } // queue up the opened notification in case the handler hasn't been set yet. Once set, // we will immediately fire the handler. - if (_extOpenedCallback.hasSubscribers) { + if (extOpenedCallback.hasSubscribers) { val openResult = NotificationHelper.generateNotificationOpenedResult(data, _time) - _extOpenedCallback.fireOnMain { it.onClick(openResult) } + extOpenedCallback.fireOnMain { it.onClick(openResult) } } else { - _unprocessedOpenedNotifs.add(data) + unprocessedOpenedNotifs.add(data) } } override fun externalRemoteNotificationReceived(notificationReceivedEvent: INotificationReceivedEvent) { - _extRemoteReceivedCallback.fire { it.onNotificationReceived(notificationReceivedEvent) } + extRemoteReceivedCallback.fire { it.onNotificationReceived(notificationReceivedEvent) } } override fun externalNotificationWillShowInForeground(willDisplayEvent: INotificationWillDisplayEvent) { - _extWillShowInForegroundCallback.fire { it.onWillDisplay(willDisplayEvent) } + extWillShowInForegroundCallback.fire { it.onWillDisplay(willDisplayEvent) } } /** @@ -128,8 +151,8 @@ internal class NotificationLifecycleService( val clazz = Class.forName(className) val clazzInstance = clazz.newInstance() // Make sure a OSRemoteNotificationReceivedHandler exists and remoteNotificationReceivedHandler has not been set yet - if (clazzInstance is INotificationServiceExtension && !_extRemoteReceivedCallback.hasCallback) { - _extRemoteReceivedCallback.set(clazzInstance) + if (clazzInstance is INotificationServiceExtension && !extRemoteReceivedCallback.hasCallback) { + extRemoteReceivedCallback.set(clazzInstance) } } catch (e: IllegalAccessException) { e.printStackTrace() diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/limiting/INotificationLimitManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/limiting/INotificationLimitManager.kt index 433ca1df4b..0403bf4737 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/limiting/INotificationLimitManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/limiting/INotificationLimitManager.kt @@ -12,7 +12,6 @@ package com.onesignal.notifications.internal.limiting * NotificationManagerService.java in the AOSP source. */ internal interface INotificationLimitManager { - /** * Cancel the oldest notifications to make room for new notifications we are about to display * If we don't make this room users will NOT be alerted of new notifications for the app. diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/limiting/impl/NotificationLimitManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/limiting/impl/NotificationLimitManager.kt index 090987c17c..4203be82ee 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/limiting/impl/NotificationLimitManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/limiting/impl/NotificationLimitManager.kt @@ -15,17 +15,22 @@ internal class NotificationLimitManager( private val _applicationService: IApplicationService, private val _notificationSummaryManager: INotificationSummaryManager, ) : INotificationLimitManager { - override suspend fun clearOldestOverLimit(notificationsToMakeRoomFor: Int) { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { clearOldestOverLimitStandard(notificationsToMakeRoomFor) } else { - _dataController.clearOldestOverLimitFallback(notificationsToMakeRoomFor, INotificationLimitManager.Constants.maxNumberOfNotifications) + _dataController.clearOldestOverLimitFallback( + notificationsToMakeRoomFor, + INotificationLimitManager.Constants.maxNumberOfNotifications, + ) } } catch (t: Throwable) { // try-catch for Android 6.0.X and possibly 8.0.0 bug work around, getActiveNotifications bug - _dataController.clearOldestOverLimitFallback(notificationsToMakeRoomFor, INotificationLimitManager.Constants.maxNumberOfNotifications) + _dataController.clearOldestOverLimitFallback( + notificationsToMakeRoomFor, + INotificationLimitManager.Constants.maxNumberOfNotifications, + ) } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/listeners/DeviceRegistrationListener.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/listeners/DeviceRegistrationListener.kt index 9017ef2214..49b9f95e2e 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/listeners/DeviceRegistrationListener.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/listeners/DeviceRegistrationListener.kt @@ -33,7 +33,6 @@ internal class DeviceRegistrationListener( ISingletonModelStoreChangeHandler, IPermissionObserver, ISubscriptionChangedHandler { - override fun start() { _configModelStore.subscribe(this) _notificationsManager.addPermissionObserver(this) @@ -42,7 +41,10 @@ internal class DeviceRegistrationListener( retrievePushTokenAndUpdateSubscription() } - override fun onModelReplaced(model: ConfigModel, tag: String) { + override fun onModelReplaced( + model: ConfigModel, + tag: String, + ) { // we only need to do things when the config model was replaced // via a hydration from the backend. if (tag != ModelChangeTags.HYDRATE) { @@ -54,7 +56,10 @@ internal class DeviceRegistrationListener( retrievePushTokenAndUpdateSubscription() } - override fun onModelUpdated(args: ModelChangedArgs, tag: String) { + override fun onModelUpdated( + args: ModelChangedArgs, + tag: String, + ) { } override fun onNotificationPermissionChange(permission: Boolean) { @@ -66,7 +71,10 @@ internal class DeviceRegistrationListener( if (pushSubscription.token.isNotEmpty()) { val permission = _notificationsManager.permission - _subscriptionManager.addOrUpdatePushSubscription(null, if (permission) SubscriptionStatus.SUBSCRIBED else SubscriptionStatus.NO_PERMISSION) + _subscriptionManager.addOrUpdatePushSubscription( + null, + if (permission) SubscriptionStatus.SUBSCRIBED else SubscriptionStatus.NO_PERMISSION, + ) } else { suspendifyOnThread { val pushTokenAndStatus = _pushTokenManager.retrievePushToken() @@ -80,8 +88,13 @@ internal class DeviceRegistrationListener( } override fun onSubscriptionRemoved(subscription: ISubscription) { } + override fun onSubscriptionAdded(subscription: ISubscription) { } - override fun onSubscriptionChanged(subscription: ISubscription, args: ModelChangedArgs) { + + override fun onSubscriptionChanged( + subscription: ISubscription, + args: ModelChangedArgs, + ) { // when setting optedIn=true and there aren't permissions, automatically drive // permission request. if (args.path == SubscriptionModel::optedIn.name && args.newValue == true && !_notificationsManager.permission) { diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/listeners/NotificationListener.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/listeners/NotificationListener.kt index 4a7d53e262..b74195d4da 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/listeners/NotificationListener.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/listeners/NotificationListener.kt @@ -39,8 +39,7 @@ internal class NotificationListener( private val _analyticsTracker: IAnalyticsTracker, private val _time: ITime, ) : IStartableService, INotificationLifecycleEventHandler { - - private val _postedOpenedNotifIds = mutableSetOf() + private val postedOpenedNotifIds = mutableSetOf() override fun start() { _notificationLifecycleService.addInternalNotificationLifecycleEventHandler(this) @@ -56,7 +55,10 @@ internal class NotificationListener( jsonObject.put(NotificationConstants.BUNDLE_KEY_ANDROID_NOTIFICATION_ID, notificationJob.androidId) val openResult = NotificationHelper.generateNotificationOpenedResult(JSONUtils.wrapInJsonArray(jsonObject), _time) - _analyticsTracker.trackReceivedEvent(openResult.notification.notificationId!!, NotificationHelper.getCampaignNameFromNotification(openResult.notification)) + _analyticsTracker.trackReceivedEvent( + openResult.notification.notificationId!!, + NotificationHelper.getCampaignNameFromNotification(openResult.notification), + ) } catch (e: JSONException) { e.printStackTrace() } @@ -73,10 +75,10 @@ internal class NotificationListener( val deviceType = _deviceService.deviceType for (i in 0 until data.length()) { - if (_postedOpenedNotifIds.contains(notificationId)) { + if (postedOpenedNotifIds.contains(notificationId)) { continue } - _postedOpenedNotifIds.add(notificationId) + postedOpenedNotifIds.add(notificationId) try { _backend.updateNotificationAsOpened( @@ -91,7 +93,10 @@ internal class NotificationListener( } val openResult = NotificationHelper.generateNotificationOpenedResult(data, _time) - _analyticsTracker.trackOpenedEvent(openResult.notification.notificationId!!, NotificationHelper.getCampaignNameFromNotification(openResult.notification)) + _analyticsTracker.trackOpenedEvent( + openResult.notification.notificationId!!, + NotificationHelper.getCampaignNameFromNotification(openResult.notification), + ) if (shouldInitDirectSessionFromNotificationOpen(activity)) { // We want to set the app entry state to NOTIFICATION_CLICK when coming from background diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/INotificationOpenedProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/INotificationOpenedProcessor.kt index f4b753bb90..138cee21f0 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/INotificationOpenedProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/INotificationOpenedProcessor.kt @@ -10,5 +10,8 @@ internal interface INotificationOpenedProcessor { * @param context Either the open activity or the dismiss receiver context. * @param intent The user intent that drove the open/dismiss. */ - suspend fun processFromContext(context: Context, intent: Intent) + suspend fun processFromContext( + context: Context, + intent: Intent, + ) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/INotificationOpenedProcessorHMS.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/INotificationOpenedProcessorHMS.kt index 0856be02cd..61ba90d1a6 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/INotificationOpenedProcessorHMS.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/INotificationOpenedProcessorHMS.kt @@ -4,5 +4,8 @@ import android.app.Activity import android.content.Intent internal interface INotificationOpenedProcessorHMS { - suspend fun handleHMSNotificationOpenIntent(activity: Activity, intent: Intent?) + suspend fun handleHMSNotificationOpenIntent( + activity: Activity, + intent: Intent?, + ) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/impl/NotificationOpenedProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/impl/NotificationOpenedProcessor.kt index 2ed4c6af23..d36df1b013 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/impl/NotificationOpenedProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/impl/NotificationOpenedProcessor.kt @@ -54,8 +54,10 @@ internal class NotificationOpenedProcessor( private val _configModelStore: ConfigModelStore, private val _lifecycleService: INotificationLifecycleService, ) : INotificationOpenedProcessor { - - override suspend fun processFromContext(context: Context, intent: Intent) { + override suspend fun processFromContext( + context: Context, + intent: Intent, + ) { if (!isOneSignalIntent(intent)) { return } @@ -67,13 +69,17 @@ internal class NotificationOpenedProcessor( // Was Bundle created from our SDK? Prevents external Intents // TODO: Could most likely be simplified checking if BUNDLE_KEY_ONESIGNAL_DATA is present private fun isOneSignalIntent(intent: Intent): Boolean { - return intent.hasExtra(NotificationConstants.BUNDLE_KEY_ONESIGNAL_DATA) || intent.hasExtra("summary") || intent.hasExtra( - NotificationConstants.BUNDLE_KEY_ANDROID_NOTIFICATION_ID, - ) + return intent.hasExtra(NotificationConstants.BUNDLE_KEY_ONESIGNAL_DATA) || intent.hasExtra("summary") || + intent.hasExtra( + NotificationConstants.BUNDLE_KEY_ANDROID_NOTIFICATION_ID, + ) } @SuppressLint("MissingPermission") - private fun handleDismissFromActionButtonPress(context: Context?, intent: Intent) { + private fun handleDismissFromActionButtonPress( + context: Context?, + intent: Intent, + ) { // Pressed an action button, need to clear the notification and close the notification area manually. if (intent.getBooleanExtra("action_button", false)) { NotificationManagerCompat.from(context!!).cancel( @@ -91,7 +97,10 @@ internal class NotificationOpenedProcessor( } } - private suspend fun processIntent(context: Context, intent: Intent) { + private suspend fun processIntent( + context: Context, + intent: Intent, + ) { val summaryGroup = intent.getStringExtra("summary") val dismissed = intent.getBooleanExtra("dismissed", false) var intentExtras: NotificationIntentExtras? = null @@ -119,7 +128,11 @@ internal class NotificationOpenedProcessor( if (context !is Activity) { Logging.error("NotificationOpenedProcessor processIntent from an non Activity context: $context") } else { - _lifecycleService.notificationOpened(context, intentExtras!!.dataArray, NotificationFormatHelper.getOSNotificationIdFromJson(intentExtras.jsonData)!!) + _lifecycleService.notificationOpened( + context, + intentExtras!!.dataArray, + NotificationFormatHelper.getOSNotificationIdFromJson(intentExtras.jsonData)!!, + ) } } } @@ -145,9 +158,10 @@ internal class NotificationOpenedProcessor( intent.getIntExtra(NotificationConstants.BUNDLE_KEY_ANDROID_NOTIFICATION_ID, 0), ) intent.putExtra(NotificationConstants.BUNDLE_KEY_ONESIGNAL_DATA, jsonData.toString()) - dataArray = JSONUtils.wrapInJsonArray( - JSONObject(intent.getStringExtra(NotificationConstants.BUNDLE_KEY_ONESIGNAL_DATA)), - ) + dataArray = + JSONUtils.wrapInJsonArray( + JSONObject(intent.getStringExtra(NotificationConstants.BUNDLE_KEY_ONESIGNAL_DATA)), + ) } catch (e: JSONException) { e.printStackTrace() } @@ -160,7 +174,10 @@ internal class NotificationOpenedProcessor( return NotificationIntentExtras(dataArray!!, jsonData!!) } - private suspend fun addChildNotifications(dataArray: JSONArray, summaryGroup: String) { + private suspend fun addChildNotifications( + dataArray: JSONArray, + summaryGroup: String, + ) { val childNotifications = _dataController.listNotificationsForGroup(summaryGroup) for (childNotification in childNotifications) dataArray.put(JSONObject(childNotification.fullData)) @@ -185,7 +202,10 @@ internal class NotificationOpenedProcessor( /** * Handles clearing the status bar notifications when opened */ - private suspend fun clearStatusBarNotifications(context: Context, summaryGroup: String?) { + private suspend fun clearStatusBarNotifications( + context: Context, + summaryGroup: String?, + ) { // Handling for clearing the notification when opened if (summaryGroup != null) { _summaryManager.clearNotificationOnSummaryClick(summaryGroup) @@ -195,7 +215,7 @@ internal class NotificationOpenedProcessor( // Check that no more groupless notifications exist in the group and cancel the group val grouplessCount = NotificationHelper.getGrouplessNotifsCount(context) if (grouplessCount < 1) { - val groupId = NotificationHelper.grouplessSummaryId + val groupId = NotificationHelper.GROUPLESS_SUMMARY_ID val notificationManager = NotificationHelper.getNotificationManager(context) notificationManager.cancel(groupId) diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/impl/NotificationOpenedProcessorHMS.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/impl/NotificationOpenedProcessorHMS.kt index 02112a67e0..389ffcfda1 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/impl/NotificationOpenedProcessorHMS.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/open/impl/NotificationOpenedProcessorHMS.kt @@ -14,13 +14,16 @@ import org.json.JSONObject internal class NotificationOpenedProcessorHMS( private val _lifecycleService: INotificationLifecycleService, ) : INotificationOpenedProcessorHMS { - - override suspend fun handleHMSNotificationOpenIntent(activity: Activity, intent: Intent?) { + override suspend fun handleHMSNotificationOpenIntent( + activity: Activity, + intent: Intent?, + ) { if (intent == null) return - val jsonData = covertHMSOpenIntentToJson( - intent, - ) - ?: return + val jsonData = + covertHMSOpenIntentToJson( + intent, + ) + ?: return handleProcessJsonOpenData(activity, jsonData) } @@ -52,11 +55,18 @@ internal class NotificationOpenedProcessorHMS( } } - private suspend fun handleProcessJsonOpenData(activity: Activity, jsonData: JSONObject) { + private suspend fun handleProcessJsonOpenData( + activity: Activity, + jsonData: JSONObject, + ) { if (!_lifecycleService.canOpenNotification(activity, jsonData)) { return } - _lifecycleService.notificationOpened(activity, JSONUtils.wrapInJsonArray(jsonData), NotificationFormatHelper.getOSNotificationIdFromJson(jsonData)!!) + _lifecycleService.notificationOpened( + activity, + JSONUtils.wrapInJsonArray(jsonData), + NotificationFormatHelper.getOSNotificationIdFromJson(jsonData)!!, + ) } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/permissions/impl/NotificationPermissionController.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/permissions/impl/NotificationPermissionController.kt index b524770bd6..df4683989b 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/permissions/impl/NotificationPermissionController.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/permissions/impl/NotificationPermissionController.kt @@ -51,16 +51,16 @@ internal class NotificationPermissionController( private val _preferenceService: IPreferencesService, ) : IRequestPermissionService.PermissionCallback, INotificationPermissionController { - - private val _waiter = WaiterWithValue() - private val _events = EventProducer() + private val waiter = WaiterWithValue() + private val events = EventProducer() override val canRequestPermission: Boolean - get() = !_preferenceService.getBool( - PreferenceStores.ONESIGNAL, - "${PreferenceOneSignalKeys.PREFS_OS_USER_RESOLVED_PERMISSION_PREFIX}$ANDROID_PERMISSION_STRING", - false, - )!! + get() = + !_preferenceService.getBool( + PreferenceStores.ONESIGNAL, + "${PreferenceOneSignalKeys.PREFS_OS_USER_RESOLVED_PERMISSION_PREFIX}$ANDROID_PERMISSION_STRING", + false, + )!! init { _requestPermission.registerAsCallback(PERMISSION_TYPE, this) @@ -103,17 +103,19 @@ internal class NotificationPermissionController( // this won't return until onAccept or onReject sends the response on the channel (either // through the native prompt or through the fallback) - return _waiter.waitForWake() + return waiter.waitForWake() } - override fun subscribe(handler: INotificationPermissionChangedHandler) = _events.subscribe(handler) - override fun unsubscribe(handler: INotificationPermissionChangedHandler) = _events.subscribe(handler) + override fun subscribe(handler: INotificationPermissionChangedHandler) = events.subscribe(handler) + + override fun unsubscribe(handler: INotificationPermissionChangedHandler) = events.subscribe(handler) + override val hasSubscribers: Boolean - get() = _events.hasSubscribers + get() = events.hasSubscribers override fun onAccept() { - _waiter.wake(true) - _events.fire { it.onNotificationPermissionChanged(true) } + waiter.wake(true) + events.fire { it.onNotificationPermissionChanged(true) } } override fun onReject(fallbackToSettings: Boolean) { @@ -125,8 +127,8 @@ internal class NotificationPermissionController( } if (!fallbackShown) { - _waiter.wake(false) - _events.fire { it.onNotificationPermissionChanged(false) } + waiter.wake(false) + events.fire { it.onNotificationPermissionChanged(false) } } } @@ -141,20 +143,23 @@ internal class NotificationPermissionController( object : AlertDialogPrepromptForAndroidSettings.Callback { override fun onAccept() { // wait for focus to be regained, and check the current permission status. - _applicationService.addApplicationLifecycleHandler(object : ApplicationLifecycleHandlerBase() { - override fun onFocus() { - super.onFocus() - _applicationService.removeApplicationLifecycleHandler(this) - val hasPermission = AndroidUtils.hasPermission(ANDROID_PERMISSION_STRING, true, _applicationService) - _waiter.wake(hasPermission) - _events.fire { it.onNotificationPermissionChanged(hasPermission) } - } - }) + _applicationService.addApplicationLifecycleHandler( + object : ApplicationLifecycleHandlerBase() { + override fun onFocus() { + super.onFocus() + _applicationService.removeApplicationLifecycleHandler(this) + val hasPermission = AndroidUtils.hasPermission(ANDROID_PERMISSION_STRING, true, _applicationService) + waiter.wake(hasPermission) + events.fire { it.onNotificationPermissionChanged(hasPermission) } + } + }, + ) NavigateToAndroidSettingsForNotifications.show(activity) } + override fun onDecline() { - _waiter.wake(false) - _events.fire { it.onNotificationPermissionChanged(false) } + waiter.wake(false) + events.fire { it.onNotificationPermissionChanged(false) } } }, ) diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/pushtoken/PushTokenManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/pushtoken/PushTokenManager.kt index 657419e80a..1e5b65c60e 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/pushtoken/PushTokenManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/pushtoken/PushTokenManager.kt @@ -22,7 +22,9 @@ internal class PushTokenManager( pushTokenStatus = SubscriptionStatus.MISSING_ANDROID_SUPPORT_LIBRARY } IDeviceService.AndroidSupportLibraryStatus.OUTDATED -> { - Logging.fatal("The included Android Support Library is too old or incomplete. Please update to the 26.0.0 revision or newer.") + Logging.fatal( + "The included Android Support Library is too old or incomplete. Please update to the 26.0.0 revision or newer.", + ) pushTokenStatus = SubscriptionStatus.OUTDATED_ANDROID_SUPPORT_LIBRARY } else -> { @@ -39,7 +41,7 @@ internal class PushTokenManager( ( pushTokenStatus == SubscriptionStatus.NO_PERMISSION || pushStatusRuntimeError(pushTokenStatus) - ) + ) ) { pushTokenStatus = registerResult.status } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/IReceiveReceiptProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/IReceiveReceiptProcessor.kt index d2fd3b700f..77cb6cec38 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/IReceiveReceiptProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/IReceiveReceiptProcessor.kt @@ -6,7 +6,6 @@ package com.onesignal.notifications.internal.receivereceipt * assurance of success. */ internal interface IReceiveReceiptProcessor { - /** * Send the receive receipt to the backend on the current thread. * @@ -14,5 +13,9 @@ internal interface IReceiveReceiptProcessor { * @param subscriptionId The id of the subscription the notification was received under. * @param notificationId The id of the notification that has been received. */ - suspend fun sendReceiveReceipt(appId: String, subscriptionId: String, notificationId: String) + suspend fun sendReceiveReceipt( + appId: String, + subscriptionId: String, + notificationId: String, + ) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/IReceiveReceiptWorkManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/IReceiveReceiptWorkManager.kt index 447c9a6b09..9bcfc22a42 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/IReceiveReceiptWorkManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/IReceiveReceiptWorkManager.kt @@ -6,7 +6,6 @@ package com.onesignal.notifications.internal.receivereceipt * as the worker will persist across the application lifecycle. */ internal interface IReceiveReceiptWorkManager { - /** * Enqueue a worker which will send receipt of receiving a notification. * diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/impl/ReceiveReceiptProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/impl/ReceiveReceiptProcessor.kt index 8b2b305a35..ad7827d11a 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/impl/ReceiveReceiptProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/impl/ReceiveReceiptProcessor.kt @@ -10,8 +10,11 @@ internal class ReceiveReceiptProcessor( private val _deviceService: IDeviceService, private val _backend: INotificationBackendService, ) : IReceiveReceiptProcessor { - - override suspend fun sendReceiveReceipt(appId: String, subscriptionId: String, notificationId: String) { + override suspend fun sendReceiveReceipt( + appId: String, + subscriptionId: String, + notificationId: String, + ) { val deviceType = _deviceService.deviceType try { diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/impl/ReceiveReceiptWorkManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/impl/ReceiveReceiptWorkManager.kt index d2e58d882f..cd281463c5 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/impl/ReceiveReceiptWorkManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/receivereceipt/impl/ReceiveReceiptWorkManager.kt @@ -24,7 +24,6 @@ internal class ReceiveReceiptWorkManager( private val _configModelStore: ConfigModelStore, private val _subscriptionManager: ISubscriptionManager, ) : IReceiveReceiptWorkManager { - private val minDelay = 0 private val maxDelay = 25 @@ -42,18 +41,22 @@ internal class ReceiveReceiptWorkManager( } val delay: Int = AndroidUtils.getRandomDelay(minDelay, maxDelay) - val inputData = Data.Builder() - .putString(OS_NOTIFICATION_ID, notificationId) - .putString(OS_APP_ID, appId) - .putString(OS_SUBSCRIPTION_ID, subscriptionId) - .build() + val inputData = + Data.Builder() + .putString(OS_NOTIFICATION_ID, notificationId) + .putString(OS_APP_ID, appId) + .putString(OS_SUBSCRIPTION_ID, subscriptionId) + .build() val constraints = buildConstraints() - val workRequest = OneTimeWorkRequest.Builder(ReceiveReceiptWorker::class.java) - .setConstraints(constraints) - .setInitialDelay(delay.toLong(), TimeUnit.SECONDS) - .setInputData(inputData) - .build() - Logging.debug("OSReceiveReceiptController enqueueing send receive receipt work with notificationId: $notificationId and delay: $delay seconds") + val workRequest = + OneTimeWorkRequest.Builder(ReceiveReceiptWorker::class.java) + .setConstraints(constraints) + .setInitialDelay(delay.toLong(), TimeUnit.SECONDS) + .setInputData(inputData) + .build() + Logging.debug( + "OSReceiveReceiptController enqueueing send receive receipt work with notificationId: $notificationId and delay: $delay seconds", + ) WorkManager.getInstance(_applicationService.appContext) .enqueueUniqueWork( notificationId + "_receive_receipt", @@ -69,14 +72,14 @@ internal class ReceiveReceiptWorkManager( } class ReceiveReceiptWorker(context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) { - private var _receiveReceiptProcessor: IReceiveReceiptProcessor = OneSignal.getService() + private var receiveReceiptProcessor: IReceiveReceiptProcessor = OneSignal.getService() override suspend fun doWork(): Result { val inputData = inputData val notificationId = inputData.getString(OS_NOTIFICATION_ID)!! val appId = inputData.getString(OS_APP_ID)!! val subscriptionId = inputData.getString(OS_SUBSCRIPTION_ID)!! - _receiveReceiptProcessor.sendReceiveReceipt(appId, subscriptionId, notificationId) + receiveReceiptProcessor.sendReceiveReceipt(appId, subscriptionId, notificationId) return Result.success() } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/GooglePlayServicesUpgradePrompt.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/GooglePlayServicesUpgradePrompt.kt index b011371703..2419ca4fb6 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/GooglePlayServicesUpgradePrompt.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/GooglePlayServicesUpgradePrompt.kt @@ -22,10 +22,11 @@ internal class GooglePlayServicesUpgradePrompt( private get() { try { val pm = _applicationService.appContext.packageManager - val info = pm.getPackageInfo( - GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE, - PackageManager.GET_META_DATA, - ) + val info = + pm.getPackageInfo( + GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE, + PackageManager.GET_META_DATA, + ) val label = info.applicationInfo.loadLabel(pm) as String return label != "Market" } catch (e: PackageManager.NameNotFoundException) { @@ -47,26 +48,30 @@ internal class GooglePlayServicesUpgradePrompt( val activity = _applicationService.current ?: return@withContext // Load resource strings so a developer can customize this dialog - val alertBodyText = AndroidUtils.getResourceString( - activity, - "onesignal_gms_missing_alert_text", - "To receive push notifications please press 'Update' to enable 'Google Play services'.", - ) - val alertButtonUpdate = AndroidUtils.getResourceString( - activity, - "onesignal_gms_missing_alert_button_update", - "Update", - ) - val alertButtonSkip = AndroidUtils.getResourceString( - activity, - "onesignal_gms_missing_alert_button_skip", - "Skip", - ) - val alertButtonClose = AndroidUtils.getResourceString( - activity, - "onesignal_gms_missing_alert_button_close", - "Close", - ) + val alertBodyText = + AndroidUtils.getResourceString( + activity, + "onesignal_gms_missing_alert_text", + "To receive push notifications please press 'Update' to enable 'Google Play services'.", + ) + val alertButtonUpdate = + AndroidUtils.getResourceString( + activity, + "onesignal_gms_missing_alert_button_update", + "Update", + ) + val alertButtonSkip = + AndroidUtils.getResourceString( + activity, + "onesignal_gms_missing_alert_button_skip", + "Skip", + ) + val alertButtonClose = + AndroidUtils.getResourceString( + activity, + "onesignal_gms_missing_alert_button_close", + "Close", + ) val builder = AlertDialog.Builder(activity) builder.setMessage(alertBodyText) @@ -83,11 +88,12 @@ internal class GooglePlayServicesUpgradePrompt( val apiAvailability = GoogleApiAvailability.getInstance() val resultCode = apiAvailability.isGooglePlayServicesAvailable(_applicationService.appContext) // Send the Intent to trigger opening the store - val pendingIntent = apiAvailability.getErrorResolutionPendingIntent( - activity, - resultCode, - PLAY_SERVICES_RESOLUTION_REQUEST, - ) + val pendingIntent = + apiAvailability.getErrorResolutionPendingIntent( + activity, + resultCode, + PLAY_SERVICES_RESOLUTION_REQUEST, + ) pendingIntent?.send() } catch (e: CanceledException) { e.printStackTrace() diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorADM.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorADM.kt index 9319c2a52f..98d1611302 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorADM.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorADM.kt @@ -11,50 +11,51 @@ import kotlinx.coroutines.withTimeout internal class PushRegistratorADM( private val _applicationService: IApplicationService, ) : IPushRegistrator, IPushRegistratorCallback { - - private var _waiter: WaiterWithValue? = null + private var waiter: WaiterWithValue? = null override suspend fun registerForPush(): IPushRegistrator.RegisterResult { var result: IPushRegistrator.RegisterResult? = null - _waiter = WaiterWithValue() + waiter = WaiterWithValue() val adm = ADM(_applicationService.appContext) var registrationId = adm.registrationId if (registrationId != null) { Logging.debug("ADM Already registered with ID:$registrationId") - result = IPushRegistrator.RegisterResult( - registrationId, - SubscriptionStatus.SUBSCRIBED, - ) + result = + IPushRegistrator.RegisterResult( + registrationId, + SubscriptionStatus.SUBSCRIBED, + ) } else { adm.startRegister() // wait up to 30 seconds for someone to call `fireCallback` with the registration id. // if it comes before we will continue immediately. withTimeout(30000) { - registrationId = _waiter?.waitForWake() + registrationId = waiter?.waitForWake() } - result = if (registrationId != null) { - Logging.error("ADM registered with ID:$registrationId") - IPushRegistrator.RegisterResult( - registrationId, - SubscriptionStatus.SUBSCRIBED, - ) - } else { - Logging.error("com.onesignal.ADMMessageHandler timed out, please check that your have the receiver, service, and your package name matches(NOTE: Case Sensitive) per the OneSignal instructions.") - IPushRegistrator.RegisterResult( - null, - SubscriptionStatus.ERROR, - ) - } + result = + if (registrationId != null) { + Logging.error("ADM registered with ID:$registrationId") + IPushRegistrator.RegisterResult( + registrationId, + SubscriptionStatus.SUBSCRIBED, + ) + } else { + Logging.error("com.onesignal.ADMMessageHandler timed out, please check that your have the receiver, service, and your package name matches(NOTE: Case Sensitive) per the OneSignal instructions.") + IPushRegistrator.RegisterResult( + null, + SubscriptionStatus.ERROR, + ) + } } return result!! } override suspend fun fireCallback(id: String?) { - _waiter?.wake(id) + waiter?.wake(id) } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorAbstractGoogle.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorAbstractGoogle.kt index 34ccfbd021..6f082b04eb 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorAbstractGoogle.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorAbstractGoogle.kt @@ -61,7 +61,9 @@ internal abstract class PushRegistratorAbstractGoogle( } return if (!isValidProjectNumber(_configModelStore.model.googleProjectNumber)) { - Logging.error("Missing Google Project number!\nPlease enter a Google Project number / Sender ID on under App Settings > Android > Configuration on the OneSignal dashboard.") + Logging.error( + "Missing Google Project number!\nPlease enter a Google Project number / Sender ID on under App Settings > Android > Configuration on the OneSignal dashboard.", + ) IPushRegistrator.RegisterResult( null, SubscriptionStatus.INVALID_FCM_SENDER_ID, @@ -117,7 +119,10 @@ internal abstract class PushRegistratorAbstractGoogle( ) } - private suspend fun attemptRegistration(senderId: String, currentRetry: Int): IPushRegistrator.RegisterResult? { + private suspend fun attemptRegistration( + senderId: String, + currentRetry: Int, + ): IPushRegistrator.RegisterResult? { try { val registrationId = getToken(senderId) Logging.info("Device registered, push token = $registrationId") @@ -175,12 +180,13 @@ internal abstract class PushRegistratorAbstractGoogle( } private fun isValidProjectNumber(senderId: String?): Boolean { - val isProjectNumberValidFormat: Boolean = try { - senderId!!.toFloat() - true - } catch (t: Throwable) { - false - } + val isProjectNumberValidFormat: Boolean = + try { + senderId!!.toFloat() + true + } catch (t: Throwable) { + false + } if (!isProjectNumberValidFormat) { return false diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorFCM.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorFCM.kt index f96333f1be..af396a093b 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorFCM.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorFCM.kt @@ -23,7 +23,6 @@ internal class PushRegistratorFCM( upgradePrompt: GooglePlayServicesUpgradePrompt, deviceService: IDeviceService, ) : PushRegistratorAbstractGoogle(deviceService, _configModelStore, upgradePrompt) { - companion object { private const val FCM_APP_NAME = "ONESIGNAL_SDK_FCM_APP_NAME" @@ -75,72 +74,76 @@ internal class PushRegistratorFCM( // - This version of Firebase has completely removed FirebaseInstanceId @Deprecated("") @Throws(IOException::class) - private suspend fun getTokenWithClassFirebaseInstanceId(senderId: String): String = coroutineScope { - var token: String = "" - // The following code is equivalent to: - // FirebaseInstanceId instanceId = FirebaseInstanceId.getInstance(firebaseApp); - // return instanceId.getToken(senderId, FirebaseMessaging.INSTANCE_ID_SCOPE); - val exception: Exception = try { - val firebaseInstanceIdClass = Class.forName("com.google.firebase.iid.FirebaseInstanceId") - val getInstanceMethod = firebaseInstanceIdClass.getMethod("getInstance", FirebaseApp::class.java) - val instanceId = getInstanceMethod.invoke(null, firebaseApp) - val getTokenMethod = instanceId.javaClass.getMethod("getToken", String::class.java, String::class.java) - - launch(Dispatchers.Default) { - val tkn = getTokenMethod.invoke(instanceId, senderId, "FCM") - token = tkn as String - } - - return@coroutineScope token - } catch (e: ClassNotFoundException) { - e - } catch (e: NoSuchMethodException) { - e - } catch (e: IllegalAccessException) { - e - } catch (e: InvocationTargetException) { - e + private suspend fun getTokenWithClassFirebaseInstanceId(senderId: String): String = + coroutineScope { + var token: String = "" + // The following code is equivalent to: + // FirebaseInstanceId instanceId = FirebaseInstanceId.getInstance(firebaseApp); + // return instanceId.getToken(senderId, FirebaseMessaging.INSTANCE_ID_SCOPE); + val exception: Exception = + try { + val firebaseInstanceIdClass = Class.forName("com.google.firebase.iid.FirebaseInstanceId") + val getInstanceMethod = firebaseInstanceIdClass.getMethod("getInstance", FirebaseApp::class.java) + val instanceId = getInstanceMethod.invoke(null, firebaseApp) + val getTokenMethod = instanceId.javaClass.getMethod("getToken", String::class.java, String::class.java) + + launch(Dispatchers.Default) { + val tkn = getTokenMethod.invoke(instanceId, senderId, "FCM") + token = tkn as String + } + + return@coroutineScope token + } catch (e: ClassNotFoundException) { + e + } catch (e: NoSuchMethodException) { + e + } catch (e: IllegalAccessException) { + e + } catch (e: InvocationTargetException) { + e + } + + throw Error( + "Reflection error on FirebaseInstanceId.getInstance(firebaseApp).getToken(senderId, FirebaseMessaging.INSTANCE_ID_SCOPE)", + exception, + ) } - throw Error( - "Reflection error on FirebaseInstanceId.getInstance(firebaseApp).getToken(senderId, FirebaseMessaging.INSTANCE_ID_SCOPE)", - exception, - ) - } - // We use firebaseApp.get(FirebaseMessaging.class) instead of FirebaseMessaging.getInstance() // as the latter uses the default Firebase app. We need to use a custom Firebase app as // the senderId is provided at runtime. @Throws(ExecutionException::class, InterruptedException::class) - private suspend fun getTokenWithClassFirebaseMessaging(): String = coroutineScope { - var token: String = "" - - withContext(Dispatchers.Default) { - // FirebaseMessaging.getToken API was introduced in firebase-messaging:21.0.0 - // We use firebaseApp.get(FirebaseMessaging.class) instead of FirebaseMessaging.getInstance() - // as the latter uses the default Firebase app. We need to use a custom Firebase app as - // the senderId is provided at runtime. - val fcmInstance = firebaseApp!!.get(FirebaseMessaging::class.java) - // FirebaseMessaging.getToken API was introduced in firebase-messaging:21.0.0 - val tokenTask = fcmInstance.token - try { - token = Tasks.await(tokenTask) - } catch (e: ExecutionException) { - throw tokenTask.exception + private suspend fun getTokenWithClassFirebaseMessaging(): String = + coroutineScope { + var token: String = "" + + withContext(Dispatchers.Default) { + // FirebaseMessaging.getToken API was introduced in firebase-messaging:21.0.0 + // We use firebaseApp.get(FirebaseMessaging.class) instead of FirebaseMessaging.getInstance() + // as the latter uses the default Firebase app. We need to use a custom Firebase app as + // the senderId is provided at runtime. + val fcmInstance = firebaseApp!!.get(FirebaseMessaging::class.java) + // FirebaseMessaging.getToken API was introduced in firebase-messaging:21.0.0 + val tokenTask = fcmInstance.token + try { + token = Tasks.await(tokenTask) + } catch (e: ExecutionException) { + throw tokenTask.exception + } } - } - return@coroutineScope token - } + return@coroutineScope token + } private fun initFirebaseApp(senderId: String) { if (firebaseApp != null) return - val firebaseOptions = FirebaseOptions.Builder() - .setGcmSenderId(senderId) - .setApplicationId(appId) - .setApiKey(apiKey) - .setProjectId(projectId) - .build() + val firebaseOptions = + FirebaseOptions.Builder() + .setGcmSenderId(senderId) + .setApplicationId(appId) + .setApiKey(apiKey) + .setProjectId(projectId) + .build() firebaseApp = FirebaseApp.initializeApp(_applicationService.appContext, firebaseOptions, FCM_APP_NAME) } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorHMS.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorHMS.kt index faf0732383..7d0c6ff9b8 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorHMS.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/registration/impl/PushRegistratorHMS.kt @@ -20,29 +20,29 @@ internal class PushRegistratorHMS( private val _applicationService: IApplicationService, ) : IPushRegistrator, IPushRegistratorCallback { - companion object { private const val HMS_CLIENT_APP_ID = "client/app_id" } - private var _waiter: WaiterWithValue? = null + private var waiter: WaiterWithValue? = null override suspend fun registerForPush(): IPushRegistrator.RegisterResult { var result: IPushRegistrator.RegisterResult? = null - result = try { - getHMSTokenTask(_applicationService.appContext) - } catch (e: ApiException) { - Logging.error("HMS ApiException getting Huawei push token!", e) - val pushStatus: SubscriptionStatus = - if (e.statusCode == CommonCode.ErrorCode.ARGUMENTS_INVALID) { - SubscriptionStatus.HMS_ARGUMENTS_INVALID - } else { - SubscriptionStatus.HMS_API_EXCEPTION_OTHER - } + result = + try { + getHMSTokenTask(_applicationService.appContext) + } catch (e: ApiException) { + Logging.error("HMS ApiException getting Huawei push token!", e) + val pushStatus: SubscriptionStatus = + if (e.statusCode == CommonCode.ErrorCode.ARGUMENTS_INVALID) { + SubscriptionStatus.HMS_ARGUMENTS_INVALID + } else { + SubscriptionStatus.HMS_API_EXCEPTION_OTHER + } - IPushRegistrator.RegisterResult(null, pushStatus) - } + IPushRegistrator.RegisterResult(null, pushStatus) + } return result!! } @@ -59,7 +59,7 @@ internal class PushRegistratorHMS( ) } - _waiter = WaiterWithValue() + waiter = WaiterWithValue() val appId = AGConnectServicesConfig.fromContext(context).getString(HMS_CLIENT_APP_ID) val hmsInstanceId = HmsInstanceId.getInstance(context) var pushToken = hmsInstanceId.getToken(appId, HmsMessaging.DEFAULT_TOKEN_SCOPE) @@ -75,7 +75,7 @@ internal class PushRegistratorHMS( // wait up to 30 seconds for someone to call `fireCallback` with the registration id. // if it comes before we will continue immediately. withTimeout(30000) { - pushToken = _waiter?.waitForWake() + pushToken = waiter?.waitForWake() } return if (pushToken != null) { @@ -95,6 +95,6 @@ internal class PushRegistratorHMS( } override suspend fun fireCallback(id: String?) { - _waiter?.wake(id) + waiter?.wake(id) } } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/INotificationRestoreProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/INotificationRestoreProcessor.kt index 5c88ff85eb..73bf7afdf8 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/INotificationRestoreProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/INotificationRestoreProcessor.kt @@ -5,5 +5,8 @@ import com.onesignal.notifications.internal.data.INotificationRepository internal interface INotificationRestoreProcessor { suspend fun process() - suspend fun processNotification(notification: INotificationRepository.NotificationData, delay: Int = 0) + suspend fun processNotification( + notification: INotificationRepository.NotificationData, + delay: Int = 0, + ) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/INotificationRestoreWorkManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/INotificationRestoreWorkManager.kt index 34af8161c4..9e437fb6f9 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/INotificationRestoreWorkManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/INotificationRestoreWorkManager.kt @@ -3,5 +3,8 @@ package com.onesignal.notifications.internal.restoration import android.content.Context internal interface INotificationRestoreWorkManager { - fun beginEnqueueingWork(context: Context, shouldDelay: Boolean) + fun beginEnqueueingWork( + context: Context, + shouldDelay: Boolean, + ) } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/impl/NotificationRestoreProcessor.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/impl/NotificationRestoreProcessor.kt index fcf3cb1381..d00de6ce8d 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/impl/NotificationRestoreProcessor.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/impl/NotificationRestoreProcessor.kt @@ -34,7 +34,10 @@ internal class NotificationRestoreProcessor( } } - override suspend fun processNotification(notification: INotificationRepository.NotificationData, delay: Int) { + override suspend fun processNotification( + notification: INotificationRepository.NotificationData, + delay: Int, + ) { _workManager.beginEnqueueingWork( _applicationService.appContext, notification.id, diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/impl/NotificationRestoreWorkManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/impl/NotificationRestoreWorkManager.kt index cbe519631d..b97d123daf 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/impl/NotificationRestoreWorkManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/restoration/impl/NotificationRestoreWorkManager.kt @@ -13,12 +13,14 @@ import com.onesignal.notifications.internal.restoration.INotificationRestoreWork import java.util.concurrent.TimeUnit internal class NotificationRestoreWorkManager : INotificationRestoreWorkManager { - // Notifications will never be force removed when the app's process is running, // so we only need to restore at most once per cold start of the app. private var restored = false - override fun beginEnqueueingWork(context: Context, shouldDelay: Boolean) { + override fun beginEnqueueingWork( + context: Context, + shouldDelay: Boolean, + ) { // Only allow one piece of work to be enqueued. synchronized(restored) { if (restored) { @@ -30,9 +32,10 @@ internal class NotificationRestoreWorkManager : INotificationRestoreWorkManager // When boot or upgrade, add a 15 second delay to alleviate app doing to much work all at once val restoreDelayInSeconds = if (shouldDelay) 15 else 0 - val workRequest = OneTimeWorkRequest.Builder(NotificationRestoreWorker::class.java) - .setInitialDelay(restoreDelayInSeconds.toLong(), TimeUnit.SECONDS) - .build() + val workRequest = + OneTimeWorkRequest.Builder(NotificationRestoreWorker::class.java) + .setInitialDelay(restoreDelayInSeconds.toLong(), TimeUnit.SECONDS) + .build() WorkManager.getInstance(context!!) .enqueueUniqueWork( NOTIFICATION_RESTORE_WORKER_IDENTIFIER, diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/summary/INotificationSummaryManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/summary/INotificationSummaryManager.kt index e837ef47e2..cc34e6060b 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/summary/INotificationSummaryManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/summary/INotificationSummaryManager.kt @@ -5,7 +5,10 @@ internal interface INotificationSummaryManager { suspend fun updatePossibleDependentSummaryOnDismiss(androidNotificationId: Int) // Called from an opened / dismissed / cancel event of a single notification to update it's parent the summary notification. - suspend fun updateSummaryNotificationAfterChildRemoved(group: String, dismissed: Boolean) + suspend fun updateSummaryNotificationAfterChildRemoved( + group: String, + dismissed: Boolean, + ) /** * Clears notifications from the status bar based on a few parameters diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/summary/impl/NotificationSummaryManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/summary/impl/NotificationSummaryManager.kt index 0bf9c29ec0..f5acb7d0d0 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/summary/impl/NotificationSummaryManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/summary/impl/NotificationSummaryManager.kt @@ -20,7 +20,6 @@ internal class NotificationSummaryManager( private val _notificationRestoreProcessor: INotificationRestoreProcessor, private val _time: ITime, ) : INotificationSummaryManager { - // A notification was just dismissed, check if it was a child to a summary notification and update it. override suspend fun updatePossibleDependentSummaryOnDismiss(androidNotificationId: Int) { val groupId = _dataController.getGroupId(androidNotificationId) @@ -31,11 +30,17 @@ internal class NotificationSummaryManager( } // Called from an opened / dismissed / cancel event of a single notification to update it's parent the summary notification. - override suspend fun updateSummaryNotificationAfterChildRemoved(group: String, dismissed: Boolean) { + override suspend fun updateSummaryNotificationAfterChildRemoved( + group: String, + dismissed: Boolean, + ) { internalUpdateSummaryNotificationAfterChildRemoved(group, dismissed) } - private suspend fun internalUpdateSummaryNotificationAfterChildRemoved(group: String, dismissed: Boolean) { + private suspend fun internalUpdateSummaryNotificationAfterChildRemoved( + group: String, + dismissed: Boolean, + ) { var notifications = _dataController.listNotificationsForGroup(group) val notificationsInGroup = notifications.count() @@ -95,13 +100,14 @@ internal class NotificationSummaryManager( if (mostRecentId != null) { val shouldDismissAll = _configModelStore.model.clearGroupOnSummaryClick if (shouldDismissAll) { - val groupId = if (group == NotificationHelper.grouplessSummaryKey) { - // If the group is groupless, obtain the hardcoded groupless summary id - NotificationHelper.grouplessSummaryId - } else { - // Obtain the group to clear notifications from - _dataController.getAndroidIdForGroup(group, true) - } + val groupId = + if (group == NotificationHelper.GROUPLESS_SUMMARY_KEY) { + // If the group is groupless, obtain the hardcoded groupless summary id + NotificationHelper.GROUPLESS_SUMMARY_ID + } else { + // Obtain the group to clear notifications from + _dataController.getAndroidIdForGroup(group, true) + } // Clear the entire notification summary if (groupId != null) { diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/ADMMessageReceiver.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/ADMMessageReceiver.kt index 1c236dd3d7..746a3e38ab 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/ADMMessageReceiver.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/ADMMessageReceiver.kt @@ -8,17 +8,17 @@ import com.onesignal.notifications.services.ADMMessageHandlerJob // when "proguard-android-optimize.txt" is used. class ADMMessageReceiver : com.amazon.device.messaging.ADMMessageReceiver(ADMMessageHandler::class.java) { init { - var ADMLatestAvailable = false + var admLatestAvailable = false try { Class.forName("com.amazon.device.messaging.ADMMessageHandlerJobBase") - ADMLatestAvailable = true + admLatestAvailable = true } catch (e: ClassNotFoundException) { // Handle the exception. } - if (ADMLatestAvailable) { + if (admLatestAvailable) { registerJobServiceClass(ADMMessageHandlerJob::class.java, JOB_ID) } - Logging.debug("ADM latest available: $ADMLatestAvailable") + Logging.debug("ADM latest available: $admLatestAvailable") } companion object { diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/BootUpReceiver.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/BootUpReceiver.kt index 2fa1b79bcc..208f427ebe 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/BootUpReceiver.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/BootUpReceiver.kt @@ -33,7 +33,10 @@ import com.onesignal.OneSignal import com.onesignal.notifications.internal.restoration.INotificationRestoreWorkManager class BootUpReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { + override fun onReceive( + context: Context, + intent: Intent, + ) { if (!OneSignal.initWithContext(context)) { return } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/FCMBroadcastReceiver.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/FCMBroadcastReceiver.kt index 9f2f1f86d0..fe8062f662 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/FCMBroadcastReceiver.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/FCMBroadcastReceiver.kt @@ -12,8 +12,10 @@ import com.onesignal.notifications.internal.bundle.INotificationBundleProcessor // to be setup in an app. See the following issue for context on why this this important: // - https://github.com/OneSignal/OneSignal-Android-SDK/issues/1355 class FCMBroadcastReceiver : BroadcastReceiver() { - - override fun onReceive(context: Context, intent: Intent) { + override fun onReceive( + context: Context, + intent: Intent, + ) { // Do not process token update messages here. // They are also non-ordered broadcasts. val bundle = intent.extras @@ -70,6 +72,7 @@ class FCMBroadcastReceiver : BroadcastReceiver() { private const val FCM_RECEIVE_ACTION = "com.google.android.c2dm.intent.RECEIVE" private const val FCM_TYPE = "gcm" private const val MESSAGE_TYPE_EXTRA_KEY = "message_type" + private fun isFCMMessage(intent: Intent): Boolean { if (FCM_RECEIVE_ACTION == intent.action) { val messageType = intent.getStringExtra(MESSAGE_TYPE_EXTRA_KEY) diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/NotificationDismissReceiver.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/NotificationDismissReceiver.kt index 5bb9c31d51..560d2b417a 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/NotificationDismissReceiver.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/NotificationDismissReceiver.kt @@ -32,7 +32,10 @@ import com.onesignal.common.threading.suspendifyBlocking import com.onesignal.notifications.internal.open.INotificationOpenedProcessor class NotificationDismissReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { + override fun onReceive( + context: Context, + intent: Intent, + ) { if (!OneSignal.initWithContext(context.applicationContext)) { return } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/UpgradeReceiver.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/UpgradeReceiver.kt index ecd5e5e026..d6ed9e4782 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/UpgradeReceiver.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/receivers/UpgradeReceiver.kt @@ -34,7 +34,10 @@ import com.onesignal.OneSignal import com.onesignal.notifications.internal.restoration.INotificationRestoreWorkManager class UpgradeReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { + override fun onReceive( + context: Context, + intent: Intent, + ) { // TODO: Now that we arent restoring like we use to, think we can remove this? Ill do some // testing and look at the issue but maybe someone has a answer or rems what directly // was causing this issue diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/ADMMessageHandler.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/ADMMessageHandler.kt index 3ae013b955..e53f87eb15 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/ADMMessageHandler.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/ADMMessageHandler.kt @@ -11,7 +11,6 @@ import com.onesignal.notifications.internal.registration.impl.IPushRegistratorCa // WARNING: Do not pass 'this' to any methods as it will cause proguard build errors // when "proguard-android-optimize.txt" is used. class ADMMessageHandler : ADMMessageHandlerBase("ADMMessageHandler") { - override fun onMessage(intent: Intent) { val context = applicationContext val bundle = intent.extras @@ -34,7 +33,9 @@ class ADMMessageHandler : ADMMessageHandlerBase("ADMMessageHandler") { Logging.error("ADM:onRegistrationError: $error") if ("INVALID_SENDER" == error) { - Logging.error("Please double check that you have a matching package name (NOTE: Case Sensitive), api_key.txt, and the apk was signed with the same Keystore and Alias.") + Logging.error( + "Please double check that you have a matching package name (NOTE: Case Sensitive), api_key.txt, and the apk was signed with the same Keystore and Alias.", + ) } var registerer = OneSignal.getService() diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/ADMMessageHandlerJob.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/ADMMessageHandlerJob.kt index 6d6d156309..ec96fd793b 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/ADMMessageHandlerJob.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/ADMMessageHandlerJob.kt @@ -10,8 +10,10 @@ import com.onesignal.notifications.internal.bundle.INotificationBundleProcessor import com.onesignal.notifications.internal.registration.impl.IPushRegistratorCallback class ADMMessageHandlerJob : ADMMessageHandlerJobBase() { - - override fun onMessage(context: Context?, intent: Intent?) { + override fun onMessage( + context: Context?, + intent: Intent?, + ) { val bundle = intent?.extras val bundleProcessor = OneSignal.getService() @@ -19,7 +21,10 @@ class ADMMessageHandlerJob : ADMMessageHandlerJobBase() { bundleProcessor.processBundleFromReceiver(context!!, bundle!!) } - override fun onRegistered(context: Context?, newRegistrationId: String?) { + override fun onRegistered( + context: Context?, + newRegistrationId: String?, + ) { Logging.info("ADM registration ID: $newRegistrationId") var registerer = OneSignal.getService() @@ -28,14 +33,22 @@ class ADMMessageHandlerJob : ADMMessageHandlerJobBase() { } } - override fun onUnregistered(context: Context?, registrationId: String?) { + override fun onUnregistered( + context: Context?, + registrationId: String?, + ) { Logging.info("ADM:onUnregistered: $registrationId") } - override fun onRegistrationError(context: Context?, error: String?) { + override fun onRegistrationError( + context: Context?, + error: String?, + ) { Logging.error("ADM:onRegistrationError: $error") if ("INVALID_SENDER" == error) { - Logging.error("Please double check that you have a matching package name (NOTE: Case Sensitive), api_key.txt, and the apk was signed with the same Keystore and Alias.") + Logging.error( + "Please double check that you have a matching package name (NOTE: Case Sensitive), api_key.txt, and the apk was signed with the same Keystore and Alias.", + ) } var registerer = OneSignal.getService() diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/HmsMessageServiceOneSignal.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/HmsMessageServiceOneSignal.kt index f8299f9ef5..fbd41f8c1f 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/HmsMessageServiceOneSignal.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/services/HmsMessageServiceOneSignal.kt @@ -30,7 +30,10 @@ class HmsMessageServiceOneSignal : HmsMessageService() { * @param token token * @param bundle bundle */ - override fun onNewToken(token: String, bundle: Bundle) { + override fun onNewToken( + token: String, + bundle: Bundle, + ) { Logging.debug("HmsMessageServiceOneSignal onNewToken refresh token:$token") OneSignalHmsEventBridge.onNewToken(this, token, bundle) } diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/ContainedRobolectricRunner.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/ContainedRobolectricRunner.kt index ab3f0f4dd4..fa722e93ad 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/ContainedRobolectricRunner.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/ContainedRobolectricRunner.kt @@ -17,11 +17,13 @@ internal class ContainedRobolectricRunner( private val config: Config?, ) : RobolectricTestRunner(PlaceholderTest::class.java, injector) { private val placeHolderMethod: FrameworkMethod = children[0] - val sdkEnvironment = getSandbox(placeHolderMethod).also { - configureSandbox(it, placeHolderMethod) - } - private val bootStrapMethod = sdkEnvironment.bootstrappedClass(testClass.javaClass) - .getMethod(PlaceholderTest::bootStrapMethod.name) + val sdkEnvironment = + getSandbox(placeHolderMethod).also { + configureSandbox(it, placeHolderMethod) + } + private val bootStrapMethod = + sdkEnvironment.bootstrappedClass(testClass.javaClass) + .getMethod(PlaceholderTest::bootStrapMethod.name) fun containedBefore() { Thread.currentThread().contextClassLoader = sdkEnvironment.robolectricClassLoader @@ -41,8 +43,9 @@ internal class ContainedRobolectricRunner( } override fun getConfig(method: Method?): Config { - val defaultConfiguration = injector.getInstance(ConfigurationStrategy::class.java) - .getConfig(testClass.javaClass, method) + val defaultConfiguration = + injector.getInstance(ConfigurationStrategy::class.java) + .getConfig(testClass.javaClass, method) if (config != null) { val configConfigurer = injector.getInstance(ConfigConfigurer::class.java) diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/RobolectricExtension.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/RobolectricExtension.kt index 570e7285eb..3250906490 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/RobolectricExtension.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/extensions/RobolectricExtension.kt @@ -30,9 +30,10 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { } private fun KClass<*>.getConfig(): Config { - val configAnnotations = listOf(this.java).plus(this.java.getParentClass()) - .mapNotNull { it.kotlin.findAnnotation() } - .asSequence() + val configAnnotations = + listOf(this.java).plus(this.java.getParentClass()) + .mapNotNull { it.kotlin.findAnnotation() } + .asSequence() val configAnnotation = configAnnotations.firstOrNull() @@ -40,12 +41,14 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { return Config.Builder(configAnnotation).build() } - val robolectricTestAnnotations = listOf(this.java).plus(this.java.getParentClass()) - .mapNotNull { it.kotlin.findAnnotation() } - .asSequence() + val robolectricTestAnnotations = + listOf(this.java).plus(this.java.getParentClass()) + .mapNotNull { it.kotlin.findAnnotation() } + .asSequence() - val application: KClass? = robolectricTestAnnotations - .firstOrNull { it.application != KotestDefaultApplication::class }?.application + val application: KClass? = + robolectricTestAnnotations + .firstOrNull { it.application != KotestDefaultApplication::class }?.application val sdk: Int? = robolectricTestAnnotations.firstOrNull { it.sdk != -1 }?.takeUnless { it.sdk == -1 }?.sdk return Config.Builder() @@ -72,9 +75,10 @@ internal class RobolectricExtension : ConstructorExtension, TestCaseExtension { execute: suspend (TestCase) -> TestResult, ): TestResult { // FIXED: Updated code based on https://github.com/kotest/kotest/issues/2717 - val hasRobolectricAnnotation = testCase.spec::class.annotations.any { annotation -> - annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName - } + val hasRobolectricAnnotation = + testCase.spec::class.annotations.any { annotation -> + annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName + } if (!hasRobolectricAnnotation) { return execute(testCase) diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/backend/NotificationBackendServiceTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/backend/NotificationBackendServiceTests.kt index b37941fd7a..db435e53a1 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/backend/NotificationBackendServiceTests.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/backend/NotificationBackendServiceTests.kt @@ -23,16 +23,21 @@ class NotificationBackendServiceTests : FunSpec({ } test("updateNotificationAsReceived succeeds when response is successful") { - /* Given */ + // Given val spyHttpClient = mockk() coEvery { spyHttpClient.put(any(), any()) } returns HttpResponse(202, null) val notificationBackendService = NotificationBackendService(spyHttpClient) - /* When */ - notificationBackendService.updateNotificationAsReceived("appId", "notificationId", "subscriptionId", IDeviceService.DeviceType.Android) + // When + notificationBackendService.updateNotificationAsReceived( + "appId", + "notificationId", + "subscriptionId", + IDeviceService.DeviceType.Android, + ) - /* Then */ + // Then coVerify { spyHttpClient.put( "notifications/notificationId/report_received", @@ -46,37 +51,43 @@ class NotificationBackendServiceTests : FunSpec({ } test("updateNotificationAsReceived throws exception when response is unsuccessful") { - /* Given */ + // Given val spyHttpClient = mockk() coEvery { spyHttpClient.put(any(), any()) } returns HttpResponse(404, null) val notificationBackendService = NotificationBackendService(spyHttpClient) - /* When */ - val exception = shouldThrowUnit { - notificationBackendService.updateNotificationAsReceived( - "appId", - "notificationId", - "subscriptionId", - IDeviceService.DeviceType.Android, - ) - } - - /* Then */ + // When + val exception = + shouldThrowUnit { + notificationBackendService.updateNotificationAsReceived( + "appId", + "notificationId", + "subscriptionId", + IDeviceService.DeviceType.Android, + ) + } + + // Then exception.statusCode shouldBe 404 } test("updateNotificationAsOpened succeeds when response is successful") { - /* Given */ + // Given val spyHttpClient = mockk() coEvery { spyHttpClient.put(any(), any()) } returns HttpResponse(202, null) val notificationBackendService = NotificationBackendService(spyHttpClient) - /* When */ - notificationBackendService.updateNotificationAsOpened("appId", "notificationId", "subscriptionId", IDeviceService.DeviceType.Android) + // When + notificationBackendService.updateNotificationAsOpened( + "appId", + "notificationId", + "subscriptionId", + IDeviceService.DeviceType.Android, + ) - /* Then */ + // Then coVerify { spyHttpClient.put( "notifications/notificationId", @@ -91,23 +102,24 @@ class NotificationBackendServiceTests : FunSpec({ } test("updateNotificationAsOpened throws exception when response is unsuccessful") { - /* Given */ + // Given val spyHttpClient = mockk() coEvery { spyHttpClient.put(any(), any()) } returns HttpResponse(404, null) val notificationBackendService = NotificationBackendService(spyHttpClient) - /* When */ - val exception = shouldThrowUnit { - notificationBackendService.updateNotificationAsOpened( - "appId", - "notificationId", - "subscriptionId", - IDeviceService.DeviceType.Android, - ) - } - - /* Then */ + // When + val exception = + shouldThrowUnit { + notificationBackendService.updateNotificationAsOpened( + "appId", + "notificationId", + "subscriptionId", + IDeviceService.DeviceType.Android, + ) + } + + // Then exception.statusCode shouldBe 404 } }) diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/channels/NotificationChannelManagerTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/channels/NotificationChannelManagerTests.kt index 9137bfc5e3..a5fa36f336 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/channels/NotificationChannelManagerTests.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/channels/NotificationChannelManagerTests.kt @@ -36,15 +36,15 @@ class NotificationChannelManagerTests : FunSpec({ } test("createNotificationChannel should return default channel with empty payload") { - /* Given */ + // Given val mockTime = MockHelper.time(1111) val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) - /* When */ + // When val response = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(JSONObject(), mockTime)) - /* Then */ + // Then response shouldBe "fcm_fallback_notification_channel" val lastChannel = ShadowRoboNotificationManager.lastChannel @@ -56,21 +56,22 @@ class NotificationChannelManagerTests : FunSpec({ } test("createNotificationChannel should create basic channel") { - /* Given */ + // Given val mockTime = MockHelper.time(1111) val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) - val payload = JSONObject() - .put( - "chnl", - JSONObject() - .put("id", "test_id"), - ) - - /* When */ + val payload = + JSONObject() + .put( + "chnl", + JSONObject() + .put("id", "test_id"), + ) + + // When val response = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) - /* Then */ + // Then response shouldBe "test_id" val lastChannel = ShadowRoboNotificationManager.lastChannel @@ -82,34 +83,35 @@ class NotificationChannelManagerTests : FunSpec({ } test("createNotificationChannel with all options") { - /* Given */ + // Given val mockTime = MockHelper.time(1111) val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) - val payload = JSONObject() - .put("pri", 10) - .put("led", 0) - .put("ledc", "FFFF0000") - .put("vib", 0) - .put("vib_pt", JSONArray("[1,2,3,4]")) - .put("sound", "notification") - .put("vis", Notification.VISIBILITY_SECRET) - .put("bdg", 1) - .put("bdnd", 1) - .put( - "chnl", - JSONObject() - .put("id", "test_id") - .put("nm", "Test Name") - .put("dscr", "Some description") - .put("grp_id", "grp_id") - .put("grp_nm", "Group Name"), - ) - - /* When */ + val payload = + JSONObject() + .put("pri", 10) + .put("led", 0) + .put("ledc", "FFFF0000") + .put("vib", 0) + .put("vib_pt", JSONArray("[1,2,3,4]")) + .put("sound", "notification") + .put("vis", Notification.VISIBILITY_SECRET) + .put("bdg", 1) + .put("bdnd", 1) + .put( + "chnl", + JSONObject() + .put("id", "test_id") + .put("nm", "Test Name") + .put("dscr", "Some description") + .put("grp_id", "grp_id") + .put("grp_nm", "Group Name"), + ) + + // When val response = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) - /* Then */ + // Then response shouldBe "test_id" val lastChannel = ShadowRoboNotificationManager.lastChannel @@ -141,42 +143,44 @@ class NotificationChannelManagerTests : FunSpec({ } test("createNotificationChannel use other channel when available") { - /* Given */ + // Given val mockTime = MockHelper.time(1111) val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) - val payload = JSONObject() - .put("oth_chnl", "existing_id") - .put("chnl", JSONObject().put("id", "test_id")) + val payload = + JSONObject() + .put("oth_chnl", "existing_id") + .put("chnl", JSONObject().put("id", "test_id")) - /* When */ + // When val response1 = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) createChannel("existing_id", ApplicationProvider.getApplicationContext()) val response2 = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) - /* Then */ + // Then response1 shouldBe "test_id" response2 shouldBe "existing_id" } test("createNotificationChannel with invalid color should revert to FFFFFFFF") { - /* Given */ + // Given val mockTime = MockHelper.time(1111) val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) - val payload = JSONObject() - .put("ledc", "FFFFFFFFY") - .put( - "chnl", - JSONObject() - .put("id", "test_id") - .put("nm", "Test Name"), - ) - - /* When */ + val payload = + JSONObject() + .put("ledc", "FFFFFFFFY") + .put( + "chnl", + JSONObject() + .put("id", "test_id") + .put("nm", "Test Name"), + ) + + // When val response = notificationChannelManager.createNotificationChannel(NotificationGenerationJob(payload, mockTime)) - /* Then */ + // Then val lastChannel = ShadowRoboNotificationManager.lastChannel response shouldBe "test_id" lastChannel shouldNotBe null @@ -184,92 +188,95 @@ class NotificationChannelManagerTests : FunSpec({ } test("processChannelList with no channel list should keep existing channels") { - /* Given */ + // Given val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) createChannel("local_existing_id", ApplicationProvider.getApplicationContext()) createChannel("OS_existing_id", ApplicationProvider.getApplicationContext()) - /* When */ + // When notificationChannelManager.processChannelList(null) - /* Then */ + // Then getChannel("local_existing_id", ApplicationProvider.getApplicationContext()) shouldNotBe null getChannel("OS_existing_id", ApplicationProvider.getApplicationContext()) shouldNotBe null } test("processChannelList with existing local channel should not delete local channel") { - /* Given */ + // Given val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) createChannel("local_existing_id", ApplicationProvider.getApplicationContext()) - val payload = JSONArray() - .put( - JSONObject() - .put("chnl", JSONObject().put("id", "OS_id1")), - ) + val payload = + JSONArray() + .put( + JSONObject() + .put("chnl", JSONObject().put("id", "OS_id1")), + ) - /* When */ + // When notificationChannelManager.processChannelList(payload) - /* Then */ + // Then getChannel("local_existing_id", ApplicationProvider.getApplicationContext()) shouldNotBe null getChannel("OS_id1", ApplicationProvider.getApplicationContext()) shouldNotBe null } test("processChannelList with existing OS channel should delete old OS channel when it is not in channel list") { - /* Given */ + // Given val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) createChannel("local_existing_id", ApplicationProvider.getApplicationContext()) createChannel("OS_existing_id", ApplicationProvider.getApplicationContext()) - val payload = JSONArray() - .put( - JSONObject() - .put("chnl", JSONObject().put("id", "OS_id1")), - ) + val payload = + JSONArray() + .put( + JSONObject() + .put("chnl", JSONObject().put("id", "OS_id1")), + ) - /* When */ + // When notificationChannelManager.processChannelList(payload) - /* Then */ + // Then getChannel("local_existing_id", ApplicationProvider.getApplicationContext()) shouldNotBe null getChannel("OS_existing_id", ApplicationProvider.getApplicationContext()) shouldBe null getChannel("OS_id1", ApplicationProvider.getApplicationContext()) shouldNotBe null } test("processChannelList multilanguage") { - /* Given */ + // Given val notificationChannelManager = NotificationChannelManager(AndroidMockHelper.applicationService(), MockHelper.languageContext()) - val payload = JSONArray() - .put( - JSONObject() - .put( - "chnl", - JSONObject() - .put("id", "OS_id1") - .put("grp_id", "grp_id1") - .put( - "langs", - JSONObject() - .put( - "en", - JSONObject() - .put("nm", "en_nm") - .put("dscr", "en_dscr") - .put("grp_nm", "en_grp_nm"), - ), - ), - ), - ) - - /* When */ + val payload = + JSONArray() + .put( + JSONObject() + .put( + "chnl", + JSONObject() + .put("id", "OS_id1") + .put("grp_id", "grp_id1") + .put( + "langs", + JSONObject() + .put( + "en", + JSONObject() + .put("nm", "en_nm") + .put("dscr", "en_dscr") + .put("grp_nm", "en_grp_nm"), + ), + ), + ), + ) + + // When notificationChannelManager.processChannelList(payload) - /* Then */ + // Then val lastGroup = ShadowRoboNotificationManager.lastChannelGroup val channel = getChannel("OS_id1", ApplicationProvider.getApplicationContext()) channel shouldNotBe null @@ -280,13 +287,19 @@ class NotificationChannelManagerTests : FunSpec({ } }) -fun createChannel(id: String, context: Context) { +fun createChannel( + id: String, + context: Context, +) { val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val channel = NotificationChannel(id, "name", NotificationManager.IMPORTANCE_DEFAULT) notificationManager.createNotificationChannel(channel) } -private fun getChannel(id: String, context: Context): NotificationChannel? { +private fun getChannel( + id: String, + context: Context, +): NotificationChannel? { val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager return notificationManager.getNotificationChannel(id) } diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt index f1e8869fe5..33d66ddb03 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt @@ -40,7 +40,7 @@ class NotificationGenerationProcessorTests : FunSpec({ } test("processNotificationData should set title correctly") { - /* Given */ + // Given val context = ApplicationProvider.getApplicationContext() val mockTime = MockHelper.time(1111) val mockApplicationService = AndroidMockHelper.applicationService() @@ -49,7 +49,20 @@ class NotificationGenerationProcessorTests : FunSpec({ coEvery { mockNotificationDisplayer.displayNotification(any()) } returns true val mockNotificationRepository = mockk() coEvery { mockNotificationRepository.doesNotificationExist(any()) } returns false - coEvery { mockNotificationRepository.createNotification(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()) } just runs + coEvery { + mockNotificationRepository.createNotification( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any(), + ) + } just runs val mockNotificationSummaryManager = mockk() val mockNotificationLifecycleService = mockk() coEvery { mockNotificationLifecycleService.canReceiveNotification(any()) } returns true @@ -57,29 +70,31 @@ class NotificationGenerationProcessorTests : FunSpec({ coEvery { mockNotificationLifecycleService.externalRemoteNotificationReceived(any()) } just runs coEvery { mockNotificationLifecycleService.externalNotificationWillShowInForeground(any()) } just runs - val notificationGenerationProcessor = NotificationGenerationProcessor( - mockApplicationService, - mockNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRepository, - mockNotificationSummaryManager, - mockNotificationLifecycleService, - mockTime, - ) - - val payload = JSONObject() - .put("alert", "test message") - .put("title", "test title") - .put( - "custom", - JSONObject() - .put("i", "UUID1"), + val notificationGenerationProcessor = + NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime, ) - /* When */ + val payload = + JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1"), + ) + + // When notificationGenerationProcessor.processNotificationData(context, 1, payload, false, 1111) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationDisplayer.displayNotification( withArg { @@ -98,7 +113,7 @@ class NotificationGenerationProcessorTests : FunSpec({ } test("processNotificationData should restore notification correctly") { - /* Given */ + // Given val context = ApplicationProvider.getApplicationContext() val mockTime = MockHelper.time(1111) val mockApplicationService = AndroidMockHelper.applicationService() @@ -114,29 +129,31 @@ class NotificationGenerationProcessorTests : FunSpec({ coEvery { mockNotificationLifecycleService.externalRemoteNotificationReceived(any()) } just runs coEvery { mockNotificationLifecycleService.externalNotificationWillShowInForeground(any()) } just runs - val notificationGenerationProcessor = NotificationGenerationProcessor( - mockApplicationService, - mockNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRepository, - mockNotificationSummaryManager, - mockNotificationLifecycleService, - mockTime, - ) - - val payload = JSONObject() - .put("alert", "test message") - .put("title", "test title") - .put( - "custom", - JSONObject() - .put("i", "UUID1"), + val notificationGenerationProcessor = + NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime, ) - /* When */ + val payload = + JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1"), + ) + + // When notificationGenerationProcessor.processNotificationData(context, 1, payload, true, 1111) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationDisplayer.displayNotification( withArg { @@ -152,7 +169,7 @@ class NotificationGenerationProcessorTests : FunSpec({ } test("processNotificationData should not display notification when external callback indicates not to") { - /* Given */ + // Given val context = ApplicationProvider.getApplicationContext() val mockTime = MockHelper.time(1111) val mockApplicationService = AndroidMockHelper.applicationService() @@ -170,33 +187,35 @@ class NotificationGenerationProcessorTests : FunSpec({ receivedEvent.preventDefault() } - val notificationGenerationProcessor = NotificationGenerationProcessor( - mockApplicationService, - mockNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRepository, - mockNotificationSummaryManager, - mockNotificationLifecycleService, - mockTime, - ) - - val payload = JSONObject() - .put("alert", "test message") - .put("title", "test title") - .put( - "custom", - JSONObject() - .put("i", "UUID1"), + val notificationGenerationProcessor = + NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime, ) - /* When */ + val payload = + JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1"), + ) + + // When notificationGenerationProcessor.processNotificationData(context, 1, payload, false, 1111) - /* Then */ + // Then } test("processNotificationData should display notification when external callback takes longer than 30 seconds") { - /* Given */ + // Given val context = ApplicationProvider.getApplicationContext() val mockTime = MockHelper.time(1111) val mockApplicationService = AndroidMockHelper.applicationService() @@ -214,29 +233,31 @@ class NotificationGenerationProcessorTests : FunSpec({ delay(40000) } - val notificationGenerationProcessor = NotificationGenerationProcessor( - mockApplicationService, - mockNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRepository, - mockNotificationSummaryManager, - mockNotificationLifecycleService, - mockTime, - ) - - val payload = JSONObject() - .put("alert", "test message") - .put("title", "test title") - .put( - "custom", - JSONObject() - .put("i", "UUID1"), + val notificationGenerationProcessor = + NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime, ) - /* When */ + val payload = + JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1"), + ) + + // When notificationGenerationProcessor.processNotificationData(context, 1, payload, true, 1111) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationDisplayer.displayNotification( withArg { @@ -252,7 +273,7 @@ class NotificationGenerationProcessorTests : FunSpec({ } test("processNotificationData should not display notification when foreground callback indicates not to") { - /* Given */ + // Given val context = ApplicationProvider.getApplicationContext() val mockTime = MockHelper.time(1111) val mockApplicationService = AndroidMockHelper.applicationService() @@ -271,33 +292,35 @@ class NotificationGenerationProcessorTests : FunSpec({ receivedEvent.preventDefault() } - val notificationGenerationProcessor = NotificationGenerationProcessor( - mockApplicationService, - mockNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRepository, - mockNotificationSummaryManager, - mockNotificationLifecycleService, - mockTime, - ) - - val payload = JSONObject() - .put("alert", "test message") - .put("title", "test title") - .put( - "custom", - JSONObject() - .put("i", "UUID1"), + val notificationGenerationProcessor = + NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime, ) - /* When */ + val payload = + JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1"), + ) + + // When notificationGenerationProcessor.processNotificationData(context, 1, payload, false, 1111) - /* Then */ + // Then } test("processNotificationData should display notification when foreground callback takes longer than 30 seconds") { - /* Given */ + // Given val context = ApplicationProvider.getApplicationContext() val mockTime = MockHelper.time(1111) val mockApplicationService = AndroidMockHelper.applicationService() @@ -315,29 +338,31 @@ class NotificationGenerationProcessorTests : FunSpec({ delay(40000) } - val notificationGenerationProcessor = NotificationGenerationProcessor( - mockApplicationService, - mockNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRepository, - mockNotificationSummaryManager, - mockNotificationLifecycleService, - mockTime, - ) - - val payload = JSONObject() - .put("alert", "test message") - .put("title", "test title") - .put( - "custom", - JSONObject() - .put("i", "UUID1"), + val notificationGenerationProcessor = + NotificationGenerationProcessor( + mockApplicationService, + mockNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRepository, + mockNotificationSummaryManager, + mockNotificationLifecycleService, + mockTime, ) - /* When */ + val payload = + JSONObject() + .put("alert", "test message") + .put("title", "test title") + .put( + "custom", + JSONObject() + .put("i", "UUID1"), + ) + + // When notificationGenerationProcessor.processNotificationData(context, 1, payload, true, 1111) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationDisplayer.displayNotification( withArg { diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/limiting/NotificationLimitManagerTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/limiting/NotificationLimitManagerTests.kt index 655b2701ed..79ba17c980 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/limiting/NotificationLimitManagerTests.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/limiting/NotificationLimitManagerTests.kt @@ -34,7 +34,7 @@ class NotificationLimitManagerTests : FunSpec({ } test("clearOldestOverLimit should make room for one when at limit") { - /* Given */ + // Given createNotification(ApplicationProvider.getApplicationContext(), 1) createNotification(ApplicationProvider.getApplicationContext(), 2) @@ -42,33 +42,35 @@ class NotificationLimitManagerTests : FunSpec({ coEvery { mockNotificationRepository.markAsDismissed(any()) } returns true val mockNotificationSummaryManager = spyk() - val notificationLimitManager = NotificationLimitManager(mockNotificationRepository, AndroidMockHelper.applicationService(), mockNotificationSummaryManager) + val notificationLimitManager = + NotificationLimitManager(mockNotificationRepository, AndroidMockHelper.applicationService(), mockNotificationSummaryManager) - /* When */ + // When notificationLimitManager.clearOldestOverLimit(1) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationRepository.markAsDismissed(1) } } test("clearOldestOverLimit should not dismiss any when under limit") { - /* Given */ + // Given createNotification(ApplicationProvider.getApplicationContext(), 1) val mockNotificationRepository = mockk() val mockNotificationSummaryManager = spyk() - val notificationLimitManager = NotificationLimitManager(mockNotificationRepository, AndroidMockHelper.applicationService(), mockNotificationSummaryManager) + val notificationLimitManager = + NotificationLimitManager(mockNotificationRepository, AndroidMockHelper.applicationService(), mockNotificationSummaryManager) - /* When */ + // When notificationLimitManager.clearOldestOverLimit(1) - /* Then */ + // Then coVerify(exactly = 0) { mockNotificationRepository.markAsDismissed(1) } } test("clearOldestOverLimit should skip dismissing summary notifications") { - /* Given */ + // Given createNotification(ApplicationProvider.getApplicationContext(), 1, true) createNotification(ApplicationProvider.getApplicationContext(), 2) @@ -76,17 +78,22 @@ class NotificationLimitManagerTests : FunSpec({ coEvery { mockNotificationRepository.markAsDismissed(any()) } returns true val mockNotificationSummaryManager = spyk() - val notificationLimitManager = NotificationLimitManager(mockNotificationRepository, AndroidMockHelper.applicationService(), mockNotificationSummaryManager) + val notificationLimitManager = + NotificationLimitManager(mockNotificationRepository, AndroidMockHelper.applicationService(), mockNotificationSummaryManager) - /* When */ + // When notificationLimitManager.clearOldestOverLimit(1) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationRepository.markAsDismissed(2) } } }) -fun createNotification(context: Context, notifId: Int, isSummary: Boolean = false) { +fun createNotification( + context: Context, + notifId: Int, + isSummary: Boolean = false, +) { val notifBuilder = NotificationCompat.Builder(context, "") notifBuilder.setWhen(notifId.toLong()) // Android automatically sets this normally. if (isSummary) { diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/pushtoken/PushTokenManagerTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/pushtoken/PushTokenManagerTests.kt index 3ca7383b15..c5f666f51a 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/pushtoken/PushTokenManagerTests.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/pushtoken/PushTokenManagerTests.kt @@ -24,19 +24,19 @@ class PushTokenManagerTests : FunSpec({ } test("retrievePushToken should fail with missing library when android support libraries are missing") { - /* Given */ + // Given val mockPushRegistrator = mockk() val mockDeviceService = MockHelper.deviceService() every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.MISSING val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) - /* When */ + // When val response = pushTokenManager.retrievePushToken() val pushToken = pushTokenManager.pushToken val pushTokenStatus = pushTokenManager.pushTokenStatus - /* Then */ + // Then response.token shouldBe null response.status shouldBe SubscriptionStatus.MISSING_ANDROID_SUPPORT_LIBRARY pushToken shouldBe null @@ -44,19 +44,19 @@ class PushTokenManagerTests : FunSpec({ } test("retrievePushToken should fail with outdated library when android support libraries are missing") { - /* Given */ + // Given val mockPushRegistrator = mockk() val mockDeviceService = MockHelper.deviceService() every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.OUTDATED val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) - /* When */ + // When val response = pushTokenManager.retrievePushToken() val pushToken = pushTokenManager.pushToken val pushTokenStatus = pushTokenManager.pushTokenStatus - /* Then */ + // Then response.token shouldBe null response.status shouldBe SubscriptionStatus.OUTDATED_ANDROID_SUPPORT_LIBRARY pushToken shouldBe null @@ -64,7 +64,7 @@ class PushTokenManagerTests : FunSpec({ } test("retrievePushToken should succeed when registration is successful") { - /* Given */ + // Given val mockPushRegistrator = mockk() coEvery { mockPushRegistrator.registerForPush() } returns IPushRegistrator.RegisterResult("pushToken", SubscriptionStatus.SUBSCRIBED) val mockDeviceService = MockHelper.deviceService() @@ -72,12 +72,12 @@ class PushTokenManagerTests : FunSpec({ val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) - /* When */ + // When val response = pushTokenManager.retrievePushToken() val pushToken = pushTokenManager.pushToken val pushTokenStatus = pushTokenManager.pushTokenStatus - /* Then */ + // Then coVerify(exactly = 1) { mockPushRegistrator.registerForPush() } response.token shouldBe "pushToken" response.status shouldBe SubscriptionStatus.SUBSCRIBED @@ -86,20 +86,22 @@ class PushTokenManagerTests : FunSpec({ } test("retrievePushToken should fail with failure status from push registrator with config-type error") { - /* Given */ + // Given val mockPushRegistrator = mockk() - coEvery { mockPushRegistrator.registerForPush() } returns IPushRegistrator.RegisterResult(null, SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY) + coEvery { + mockPushRegistrator.registerForPush() + } returns IPushRegistrator.RegisterResult(null, SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY) val mockDeviceService = MockHelper.deviceService() every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.OK val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) - /* When */ + // When val response = pushTokenManager.retrievePushToken() val pushToken = pushTokenManager.pushToken val pushTokenStatus = pushTokenManager.pushTokenStatus - /* Then */ + // Then coVerify(exactly = 1) { mockPushRegistrator.registerForPush() } response.token shouldBe null response.status shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY @@ -108,20 +110,22 @@ class PushTokenManagerTests : FunSpec({ } test("retrievePushToken should fail with failure status from push registrator with runtime-type error") { - /* Given */ + // Given val mockPushRegistrator = mockk() - coEvery { mockPushRegistrator.registerForPush() } returns IPushRegistrator.RegisterResult(null, SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION) + coEvery { + mockPushRegistrator.registerForPush() + } returns IPushRegistrator.RegisterResult(null, SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION) val mockDeviceService = MockHelper.deviceService() every { mockDeviceService.androidSupportLibraryStatus } returns IDeviceService.AndroidSupportLibraryStatus.OK val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) - /* When */ + // When val response = pushTokenManager.retrievePushToken() val pushToken = pushTokenManager.pushToken val pushTokenStatus = pushTokenManager.pushTokenStatus - /* Then */ + // Then coVerify(exactly = 1) { mockPushRegistrator.registerForPush() } response.token shouldBe null response.status shouldBe SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION @@ -130,7 +134,7 @@ class PushTokenManagerTests : FunSpec({ } test("retrievePushToken should fail with failure status of config-type error even if subsequent runtime-type error") { - /* Given */ + // Given val mockPushRegistrator = mockk() coEvery { mockPushRegistrator.registerForPush() } returns IPushRegistrator.RegisterResult(null, SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY) andThen @@ -141,7 +145,7 @@ class PushTokenManagerTests : FunSpec({ val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) - /* When */ + // When val response1 = pushTokenManager.retrievePushToken() val pushToken1 = pushTokenManager.pushToken val pushTokenStatus1 = pushTokenManager.pushTokenStatus @@ -149,7 +153,7 @@ class PushTokenManagerTests : FunSpec({ val pushToken2 = pushTokenManager.pushToken val pushTokenStatus2 = pushTokenManager.pushTokenStatus - /* Then */ + // Then coVerify(exactly = 2) { mockPushRegistrator.registerForPush() } response1.token shouldBe null response1.status shouldBe SubscriptionStatus.MISSING_FIREBASE_FCM_LIBRARY @@ -162,7 +166,7 @@ class PushTokenManagerTests : FunSpec({ } test("retrievePushToken should fail with failure status of config-type error even if previous runtime-type error") { - /* Given */ + // Given val mockPushRegistrator = mockk() coEvery { mockPushRegistrator.registerForPush() } returns IPushRegistrator.RegisterResult(null, SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION) andThen @@ -173,7 +177,7 @@ class PushTokenManagerTests : FunSpec({ val pushTokenManager = PushTokenManager(mockPushRegistrator, mockDeviceService) - /* When */ + // When val response1 = pushTokenManager.retrievePushToken() val pushToken1 = pushTokenManager.pushToken val pushTokenStatus1 = pushTokenManager.pushTokenStatus @@ -181,7 +185,7 @@ class PushTokenManagerTests : FunSpec({ val pushToken2 = pushTokenManager.pushToken val pushTokenStatus2 = pushTokenManager.pushTokenStatus - /* Then */ + // Then coVerify(exactly = 2) { mockPushRegistrator.registerForPush() } response1.token shouldBe null response1.status shouldBe SubscriptionStatus.FIREBASE_FCM_ERROR_MISC_EXCEPTION diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/summary/NotificationSummaryManagerTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/summary/NotificationSummaryManagerTests.kt index 3bfa49fa89..cb727dc58d 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/summary/NotificationSummaryManagerTests.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/summary/NotificationSummaryManagerTests.kt @@ -35,30 +35,31 @@ class NotificationSummaryManagerTests : FunSpec({ } test("updatePossibleDependentSummaryOnDismiss should take no action when dismissed notification is not part of a group") { - /* Given */ + // Given val mockNotificationRepository = mockk() coEvery { mockNotificationRepository.getGroupId(1) } returns null val mockSummaryNotificationDisplayer = mockk() val mockNotificationRestoreProcessor = mockk() - val notificationSummaryManager = NotificationSummaryManager( - AndroidMockHelper.applicationService(), - mockNotificationRepository, - mockSummaryNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRestoreProcessor, - MockHelper.time(111), - ) + val notificationSummaryManager = + NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor, + MockHelper.time(111), + ) - /* When */ + // When notificationSummaryManager.updatePossibleDependentSummaryOnDismiss(1) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationRepository.getGroupId(1) } } test("updatePossibleDependentSummaryOnDismiss should dismiss summary notification when there are no more notifications in group") { - /* Given */ + // Given val mockNotificationRepository = mockk() coEvery { mockNotificationRepository.getGroupId(1) } returns "groupId" coEvery { mockNotificationRepository.listNotificationsForGroup("groupId") } returns listOf() @@ -67,19 +68,20 @@ class NotificationSummaryManagerTests : FunSpec({ val mockSummaryNotificationDisplayer = mockk() val mockNotificationRestoreProcessor = mockk() - val notificationSummaryManager = NotificationSummaryManager( - AndroidMockHelper.applicationService(), - mockNotificationRepository, - mockSummaryNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRestoreProcessor, - MockHelper.time(111), - ) + val notificationSummaryManager = + NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor, + MockHelper.time(111), + ) - /* When */ + // When notificationSummaryManager.updatePossibleDependentSummaryOnDismiss(1) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationRepository.getGroupId(1) } coVerify(exactly = 1) { mockNotificationRepository.listNotificationsForGroup("groupId") } coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } @@ -89,31 +91,33 @@ class NotificationSummaryManagerTests : FunSpec({ } test("updatePossibleDependentSummaryOnDismiss should update summary notification when there are 2 or more notifications in group") { - /* Given */ + // Given val mockNotificationRepository = mockk() coEvery { mockNotificationRepository.getGroupId(1) } returns "groupId" - coEvery { mockNotificationRepository.listNotificationsForGroup("groupId") } returns listOf( - INotificationRepository.NotificationData(2, "notificationId2", "{key: \"value2\"}", 1111, "title2", "message2"), - INotificationRepository.NotificationData(3, "notificationId3", "{key: \"value3\"}", 1111, "title3", "message3"), - ) + coEvery { mockNotificationRepository.listNotificationsForGroup("groupId") } returns + listOf( + INotificationRepository.NotificationData(2, "notificationId2", "{key: \"value2\"}", 1111, "title2", "message2"), + INotificationRepository.NotificationData(3, "notificationId3", "{key: \"value3\"}", 1111, "title3", "message3"), + ) coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } returns 99 val mockSummaryNotificationDisplayer = mockk() coEvery { mockSummaryNotificationDisplayer.updateSummaryNotification(any()) } just runs val mockNotificationRestoreProcessor = mockk() - val notificationSummaryManager = NotificationSummaryManager( - AndroidMockHelper.applicationService(), - mockNotificationRepository, - mockSummaryNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRestoreProcessor, - MockHelper.time(111), - ) + val notificationSummaryManager = + NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor, + MockHelper.time(111), + ) - /* When */ + // When notificationSummaryManager.updatePossibleDependentSummaryOnDismiss(1) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationRepository.getGroupId(1) } coVerify(exactly = 1) { mockNotificationRepository.listNotificationsForGroup("groupId") } coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } @@ -121,30 +125,32 @@ class NotificationSummaryManagerTests : FunSpec({ } test("updatePossibleDependentSummaryOnDismiss should restore summary notification when there is 1 notification in group") { - /* Given */ + // Given val mockNotificationRepository = mockk() coEvery { mockNotificationRepository.getGroupId(1) } returns "groupId" - coEvery { mockNotificationRepository.listNotificationsForGroup("groupId") } returns listOf( - INotificationRepository.NotificationData(2, "notificationId2", "{key: \"value2\"}", 1111, "title2", "message2"), - ) + coEvery { mockNotificationRepository.listNotificationsForGroup("groupId") } returns + listOf( + INotificationRepository.NotificationData(2, "notificationId2", "{key: \"value2\"}", 1111, "title2", "message2"), + ) coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } returns 99 val mockSummaryNotificationDisplayer = mockk() val mockNotificationRestoreProcessor = mockk() coEvery { mockNotificationRestoreProcessor.processNotification(any()) } just runs - val notificationSummaryManager = NotificationSummaryManager( - AndroidMockHelper.applicationService(), - mockNotificationRepository, - mockSummaryNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRestoreProcessor, - MockHelper.time(111), - ) + val notificationSummaryManager = + NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor, + MockHelper.time(111), + ) - /* When */ + // When notificationSummaryManager.updatePossibleDependentSummaryOnDismiss(1) - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationRepository.getGroupId(1) } coVerify(exactly = 2) { mockNotificationRepository.listNotificationsForGroup("groupId") } coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } @@ -162,52 +168,55 @@ class NotificationSummaryManagerTests : FunSpec({ } test("clearNotificationOnSummaryClick should do nothing when there is no notifications in group") { - /* Given */ + // Given val mockNotificationRepository = mockk() coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", false) } returns null val mockSummaryNotificationDisplayer = mockk() val mockNotificationRestoreProcessor = mockk() - val notificationSummaryManager = NotificationSummaryManager( - AndroidMockHelper.applicationService(), - mockNotificationRepository, - mockSummaryNotificationDisplayer, - MockHelper.configModelStore(), - mockNotificationRestoreProcessor, - MockHelper.time(111), - ) + val notificationSummaryManager = + NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + MockHelper.configModelStore(), + mockNotificationRestoreProcessor, + MockHelper.time(111), + ) - /* When */ + // When notificationSummaryManager.clearNotificationOnSummaryClick("groupId") - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", false) } } test("clearNotificationOnSummaryClick should do something when there is 1 or more notifications in group") { - /* Given */ - val mockConfig = MockHelper.configModelStore { - it.clearGroupOnSummaryClick = true - } + // Given + val mockConfig = + MockHelper.configModelStore { + it.clearGroupOnSummaryClick = true + } val mockNotificationRepository = mockk() coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", false) } returns 1 coEvery { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } returns 99 val mockSummaryNotificationDisplayer = mockk() val mockNotificationRestoreProcessor = mockk() - val notificationSummaryManager = NotificationSummaryManager( - AndroidMockHelper.applicationService(), - mockNotificationRepository, - mockSummaryNotificationDisplayer, - mockConfig, - mockNotificationRestoreProcessor, - MockHelper.time(111), - ) + val notificationSummaryManager = + NotificationSummaryManager( + AndroidMockHelper.applicationService(), + mockNotificationRepository, + mockSummaryNotificationDisplayer, + mockConfig, + mockNotificationRestoreProcessor, + MockHelper.time(111), + ) - /* When */ + // When notificationSummaryManager.clearNotificationOnSummaryClick("groupId") - /* Then */ + // Then coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", false) } coVerify(exactly = 1) { mockNotificationRepository.getAndroidIdForGroup("groupId", true) } diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/AndroidMockHelper.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/AndroidMockHelper.kt index eff5fcc5b9..b2db452b6c 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/AndroidMockHelper.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/AndroidMockHelper.kt @@ -8,7 +8,6 @@ import io.mockk.every * Singleton which provides common mock services when running in an Android environment. */ internal object AndroidMockHelper { - fun applicationService(): IApplicationService { val mockAppService = MockHelper.applicationService() diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/DatabaseMockHelper.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/DatabaseMockHelper.kt index 90fcf42ae7..4a71a6474b 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/DatabaseMockHelper.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/DatabaseMockHelper.kt @@ -11,7 +11,10 @@ import io.mockk.spyk * Singleton which provides common mock services. */ internal object DatabaseMockHelper { - fun databaseProvider(tableName: String, records: List>? = null): Pair { + fun databaseProvider( + tableName: String, + records: List>? = null, + ): Pair { val mockOneSignalDatabase = spyk() if (records != null) { @@ -33,8 +36,14 @@ internal object DatabaseMockHelper { val mockCursor = mockk() var index = 0 every { mockCursor.count } returns records.count() - every { mockCursor.moveToFirst() } answers { index = 0; true } - every { mockCursor.moveToNext() } answers { index++; index < records.count() } + every { mockCursor.moveToFirst() } answers { + index = 0 + true + } + every { mockCursor.moveToNext() } answers { + index++ + index < records.count() + } every { mockCursor.getString(any()) } answers { records[index][firstArg()] as String } every { mockCursor.getFloat(any()) } answers { records[index][firstArg()] as Float } every { mockCursor.getLong(any()) } answers { records[index][firstArg()] as Long } diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/MockHelper.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/MockHelper.kt index bc4b32f861..1974ff9a3c 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/MockHelper.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/mocks/MockHelper.kt @@ -38,6 +38,7 @@ object MockHelper { } const val DEFAULT_APP_ID = "appId" + fun configModelStore(action: ((ConfigModel) -> Unit)? = null): ConfigModelStore { val configModel = ConfigModel() diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/shadows/ShadowRoboNotificationManager.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/shadows/ShadowRoboNotificationManager.kt index 45990698ab..bb6cec0b78 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/shadows/ShadowRoboNotificationManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/shadows/ShadowRoboNotificationManager.kt @@ -56,18 +56,26 @@ class ShadowRoboNotificationManager : ShadowNotificationManager() { cancelledNotifications.add(id) } - public override fun cancel(tag: String, id: Int) { + public override fun cancel( + tag: String, + id: Int, + ) { notifications.remove(id) cancelledNotifications.add(id) } - public override fun notify(tag: String, id: Int, notification: Notification) { + public override fun notify( + tag: String, + id: Int, + notification: Notification, + ) { lastNotif = notification lastNotifId = id - notifications[id] = PostedNotification( - id, - notification, - ) + notifications[id] = + PostedNotification( + id, + notification, + ) super.notify(tag, id, notification) } @@ -98,6 +106,7 @@ class ShadowRoboNotificationManager : ShadowNotificationManager() { } private lateinit var mInstance: ShadowRoboNotificationManager + fun getNotificationsInGroup(group: String): List { val notifications: MutableList = ArrayList() for (notification in mInstance.allNotifications) {