Skip to content

Commit 23433b6

Browse files
authored
Merge pull request #1768 from OneSignal/user-model/user-events
[User model] Push Subscription Changed Event
2 parents ce67625 + 49480f0 commit 23433b6

File tree

14 files changed

+127
-62
lines changed

14 files changed

+127
-62
lines changed

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

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import android.content.Intent;
1818
import android.os.Build;
19+
import android.util.Log;
1920
import android.util.Pair;
2021
import android.view.View;
2122
import android.view.ViewTreeObserver;
@@ -54,14 +55,15 @@
5455
import com.onesignal.sdktest.util.ProfileUtil;
5556
import com.onesignal.sdktest.util.Toaster;
5657
import com.onesignal.user.subscriptions.ISubscription;
57-
import com.onesignal.user.subscriptions.ISubscriptionChangedHandler;
58+
import com.onesignal.user.subscriptions.IPushSubscriptionObserver;
59+
import com.onesignal.user.subscriptions.PushSubscriptionChangedState;
5860

5961
import java.util.ArrayList;
6062
import java.util.HashMap;
6163
import java.util.Map;
6264

6365
@RequiresApi(api = Build.VERSION_CODES.N)
64-
public class MainActivityViewModel implements ActivityViewModel, ISubscriptionChangedHandler {
66+
public class MainActivityViewModel implements ActivityViewModel, IPushSubscriptionObserver {
6567

6668
private Animate animate;
6769
private Dialog dialog;
@@ -290,7 +292,7 @@ public ActivityViewModel onActivityCreated(Context context) {
290292
triggerSet = new HashMap<>();
291293
triggerArrayList = new ArrayList<>();
292294

293-
OneSignal.getUser().getPushSubscription().addChangeHandler(this);
295+
OneSignal.getUser().getPushSubscription().addObserver(this);
294296
return this;
295297
}
296298

@@ -494,6 +496,11 @@ public void run() {
494496
});
495497
}
496498

499+
@Override
500+
public void onPushSubscriptionChange(@NonNull PushSubscriptionChangedState state) {
501+
refreshSubscriptionState();
502+
}
503+
497504
private class DummySubscription implements ISubscription {
498505

499506
private String _id;
@@ -506,16 +513,6 @@ public DummySubscription(String id) {
506513
public String getId() {
507514
return _id;
508515
}
509-
510-
@Override
511-
public void addChangeHandler(@NonNull ISubscriptionChangedHandler handler) {
512-
513-
}
514-
515-
@Override
516-
public void removeChangeHandler(@NonNull ISubscriptionChangedHandler handler) {
517-
518-
}
519516
}
520517

521518
private void setupEmailLayout() {
@@ -825,19 +822,6 @@ private void setupPromptPushButton() {
825822
});
826823
}
827824

828-
@Override
829-
public void onSubscriptionChanged(@NonNull ISubscription subscription) {
830-
if(subscription instanceof IPushSubscription) {
831-
refreshSubscriptionState();
832-
}
833-
else if(subscription instanceof IEmailSubscription) {
834-
refreshEmailRecyclerView();
835-
}
836-
else if(subscription instanceof ISmsSubscription) {
837-
refreshSMSRecyclerView();
838-
}
839-
}
840-
841825
private void refreshSubscriptionState() {
842826
boolean isPermissionEnabled = OneSignal.getNotifications().getPermission();
843827
IPushSubscription pushSubscription = OneSignal.getUser().getPushSubscription();

MIGRATION_GUIDE.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,34 @@ To resume receiving of push notifications (driving the native permission prompt
149149

150150
pushSubscription.optIn()
151151

152+
To observe changes to the push subscription a class can implement the IPushSubscriptionObserver interface, and can then be added as an observer:
153+
154+
**Java**
155+
156+
@Override
157+
public void onPushSubscriptionChange(@NonNull PushSubscriptionChangedState state) {
158+
...
159+
}
160+
161+
pushSubscription.addObserver(this);
162+
163+
**Kotlin**
164+
165+
override fun onPushSubscriptionChange(state: PushSubscriptionChangedState) {
166+
...
167+
}
168+
169+
pushSubscription.addObserver(this)
170+
171+
If you would like to stop observing the subscription you can remove the observer:
172+
173+
**Java**
174+
175+
pushSubscription.removeObserver(this);
176+
177+
**Kotlin**
178+
179+
pushSubscription.removeObserver(this)
152180

153181
**Email/SMS Subscriptions**
154182
Email and/or SMS subscriptions can be added or removed via:
@@ -186,12 +214,12 @@ The OneSignal SDK has been rewritten in Kotlin. This is typically transparent to
186214
In Java this is surfaced on a method via an additional parameter to the method of type `Continuation`. The `Continuation` is a callback mechanism which allows a Java function to gain control when execution has resumed. If this concept is newer to your application codebase, OneSignal provides an optional java helper class to facilitate the callback model. Method `com.onesignal.Continue.none()` can be used to indicate no callback is necessary:
187215

188216

189-
OneSignal.getNotifications().requestPermission(Continue.none());
217+
OneSignal.getNotifications().requestPermission(true, Continue.none());
190218

191219
`com.onesignal.Continue.with()` can be used to create a callback lambda expression, which is passed a `ContinueResult` containing information on the success of the underlying coroutine, it's return data, and/or the exception that was thrown:
192220

193221

194-
OneSignal.getNotifications().requestPermission(Continue.with(r -> {
222+
OneSignal.getNotifications().requestPermission(true, Continue.with(r -> {
195223
if (r.isSuccess()) {
196224
if (r.getData()) {
197225
// code to execute once requestPermission has completed successfully and the user has accepted permission.

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/PushSubscription.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
package com.onesignal.user.internal
22

3+
import com.onesignal.common.events.EventProducer
34
import com.onesignal.user.internal.subscriptions.SubscriptionModel
45
import com.onesignal.user.internal.subscriptions.SubscriptionStatus
56
import com.onesignal.user.internal.subscriptions.SubscriptionType
67
import com.onesignal.user.subscriptions.IPushSubscription
8+
import com.onesignal.user.subscriptions.IPushSubscriptionObserver
9+
import com.onesignal.user.subscriptions.PushSubscriptionState
710

811
internal open class PushSubscription(
912
model: SubscriptionModel,
1013
) : Subscription(model), IPushSubscription {
14+
val changeHandlersNotifier = EventProducer<IPushSubscriptionObserver>()
15+
var savedState = fetchState()
16+
private set;
1117

1218
override val token: String
1319
get() = model.address
@@ -24,6 +30,18 @@ internal open class PushSubscription(
2430
override fun optOut() {
2531
model.optedIn = false
2632
}
33+
34+
override fun addObserver(observer: IPushSubscriptionObserver) = changeHandlersNotifier.subscribe(observer)
35+
override fun removeObserver(observer: IPushSubscriptionObserver) = changeHandlersNotifier.unsubscribe(observer)
36+
37+
fun refreshState() : PushSubscriptionState {
38+
savedState = fetchState()
39+
return savedState
40+
}
41+
42+
private fun fetchState() : PushSubscriptionState {
43+
return PushSubscriptionState(id, token, optedIn)
44+
}
2745
}
2846

2947
internal class UninitializedPushSubscription() : PushSubscription(createFakePushSub()) {

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/Subscription.kt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.onesignal.common.IDManager
44
import com.onesignal.common.events.EventProducer
55
import com.onesignal.user.internal.subscriptions.SubscriptionModel
66
import com.onesignal.user.subscriptions.ISubscription
7-
import com.onesignal.user.subscriptions.ISubscriptionChangedHandler
7+
import com.onesignal.user.subscriptions.IPushSubscriptionObserver
88

99
/**
1010
* An abstract subscription represents an open channel between
@@ -13,11 +13,5 @@ import com.onesignal.user.subscriptions.ISubscriptionChangedHandler
1313
internal abstract class Subscription(
1414
val model: SubscriptionModel,
1515
) : ISubscription {
16-
17-
val changeHandlersNotifier = EventProducer<ISubscriptionChangedHandler>()
18-
1916
override val id: String get() = if (IDManager.isLocalId(model.id)) "" else model.id
20-
21-
override fun addChangeHandler(handler: ISubscriptionChangedHandler) = changeHandlersNotifier.subscribe(handler)
22-
override fun removeChangeHandler(handler: ISubscriptionChangedHandler) = changeHandlersNotifier.unsubscribe(handler)
2317
}

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/UserManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import com.onesignal.user.internal.properties.PropertiesModel
1212
import com.onesignal.user.internal.properties.PropertiesModelStore
1313
import com.onesignal.user.internal.subscriptions.ISubscriptionManager
1414
import com.onesignal.user.subscriptions.IPushSubscription
15-
import com.onesignal.user.subscriptions.SubscriptionList
15+
import com.onesignal.user.internal.subscriptions.SubscriptionList
1616

1717
internal open class UserManager(
1818
private val _subscriptionManager: ISubscriptionManager,

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/ISubscriptionManager.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.onesignal.user.internal.subscriptions
33
import com.onesignal.common.events.IEventNotifier
44
import com.onesignal.common.modeling.ModelChangedArgs
55
import com.onesignal.user.subscriptions.ISubscription
6-
import com.onesignal.user.subscriptions.SubscriptionList
76

87
interface ISubscriptionManager : IEventNotifier<ISubscriptionChangedHandler> {
98
var subscriptions: SubscriptionList

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/SubscriptionList.kt renamed to OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/SubscriptionList.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
package com.onesignal.user.subscriptions
1+
package com.onesignal.user.internal.subscriptions
2+
3+
import com.onesignal.user.subscriptions.IEmailSubscription
4+
import com.onesignal.user.subscriptions.IPushSubscription
5+
import com.onesignal.user.subscriptions.ISmsSubscription
6+
import com.onesignal.user.subscriptions.ISubscription
27

38
/**
49
* A readonly list of subscriptions. Wraps a standard [List] to help navigate the list of

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/impl/SubscriptionManager.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import com.onesignal.user.internal.subscriptions.SubscriptionModelStore
1818
import com.onesignal.user.internal.subscriptions.SubscriptionStatus
1919
import com.onesignal.user.internal.subscriptions.SubscriptionType
2020
import com.onesignal.user.subscriptions.ISubscription
21-
import com.onesignal.user.subscriptions.SubscriptionList
21+
import com.onesignal.user.internal.subscriptions.SubscriptionList
22+
import com.onesignal.user.subscriptions.PushSubscriptionChangedState
2223

2324
/**
2425
* The subscription manager is responsible for managing the external representation of the
@@ -131,12 +132,15 @@ internal class SubscriptionManager(
131132
// don't yet have a representation for it in the subscription list.
132133
createSubscriptionAndAddToSubscriptionList(args.model as SubscriptionModel)
133134
} else {
134-
(subscription as Subscription).changeHandlersNotifier.fireOnMain {
135-
it.onSubscriptionChanged(
136-
subscription,
137-
)
135+
if (subscription is PushSubscription) {
136+
subscription.changeHandlersNotifier.fireOnMain {
137+
it.onPushSubscriptionChange(
138+
PushSubscriptionChangedState(
139+
subscription.savedState,
140+
subscription.refreshState())
141+
)
142+
}
138143
}
139-
140144
// the model has already been updated, so fire the update event
141145
_events.fire { it.onSubscriptionChanged(subscription, args) }
142146
}
@@ -161,7 +165,7 @@ internal class SubscriptionManager(
161165

162166
// There can only be 1 push subscription, always transfer any subscribers from the old one to the new
163167
if (subscriptionModel.type == SubscriptionType.PUSH) {
164-
val existingPushSubscription = this.subscriptions.push as Subscription
168+
val existingPushSubscription = this.subscriptions.push as PushSubscription
165169
((subscription as PushSubscription).changeHandlersNotifier).subscribeAll(existingPushSubscription.changeHandlersNotifier)
166170
subscriptions.remove(existingPushSubscription)
167171
}

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/IPushSubscription.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package com.onesignal.user.subscriptions
55
* channel.
66
*/
77
interface IPushSubscription : ISubscription {
8-
98
/**
109
* The token which identifies the device/app that notifications are to be sent. May
1110
* be an empty string, indicating the push token has not yet been retrieved.
@@ -34,4 +33,15 @@ interface IPushSubscription : ISubscription {
3433
* notifications, although the app permission state will not be changed.
3534
*/
3635
fun optOut()
36+
37+
/**
38+
* Add an observer to this subscription, allowing the provider to be
39+
* notified whenever the subscription has changed.
40+
*/
41+
fun addObserver(observer: IPushSubscriptionObserver)
42+
43+
/**
44+
* Remove an observer from this subscription.
45+
*/
46+
fun removeObserver(observer: IPushSubscriptionObserver)
3747
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ package com.onesignal.user.subscriptions
22

33
/**
44
* A subscription changed handler. Implement this interface and provide the implementation
5-
* to [ISubscription.addChangeHandler] to be notified when the subscription has changed.
5+
* to [ISubscription.addObserver] to be notified when the subscription has changed.
66
*/
7-
interface ISubscriptionChangedHandler {
7+
interface IPushSubscriptionObserver {
88

99
/**
1010
* Called when the subscription this change handler was added to, has changed. A
1111
* subscription can change either because of a change driven by the application, or
1212
* by the backend.
1313
*
14-
* @param subscription The subscription that has been changed.
14+
* @param state The subscription changed state.
1515
*/
16-
fun onSubscriptionChanged(subscription: ISubscription)
16+
fun onPushSubscriptionChange(state: PushSubscriptionChangedState)
1717
}

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/subscriptions/ISubscription.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,4 @@ interface ISubscription {
1111
* been successfully assigned.
1212
*/
1313
val id: String
14-
15-
/**
16-
* Add a change handler to this subscription, allowing the provider to be
17-
* notified whenever the subscription has changed.
18-
*/
19-
fun addChangeHandler(handler: ISubscriptionChangedHandler)
20-
21-
/**
22-
* Remove a change handler from this subscription.
23-
*/
24-
fun removeChangeHandler(handler: ISubscriptionChangedHandler)
2514
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.onesignal.user.subscriptions
2+
3+
class PushSubscriptionChangedState(
4+
val previous: PushSubscriptionState,
5+
val current: PushSubscriptionState
6+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.onesignal.user.subscriptions
2+
3+
/**
4+
* A subscription state.
5+
*/
6+
class PushSubscriptionState(
7+
/**
8+
* The unique identifier for this subscription. This will be an empty string
9+
* until the subscription has been successfully created on the backend and
10+
* assigned an ID. Use [addObserver] to be notified when the [id] has
11+
* been successfully assigned.
12+
*/
13+
val id: String,
14+
15+
/**
16+
* The token which identifies the device/app that notifications are to be sent. May
17+
* be an empty string, indicating the push token has not yet been retrieved.
18+
*/
19+
val token: String,
20+
21+
/**
22+
* Whether the user of this subscription is opted-in to received notifications. When true,
23+
* the user is able to receive notifications through this subscription. Otherwise, the
24+
* user will not receive notifications through this subscription (even when the user has
25+
* granted app permission).
26+
*/
27+
val optedIn: Boolean
28+
)

OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/UserManagerTests.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.onesignal.user.internal
33
import com.onesignal.core.internal.language.ILanguageContext
44
import com.onesignal.mocks.MockHelper
55
import com.onesignal.user.internal.subscriptions.ISubscriptionManager
6-
import com.onesignal.user.subscriptions.SubscriptionList
6+
import com.onesignal.user.internal.subscriptions.SubscriptionList
77
import io.kotest.core.spec.style.FunSpec
88
import io.kotest.matchers.shouldBe
99
import io.kotest.runner.junit4.KotestTestRunner

0 commit comments

Comments
 (0)