Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,12 @@ private void setupSubscriptionSwitch() {
// Add a listener to toggle the push notification enablement for the push subscription.
pushSubscriptionEnabledSwitch.setOnClickListener(v -> {
IPushSubscription subscription = OneSignal.getUser().getSubscriptions().getPush();
subscription.setEnabled(pushSubscriptionEnabledSwitch.isChecked());
if(pushSubscriptionEnabledSwitch.isChecked()) {
subscription.optIn();
}
else {
subscription.optOut();
}
});
}

Expand Down Expand Up @@ -832,7 +837,7 @@ private void refreshSubscriptionState() {
promptPushBottonLayout.setVisibility(isPermissionEnabled ? View.GONE : View.VISIBLE);
pushSubscriptionEnabledRelativeLayout.setEnabled(isPermissionEnabled);
pushSubscriptionEnabledSwitch.setEnabled(isPermissionEnabled);
pushSubscriptionEnabledSwitch.setChecked(pushSubscription.getEnabled());
pushSubscriptionEnabledSwitch.setChecked(pushSubscription.getOptedIn());
}

private void setupSendNotificationsLayout() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static void sendDeviceNotification(final Notification notification) {
new Thread(() -> {
IPushSubscription subscription = OneSignal.getUser().getSubscriptions().getPush();

if (!subscription.getEnabled())
if (!subscription.getOptedIn())
return;

int pos = notification.getTemplatePos();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ import com.onesignal.session.internal.session.ISessionService
import com.onesignal.user.IUserManager
import com.onesignal.user.internal.subscriptions.ISubscriptionChangedHandler
import com.onesignal.user.internal.subscriptions.ISubscriptionManager
import com.onesignal.user.internal.subscriptions.SubscriptionModel
import com.onesignal.user.subscriptions.IPushSubscription
import com.onesignal.user.subscriptions.ISubscription
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

Expand Down Expand Up @@ -164,7 +167,13 @@ internal class InAppMessagesManager(
}
}

override fun onSubscriptionsChanged() {
override fun onSubscriptionAdded(subscription: ISubscription) { }
override fun onSubscriptionRemoved(subscription: ISubscription) { }
override fun onSubscriptionChanged(subscription: ISubscription, args: ModelChangedArgs) {
if (subscription !is IPushSubscription || args.path != SubscriptionModel::id.name) {
return
}

suspendifyOnThread {
fetchMessages()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ internal class InAppBackendService(

override suspend fun listInAppMessages(appId: String, subscriptionId: String): List<InAppMessage>? {
// Retrieve any in app messages that might exist
val jsonBody = JSONObject()
jsonBody.put("app_id", appId)

// TODO: This will be replaced by dedicated iam endpoint once it's available
var response = _httpClient.post("players/$subscriptionId/on_session", jsonBody)
val response = _httpClient.get("apps/$appId/subscriptions/$subscriptionId/iams")

if (response.isSuccess) {
val jsonResponse = JSONObject(response.payload)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ class TriggerModel : Model() {
* The key of this trigger
*/
var key: String
get() = getProperty(::key.name) { "" }
set(value) { setProperty(::key.name, value) }
get() = getStringProperty(::key.name) { "" }
set(value) { setStringProperty(::key.name, value) }

/**
* The value of this trigger
*/
var value: Any
get() = getProperty(::value.name) { "" }
set(value) { setProperty(::value.name, value) }
get() = getAnyProperty(::value.name) { "" }
set(value) { setAnyProperty(::value.name, value) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class InAppBackendServiceTests : FunSpec({
/* Given */
val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore())
val mockHttpClient = mockk<IHttpClient>()
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: \"2020-12-13T23:23:23\", 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)

Expand All @@ -62,9 +62,9 @@ class InAppBackendServiceTests : FunSpec({
response shouldNotBe null
response!!.count() shouldBe 1
response[0].messageId shouldBe "messageId1"
response[0].variants.keys shouldBe 1
response[0].variants.keys.count() shouldBe 1
response[0].variants["all"] shouldNotBe null
response[0].variants["all"]!!.keys shouldBe 1
response[0].variants["all"]!!.keys.count() shouldBe 1
response[0].variants["all"]!!["en"] shouldBe "content1"
response[0].triggers.count() shouldBe 1
response[0].triggers[0].count() shouldBe 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import com.onesignal.common.events.EventProducer
import com.onesignal.common.threading.suspendifyOnThread
import com.onesignal.core.internal.application.IApplicationLifecycleHandler
import com.onesignal.core.internal.application.IApplicationService
import com.onesignal.core.internal.config.ConfigModelStore
import com.onesignal.debug.internal.logging.Logging
import com.onesignal.notifications.INotificationClickHandler
import com.onesignal.notifications.INotificationWillShowInForegroundHandler
import com.onesignal.notifications.INotificationsManager
import com.onesignal.notifications.IPermissionChangedHandler
import com.onesignal.notifications.internal.backend.INotificationBackendService
import com.onesignal.notifications.internal.common.GenerateNotificationOpenIntentFromPushPayload
import com.onesignal.notifications.internal.common.NotificationHelper
import com.onesignal.notifications.internal.data.INotificationRepository
Expand All @@ -33,8 +31,6 @@ interface INotificationActivityOpener {
*/
internal class NotificationsManager(
private val _applicationService: IApplicationService,
private val _configModelStore: ConfigModelStore,
private val _backend: INotificationBackendService,
private val _notificationPermissionController: INotificationPermissionController,
private val _notificationRestoreWorkManager: INotificationRestoreWorkManager,
private val _notificationLifecycleService: INotificationLifecycleService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import com.onesignal.notifications.INotificationsManager
import com.onesignal.notifications.IPermissionChangedHandler
import com.onesignal.notifications.internal.channels.INotificationChannelManager
import com.onesignal.notifications.internal.pushtoken.IPushTokenManager
import com.onesignal.user.internal.subscriptions.ISubscriptionChangedHandler
import com.onesignal.user.internal.subscriptions.ISubscriptionManager
import com.onesignal.user.internal.subscriptions.SubscriptionModel
import com.onesignal.user.internal.subscriptions.SubscriptionStatus
import com.onesignal.user.subscriptions.ISubscription

/**
* The device registration listener will subscribe to events and at the appropriate time will
Expand All @@ -28,11 +31,15 @@ internal class DeviceRegistrationListener(
private val _subscriptionManager: ISubscriptionManager
) : IStartableService,
ISingletonModelStoreChangeHandler<ConfigModel>,
IPermissionChangedHandler {
IPermissionChangedHandler,
ISubscriptionChangedHandler {

override fun start() {
_configModelStore.subscribe(this)
_notificationsManager.addPermissionChangedHandler(this)
_subscriptionManager.subscribe(this)

retrievePushTokenAndUpdateSubscription()
}

override fun onModelReplaced(model: ConfigModel, tag: String) {
Expand All @@ -44,29 +51,43 @@ internal class DeviceRegistrationListener(

_channelManager.processChannelList(model.notificationChannels)

retrievePushTokenAndUpdateSubscription(_notificationsManager.permission)
retrievePushTokenAndUpdateSubscription()
}

override fun onModelUpdated(args: ModelChangedArgs, tag: String) {
}

override fun onPermissionChanged(permission: Boolean) {
retrievePushTokenAndUpdateSubscription(permission)
retrievePushTokenAndUpdateSubscription()
}

private fun retrievePushTokenAndUpdateSubscription(permission: Boolean) {
private fun retrievePushTokenAndUpdateSubscription() {
val pushSubscription = _subscriptionManager.subscriptions.push

if (pushSubscription.pushToken.isNotEmpty()) {
val permission = _notificationsManager.permission
_subscriptionManager.addOrUpdatePushSubscription(null, if (permission) SubscriptionStatus.SUBSCRIBED else SubscriptionStatus.NO_PERMISSION)
} else {
suspendifyOnThread {
val pushTokenAndStatus = _pushTokenManager.retrievePushToken()
val permission = _notificationsManager.permission
_subscriptionManager.addOrUpdatePushSubscription(
pushTokenAndStatus.token,
if (permission) pushTokenAndStatus.status else SubscriptionStatus.NO_PERMISSION
)
}
}
}

override fun onSubscriptionRemoved(subscription: ISubscription) { }
override fun onSubscriptionAdded(subscription: ISubscription) { }
override fun onSubscriptionChanged(subscription: ISubscription, args: ModelChangedArgs) {
// when going from optedIn=false to optedIn=true and there aren't permissions, automatically drive
// permission request.
if (args.path == SubscriptionModel::optedIn.name && args.oldValue == false && args.newValue == true && !_notificationsManager.permission) {
suspendifyOnThread {
_notificationsManager.requestPermission(true)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.onesignal.common

import org.json.JSONArray
import org.json.JSONObject

/**
Expand Down Expand Up @@ -33,9 +34,9 @@ fun JSONObject.safeLong(name: String): Long? {
}

/**
* Retrieve an [Double] from the [JSONObject] safely.
* Retrieve a [Double] from the [JSONObject] safely.
*
* @param name The name of the attribute that contains an [Int] value.
* @param name The name of the attribute that contains a [Double] value.
*
* @return The [Double] value if it exists, null otherwise.
*/
Expand Down Expand Up @@ -92,15 +93,135 @@ fun JSONObject.safeJSONObject(name: String): JSONObject? {
return null
}

/**
* Create a [Map] from the [JSONObject].
*/
fun JSONObject.toMap(): Map<String, Any> {
val map = mutableMapOf<String, Any>()

for (key in this.keys()) {
map[key] = this[key]
}

return map
}

/**
* Expand into a [JSONObject] safely.
*
* @param name The name of the attribute that contains a [JSONObject] value.
* @param into The lambda method that will be executed to explore the [JSONObject] value, if the
* attribute exists.
*/
fun JSONObject.expand(name: String, into: (childObject: JSONObject) -> Unit) {
fun JSONObject.expandJSONObject(name: String, into: (childObject: JSONObject) -> Unit) {
if (this.has(name)) {
into(this.getJSONObject(name))
}
}

fun <T> JSONObject.expandJSONArray(name: String, into: (childObject: JSONObject) -> T?): List<T> {
val listToRet = mutableListOf<T>()
if (this.has(name)) {
val jsonArray = this.getJSONArray(name)
for (index in 0 until jsonArray.length()) {
val itemJSONObject = jsonArray.getJSONObject(index)
val item = into(itemJSONObject)
if (item != null) {
listToRet.add(item)
}
}
}

return listToRet
}

/**
* Populate the [JSONObject] with the [Map] provided.
*
* @param map: The map that will contain the name/values.
*
* @return The [JSONObject] itself, to allow for chaining.
*/
fun JSONObject.putMap(map: Map<String, Any?>): JSONObject {
for (identity in map) {
this.put(identity.key, identity.value ?: JSONObject.NULL)
}

return this
}

/**
* Populate the [JSONObject] as attribute [name] with the [Map] provided.
*
* @param name: The name of the attribute that will contain the [JSONObject] value.
* @param map: The map that will contain the name/values.
*
* @return The [JSONObject] itself, to allow for chaining.
*/
fun JSONObject.putMap(name: String, map: Map<String, Any?>?): JSONObject {
if (map != null) {
this.putJSONObject(name) {
it.putMap(map)
}
}

return this
}

/**
* Put the attribute named by [name] with a [JSONObject] value, the contents
* of which are determined by the expand.
*
* @param name: The name of the attribute that will contain the [JSONObject] value.
* @param expand: The lambda that will be called to populate the [JSONObject] value.
*
* @return The [JSONObject] itself, to allow for chaining.
*/
fun JSONObject.putJSONObject(name: String, expand: (item: JSONObject) -> Unit): JSONObject {
val childJSONObject = JSONObject()
expand(childJSONObject)

this.put(name, childJSONObject)

return this
}

/**
* Put the attribute named by [name] with a [JSONArray] value, the contenxt of which
* are deteremined by the input.
*
* @param name: The name of the attribute that will contain the [JSONArray] value.
* @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 <T> JSONObject.putJSONArray(name: String, list: List<T>?, create: (item: T) -> JSONObject?): JSONObject {
if (list != null) {
val jsonArray = JSONArray()
list.forEach {
val item = create(it)
if (item != null) {
jsonArray.put(item)
}
}
this.put(name, jsonArray)
}

return this
}

/**
* Put the name/value pair into the [JSONObject]. If the [value] provided is null,
* nothing will be put into the [JSONObject].
*
* @param name The name of the attribute the [value] will be saved to.
* @param value The value to put into the [JSONObject]. If not null, the attribute name will not be added.
*
* @return The [JSONObject] itself, to allow for chaining.
*/
fun JSONObject.putSafe(name: String, value: Any?): JSONObject {
if (value != null) {
this.put(name, value)
}

return this
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,28 @@ open class MapModel<V>(
}

override fun get(key: String): V {
return getProperty(key)
return getOptAnyProperty(key) as V
}

override fun clear() {
for (property in data.keys)
setProperty(property, null)
setOptAnyProperty(property, null)
}

override fun put(key: String, value: V): V {
setProperty(key, value)
setOptAnyProperty(key, value)
return value
}

override fun putAll(from: Map<out String, V>) {
for (item in from) {
setProperty(item.key, item.value)
setOptAnyProperty(item.key, item.value)
}
}

override fun remove(key: String): V {
val value = getProperty<V>(key)
setProperty(key, null)
val value = getOptAnyProperty(key) as V
setOptAnyProperty(key, null)
return value
}
}
Loading