Skip to content

Commit 45516c6

Browse files
authored
Merge pull request #1705 from OneSignal/user-model/backend-integration
[User model] backend integration
2 parents fb8cac9 + 9911f8e commit 45516c6

File tree

71 files changed

+1290
-996
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1290
-996
lines changed

Examples/OneSignalDemo/app/src/main/java/com/onesignal/sdktest/model/MainActivityViewModel.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,12 @@ private void setupSubscriptionSwitch() {
801801
// Add a listener to toggle the push notification enablement for the push subscription.
802802
pushSubscriptionEnabledSwitch.setOnClickListener(v -> {
803803
IPushSubscription subscription = OneSignal.getUser().getSubscriptions().getPush();
804-
subscription.setEnabled(pushSubscriptionEnabledSwitch.isChecked());
804+
if(pushSubscriptionEnabledSwitch.isChecked()) {
805+
subscription.optIn();
806+
}
807+
else {
808+
subscription.optOut();
809+
}
805810
});
806811
}
807812

@@ -832,7 +837,7 @@ private void refreshSubscriptionState() {
832837
promptPushBottonLayout.setVisibility(isPermissionEnabled ? View.GONE : View.VISIBLE);
833838
pushSubscriptionEnabledRelativeLayout.setEnabled(isPermissionEnabled);
834839
pushSubscriptionEnabledSwitch.setEnabled(isPermissionEnabled);
835-
pushSubscriptionEnabledSwitch.setChecked(pushSubscription.getEnabled());
840+
pushSubscriptionEnabledSwitch.setChecked(pushSubscription.getOptedIn());
836841
}
837842

838843
private void setupSendNotificationsLayout() {

Examples/OneSignalDemo/app/src/main/java/com/onesignal/sdktest/notification/OneSignalNotificationSender.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public static void sendDeviceNotification(final Notification notification) {
3535
new Thread(() -> {
3636
IPushSubscription subscription = OneSignal.getUser().getSubscriptions().getPush();
3737

38-
if (!subscription.getEnabled())
38+
if (!subscription.getOptedIn())
3939
return;
4040

4141
int pos = notification.getTemplatePos();

OneSignalSDK/onesignal/inAppMessages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ import com.onesignal.session.internal.session.ISessionService
4242
import com.onesignal.user.IUserManager
4343
import com.onesignal.user.internal.subscriptions.ISubscriptionChangedHandler
4444
import com.onesignal.user.internal.subscriptions.ISubscriptionManager
45+
import com.onesignal.user.internal.subscriptions.SubscriptionModel
46+
import com.onesignal.user.subscriptions.IPushSubscription
47+
import com.onesignal.user.subscriptions.ISubscription
4548
import kotlinx.coroutines.sync.Mutex
4649
import kotlinx.coroutines.sync.withLock
4750

@@ -164,7 +167,13 @@ internal class InAppMessagesManager(
164167
}
165168
}
166169

167-
override fun onSubscriptionsChanged() {
170+
override fun onSubscriptionAdded(subscription: ISubscription) { }
171+
override fun onSubscriptionRemoved(subscription: ISubscription) { }
172+
override fun onSubscriptionChanged(subscription: ISubscription, args: ModelChangedArgs) {
173+
if (subscription !is IPushSubscription || args.path != SubscriptionModel::id.name) {
174+
return
175+
}
176+
168177
suspendifyOnThread {
169178
fetchMessages()
170179
}

OneSignalSDK/onesignal/inAppMessages/src/main/java/com/onesignal/inAppMessages/internal/backend/impl/InAppBackendService.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,7 @@ internal class InAppBackendService(
2121

2222
override suspend fun listInAppMessages(appId: String, subscriptionId: String): List<InAppMessage>? {
2323
// Retrieve any in app messages that might exist
24-
val jsonBody = JSONObject()
25-
jsonBody.put("app_id", appId)
26-
27-
// TODO: This will be replaced by dedicated iam endpoint once it's available
28-
var response = _httpClient.post("players/$subscriptionId/on_session", jsonBody)
24+
val response = _httpClient.get("apps/$appId/subscriptions/$subscriptionId/iams")
2925

3026
if (response.isSuccess) {
3127
val jsonResponse = JSONObject(response.payload)

OneSignalSDK/onesignal/inAppMessages/src/main/java/com/onesignal/inAppMessages/internal/triggers/TriggerModel.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ class TriggerModel : Model() {
77
* The key of this trigger
88
*/
99
var key: String
10-
get() = getProperty(::key.name) { "" }
11-
set(value) { setProperty(::key.name, value) }
10+
get() = getStringProperty(::key.name) { "" }
11+
set(value) { setStringProperty(::key.name, value) }
1212

1313
/**
1414
* The value of this trigger
1515
*/
1616
var value: Any
17-
get() = getProperty(::value.name) { "" }
18-
set(value) { setProperty(::value.name, value) }
17+
get() = getAnyProperty(::value.name) { "" }
18+
set(value) { setAnyProperty(::value.name, value) }
1919
}

OneSignalSDK/onesignal/inAppMessages/src/test/java/com/onesignal/inAppMessages/internal/backend/InAppBackendServiceTests.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class InAppBackendServiceTests : FunSpec({
5151
/* Given */
5252
val mockHydrator = InAppHydrator(MockHelper.time(1000), MockHelper.propertiesModelStore())
5353
val mockHttpClient = mockk<IHttpClient>()
54-
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}] }")
54+
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}}] }")
5555

5656
val inAppBackendService = InAppBackendService(mockHttpClient, MockHelper.deviceService(), mockHydrator)
5757

@@ -62,9 +62,9 @@ class InAppBackendServiceTests : FunSpec({
6262
response shouldNotBe null
6363
response!!.count() shouldBe 1
6464
response[0].messageId shouldBe "messageId1"
65-
response[0].variants.keys shouldBe 1
65+
response[0].variants.keys.count() shouldBe 1
6666
response[0].variants["all"] shouldNotBe null
67-
response[0].variants["all"]!!.keys shouldBe 1
67+
response[0].variants["all"]!!.keys.count() shouldBe 1
6868
response[0].variants["all"]!!["en"] shouldBe "content1"
6969
response[0].triggers.count() shouldBe 1
7070
response[0].triggers[0].count() shouldBe 1

OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationsManager.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@ import com.onesignal.common.events.EventProducer
55
import com.onesignal.common.threading.suspendifyOnThread
66
import com.onesignal.core.internal.application.IApplicationLifecycleHandler
77
import com.onesignal.core.internal.application.IApplicationService
8-
import com.onesignal.core.internal.config.ConfigModelStore
98
import com.onesignal.debug.internal.logging.Logging
109
import com.onesignal.notifications.INotificationClickHandler
1110
import com.onesignal.notifications.INotificationWillShowInForegroundHandler
1211
import com.onesignal.notifications.INotificationsManager
1312
import com.onesignal.notifications.IPermissionChangedHandler
14-
import com.onesignal.notifications.internal.backend.INotificationBackendService
1513
import com.onesignal.notifications.internal.common.GenerateNotificationOpenIntentFromPushPayload
1614
import com.onesignal.notifications.internal.common.NotificationHelper
1715
import com.onesignal.notifications.internal.data.INotificationRepository
@@ -33,8 +31,6 @@ interface INotificationActivityOpener {
3331
*/
3432
internal class NotificationsManager(
3533
private val _applicationService: IApplicationService,
36-
private val _configModelStore: ConfigModelStore,
37-
private val _backend: INotificationBackendService,
3834
private val _notificationPermissionController: INotificationPermissionController,
3935
private val _notificationRestoreWorkManager: INotificationRestoreWorkManager,
4036
private val _notificationLifecycleService: INotificationLifecycleService,

OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/listeners/DeviceRegistrationListener.kt

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ import com.onesignal.notifications.INotificationsManager
1111
import com.onesignal.notifications.IPermissionChangedHandler
1212
import com.onesignal.notifications.internal.channels.INotificationChannelManager
1313
import com.onesignal.notifications.internal.pushtoken.IPushTokenManager
14+
import com.onesignal.user.internal.subscriptions.ISubscriptionChangedHandler
1415
import com.onesignal.user.internal.subscriptions.ISubscriptionManager
16+
import com.onesignal.user.internal.subscriptions.SubscriptionModel
1517
import com.onesignal.user.internal.subscriptions.SubscriptionStatus
18+
import com.onesignal.user.subscriptions.ISubscription
1619

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

3337
override fun start() {
3438
_configModelStore.subscribe(this)
3539
_notificationsManager.addPermissionChangedHandler(this)
40+
_subscriptionManager.subscribe(this)
41+
42+
retrievePushTokenAndUpdateSubscription()
3643
}
3744

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

4552
_channelManager.processChannelList(model.notificationChannels)
4653

47-
retrievePushTokenAndUpdateSubscription(_notificationsManager.permission)
54+
retrievePushTokenAndUpdateSubscription()
4855
}
4956

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

5360
override fun onPermissionChanged(permission: Boolean) {
54-
retrievePushTokenAndUpdateSubscription(permission)
61+
retrievePushTokenAndUpdateSubscription()
5562
}
5663

57-
private fun retrievePushTokenAndUpdateSubscription(permission: Boolean) {
64+
private fun retrievePushTokenAndUpdateSubscription() {
5865
val pushSubscription = _subscriptionManager.subscriptions.push
5966

6067
if (pushSubscription.pushToken.isNotEmpty()) {
68+
val permission = _notificationsManager.permission
6169
_subscriptionManager.addOrUpdatePushSubscription(null, if (permission) SubscriptionStatus.SUBSCRIBED else SubscriptionStatus.NO_PERMISSION)
6270
} else {
6371
suspendifyOnThread {
6472
val pushTokenAndStatus = _pushTokenManager.retrievePushToken()
73+
val permission = _notificationsManager.permission
6574
_subscriptionManager.addOrUpdatePushSubscription(
6675
pushTokenAndStatus.token,
6776
if (permission) pushTokenAndStatus.status else SubscriptionStatus.NO_PERMISSION
6877
)
6978
}
7079
}
7180
}
81+
82+
override fun onSubscriptionRemoved(subscription: ISubscription) { }
83+
override fun onSubscriptionAdded(subscription: ISubscription) { }
84+
override fun onSubscriptionChanged(subscription: ISubscription, args: ModelChangedArgs) {
85+
// when going from optedIn=false to optedIn=true and there aren't permissions, automatically drive
86+
// permission request.
87+
if (args.path == SubscriptionModel::optedIn.name && args.oldValue == false && args.newValue == true && !_notificationsManager.permission) {
88+
suspendifyOnThread {
89+
_notificationsManager.requestPermission(true)
90+
}
91+
}
92+
}
7293
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/common/JSONObjectExtensions.kt

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.onesignal.common
22

3+
import org.json.JSONArray
34
import org.json.JSONObject
45

56
/**
@@ -33,9 +34,9 @@ fun JSONObject.safeLong(name: String): Long? {
3334
}
3435

3536
/**
36-
* Retrieve an [Double] from the [JSONObject] safely.
37+
* Retrieve a [Double] from the [JSONObject] safely.
3738
*
38-
* @param name The name of the attribute that contains an [Int] value.
39+
* @param name The name of the attribute that contains a [Double] value.
3940
*
4041
* @return The [Double] value if it exists, null otherwise.
4142
*/
@@ -92,15 +93,135 @@ fun JSONObject.safeJSONObject(name: String): JSONObject? {
9293
return null
9394
}
9495

96+
/**
97+
* Create a [Map] from the [JSONObject].
98+
*/
99+
fun JSONObject.toMap(): Map<String, Any> {
100+
val map = mutableMapOf<String, Any>()
101+
102+
for (key in this.keys()) {
103+
map[key] = this[key]
104+
}
105+
106+
return map
107+
}
108+
95109
/**
96110
* Expand into a [JSONObject] safely.
97111
*
98112
* @param name The name of the attribute that contains a [JSONObject] value.
99113
* @param into The lambda method that will be executed to explore the [JSONObject] value, if the
100114
* attribute exists.
101115
*/
102-
fun JSONObject.expand(name: String, into: (childObject: JSONObject) -> Unit) {
116+
fun JSONObject.expandJSONObject(name: String, into: (childObject: JSONObject) -> Unit) {
103117
if (this.has(name)) {
104118
into(this.getJSONObject(name))
105119
}
106120
}
121+
122+
fun <T> JSONObject.expandJSONArray(name: String, into: (childObject: JSONObject) -> T?): List<T> {
123+
val listToRet = mutableListOf<T>()
124+
if (this.has(name)) {
125+
val jsonArray = this.getJSONArray(name)
126+
for (index in 0 until jsonArray.length()) {
127+
val itemJSONObject = jsonArray.getJSONObject(index)
128+
val item = into(itemJSONObject)
129+
if (item != null) {
130+
listToRet.add(item)
131+
}
132+
}
133+
}
134+
135+
return listToRet
136+
}
137+
138+
/**
139+
* Populate the [JSONObject] with the [Map] provided.
140+
*
141+
* @param map: The map that will contain the name/values.
142+
*
143+
* @return The [JSONObject] itself, to allow for chaining.
144+
*/
145+
fun JSONObject.putMap(map: Map<String, Any?>): JSONObject {
146+
for (identity in map) {
147+
this.put(identity.key, identity.value ?: JSONObject.NULL)
148+
}
149+
150+
return this
151+
}
152+
153+
/**
154+
* Populate the [JSONObject] as attribute [name] with the [Map] provided.
155+
*
156+
* @param name: The name of the attribute that will contain the [JSONObject] value.
157+
* @param map: The map that will contain the name/values.
158+
*
159+
* @return The [JSONObject] itself, to allow for chaining.
160+
*/
161+
fun JSONObject.putMap(name: String, map: Map<String, Any?>?): JSONObject {
162+
if (map != null) {
163+
this.putJSONObject(name) {
164+
it.putMap(map)
165+
}
166+
}
167+
168+
return this
169+
}
170+
171+
/**
172+
* Put the attribute named by [name] with a [JSONObject] value, the contents
173+
* of which are determined by the expand.
174+
*
175+
* @param name: The name of the attribute that will contain the [JSONObject] value.
176+
* @param expand: The lambda that will be called to populate the [JSONObject] value.
177+
*
178+
* @return The [JSONObject] itself, to allow for chaining.
179+
*/
180+
fun JSONObject.putJSONObject(name: String, expand: (item: JSONObject) -> Unit): JSONObject {
181+
val childJSONObject = JSONObject()
182+
expand(childJSONObject)
183+
184+
this.put(name, childJSONObject)
185+
186+
return this
187+
}
188+
189+
/**
190+
* Put the attribute named by [name] with a [JSONArray] value, the contenxt of which
191+
* are deteremined by the input.
192+
*
193+
* @param name: The name of the attribute that will contain the [JSONArray] value.
194+
* @param list: The list of items that will be converted into the [JSONArray].
195+
* @param create: The lambda that will be called for each item in [list], expecting a [JSONObject] to be added to the array.
196+
*/
197+
fun <T> JSONObject.putJSONArray(name: String, list: List<T>?, create: (item: T) -> JSONObject?): JSONObject {
198+
if (list != null) {
199+
val jsonArray = JSONArray()
200+
list.forEach {
201+
val item = create(it)
202+
if (item != null) {
203+
jsonArray.put(item)
204+
}
205+
}
206+
this.put(name, jsonArray)
207+
}
208+
209+
return this
210+
}
211+
212+
/**
213+
* Put the name/value pair into the [JSONObject]. If the [value] provided is null,
214+
* nothing will be put into the [JSONObject].
215+
*
216+
* @param name The name of the attribute the [value] will be saved to.
217+
* @param value The value to put into the [JSONObject]. If not null, the attribute name will not be added.
218+
*
219+
* @return The [JSONObject] itself, to allow for chaining.
220+
*/
221+
fun JSONObject.putSafe(name: String, value: Any?): JSONObject {
222+
if (value != null) {
223+
this.put(name, value)
224+
}
225+
226+
return this
227+
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/common/modeling/MapModel.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,28 +35,28 @@ open class MapModel<V>(
3535
}
3636

3737
override fun get(key: String): V {
38-
return getProperty(key)
38+
return getOptAnyProperty(key) as V
3939
}
4040

4141
override fun clear() {
4242
for (property in data.keys)
43-
setProperty(property, null)
43+
setOptAnyProperty(property, null)
4444
}
4545

4646
override fun put(key: String, value: V): V {
47-
setProperty(key, value)
47+
setOptAnyProperty(key, value)
4848
return value
4949
}
5050

5151
override fun putAll(from: Map<out String, V>) {
5252
for (item in from) {
53-
setProperty(item.key, item.value)
53+
setOptAnyProperty(item.key, item.value)
5454
}
5555
}
5656

5757
override fun remove(key: String): V {
58-
val value = getProperty<V>(key)
59-
setProperty(key, null)
58+
val value = getOptAnyProperty(key) as V
59+
setOptAnyProperty(key, null)
6060
return value
6161
}
6262
}

0 commit comments

Comments
 (0)