Skip to content

Commit e6b6028

Browse files
committed
Added SubscriptionObserver
* Also added fireOnMainThread setting for public observers to fire on.
1 parent a9dac1b commit e6b6028

12 files changed

+449
-39
lines changed

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSObservable.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@
3535
class OSObservable<ObserverType, StateType> {
3636
private String methodName;
3737
private List<Object> observers;
38+
private boolean fireOnMainThread;
3839

39-
OSObservable(String methodName) {
40+
OSObservable(String methodName, boolean fireOnMainThread) {
4041
this.methodName = methodName;
42+
this.fireOnMainThread = fireOnMainThread;
4143
observers = new ArrayList<>();
4244
}
4345

@@ -49,11 +51,11 @@ void addObserverStrong(ObserverType observer){
4951
observers.add(observer);
5052
}
5153

52-
boolean notifyChange(StateType state) {
54+
boolean notifyChange(final StateType state) {
5355
boolean notified = false;
5456

5557
for(Object observer : observers) {
56-
Object strongRefObserver;
58+
final Object strongRefObserver;
5759
if (observer instanceof WeakReference)
5860
strongRefObserver = ((WeakReference)observer).get();
5961
else
@@ -62,9 +64,25 @@ boolean notifyChange(StateType state) {
6264
if (strongRefObserver != null) {
6365
try {
6466
Class<?> clazz = strongRefObserver.getClass();
65-
Method method = clazz.getMethod(methodName, state.getClass());
67+
final Method method = clazz.getMethod(methodName, state.getClass());
6668
method.setAccessible(true);
67-
method.invoke(strongRefObserver, state);
69+
if (fireOnMainThread) {
70+
OSUtils.runOnMainUIThread(
71+
new Runnable() {
72+
@Override
73+
public void run() {
74+
try {
75+
method.invoke(strongRefObserver, state);
76+
}
77+
catch (Throwable t) {
78+
t.printStackTrace();
79+
}
80+
}
81+
});
82+
83+
}
84+
else
85+
method.invoke(strongRefObserver, state);
6886
notified = true;
6987
} catch (Throwable t) {
7088
t.printStackTrace();

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSPermissionChangedInternalObserver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Modified MIT License
33
*
4-
* Copyright 2016 OneSignal
4+
* Copyright 2017 OneSignal
55
*
66
* Permission is hereby granted, free of charge, to any person obtaining a copy
77
* of this software and associated documentation files (the "Software"), to deal
@@ -49,7 +49,7 @@ static void handleInternalChanges(OSPermissionState state) {
4949
static void fireChangesToPublicObserver(OSPermissionState state) {
5050
OSPermissionStateChanges stateChanges = new OSPermissionStateChanges();
5151
stateChanges.from = OneSignal.lastPermissionState;
52-
stateChanges.to = state;
52+
stateChanges.to = (OSPermissionState)state.clone();
5353

5454
boolean hasReceiver = OneSignal.getPermissionStateChangesObserver().notifyChange(stateChanges);
5555
if (hasReceiver) {

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSPermissionState.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class OSPermissionState implements Cloneable {
3737
OSObservable<Object, OSPermissionState> observable;
3838

3939
OSPermissionState(boolean asFrom) {
40-
observable = new OSObservable<>("changed");
40+
observable = new OSObservable<>("changed", false);
4141

4242
if (asFrom) {
4343
final SharedPreferences prefs = getGcmPreferences(appContext);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* Modified MIT License
3+
*
4+
* Copyright 2017 OneSignal
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* 1. The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* 2. All copies of substantial portions of the Software may only be used in connection
17+
* with services provided by OneSignal.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
package com.onesignal;
29+
30+
class OSSubscriptionChangedInternalObserver {
31+
// TODO: Make sure this method doesn't get prograuded out.
32+
public void changed(OSSubscriptionState state) {
33+
fireChangesToPublicObserver(state);
34+
}
35+
36+
// Handles firing a public facing SubscriptionStateChangesObserver
37+
// 1. Generates a OSSubscriptionStateChanges object and sets to and from states
38+
// 2. Persists acknowledgement
39+
// - Prevents duplicated events
40+
// - Notifies if changes were made outside of the app
41+
static void fireChangesToPublicObserver(OSSubscriptionState state) {
42+
OSSubscriptionStateChanges stateChanges = new OSSubscriptionStateChanges();
43+
stateChanges.from = OneSignal.lastSubscriptionState;
44+
stateChanges.to = (OSSubscriptionState)state.clone();
45+
46+
boolean hasReceiver = OneSignal.getSubscriptionStateChangesObserver().notifyChange(stateChanges);
47+
if (hasReceiver) {
48+
OneSignal.lastSubscriptionState = (OSSubscriptionState)state.clone();
49+
OneSignal.lastSubscriptionState.persistAsFrom();
50+
}
51+
}
52+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Modified MIT License
3+
*
4+
* Copyright 2017 OneSignal
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* 1. The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* 2. All copies of substantial portions of the Software may only be used in connection
17+
* with services provided by OneSignal.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
package com.onesignal;
29+
30+
public interface OSSubscriptionObserver {
31+
void onOSSubscriptionChanged(OSSubscriptionStateChanges stateChanges);
32+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* Modified MIT License
3+
*
4+
* Copyright 2017 OneSignal
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* 1. The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* 2. All copies of substantial portions of the Software may only be used in connection
17+
* with services provided by OneSignal.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
package com.onesignal;
29+
30+
31+
import android.content.SharedPreferences;
32+
33+
import static com.onesignal.OneSignal.appContext;
34+
import static com.onesignal.OneSignal.getGcmPreferences;
35+
36+
public class OSSubscriptionState implements Cloneable {
37+
38+
OSObservable<Object, OSSubscriptionState> observable;
39+
40+
OSSubscriptionState(boolean asFrom, boolean permissionAccepted) {
41+
observable = new OSObservable<>("changed", false);
42+
43+
if (asFrom) {
44+
final SharedPreferences prefs = getGcmPreferences(appContext);
45+
userSubscriptionSetting = prefs.getBoolean("ONESIGNAL_SUBSCRIPTION_LAST", false);
46+
userId = prefs.getString("ONESIGNAL_PLAYER_ID_LAST", null);
47+
pushToken = prefs.getString("ONESIGNAL_PUSH_TOKEN_LAST", null);
48+
accepted = prefs.getBoolean("ONESIGNAL_PERMISSION_ACCEPTED_LAST", false);
49+
}
50+
else {
51+
userSubscriptionSetting = OneSignalStateSynchronizer.getUserSubscribePreference();
52+
userId = OneSignal.getUserId();
53+
pushToken = OneSignalStateSynchronizer.getRegistrationId();
54+
accepted = permissionAccepted;
55+
}
56+
}
57+
58+
private boolean accepted;
59+
private boolean userSubscriptionSetting;
60+
private String userId;
61+
private String pushToken;
62+
63+
public void changed(OSPermissionState state) {
64+
setAccepted(state.getEnabled());
65+
}
66+
67+
void setUserId(String id) {
68+
boolean changed = !id.equals(userId);
69+
userId = id;
70+
if (changed)
71+
observable.notifyChange(this);
72+
}
73+
74+
public String getUserId() {
75+
return userId;
76+
}
77+
78+
void setPushToken(String id) {
79+
if (id == null)
80+
return;
81+
boolean changed = !id.equals(pushToken);
82+
pushToken = id;
83+
if (changed)
84+
observable.notifyChange(this);
85+
}
86+
87+
public String getPushToken() {
88+
return pushToken;
89+
}
90+
91+
92+
void setUserSubscriptionSetting(boolean set) {
93+
boolean changed = userSubscriptionSetting != set;
94+
userSubscriptionSetting = set;
95+
if (changed)
96+
observable.notifyChange(this);
97+
}
98+
99+
public boolean getUserSubscriptionSetting() {
100+
return userSubscriptionSetting;
101+
}
102+
103+
private void setAccepted(boolean set) {
104+
boolean lastSubscribed = getSubscribed();
105+
accepted = set;
106+
if (lastSubscribed != getSubscribed())
107+
observable.notifyChange(this);
108+
}
109+
110+
public boolean getSubscribed() {
111+
return userId != null && pushToken != null && userSubscriptionSetting && accepted;
112+
}
113+
114+
void persistAsFrom() {
115+
final SharedPreferences prefs = getGcmPreferences(appContext);
116+
SharedPreferences.Editor editor = prefs.edit();
117+
118+
editor.putBoolean("ONESIGNAL_SUBSCRIPTION_LAST", userSubscriptionSetting);
119+
editor.putString("ONESIGNAL_PLAYER_ID_LAST", userId);
120+
editor.putString("ONESIGNAL_PUSH_TOKEN_LAST", pushToken);
121+
editor.putBoolean("ONESIGNAL_PERMISSION_ACCEPTED_LAST", accepted);
122+
123+
editor.commit();
124+
}
125+
126+
boolean compare(OSSubscriptionState from) {
127+
return userSubscriptionSetting != from.userSubscriptionSetting
128+
|| !(userId != null ? userId : "").equals(from.userId != null ? from.userId : "")
129+
|| !(pushToken != null ? pushToken : "").equals(from.pushToken != null ? from.pushToken : "")
130+
|| accepted != from.accepted;
131+
}
132+
133+
protected Object clone() {
134+
try {
135+
return super.clone();
136+
} catch (Throwable t) {}
137+
return null;
138+
}
139+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Modified MIT License
3+
*
4+
* Copyright 2017 OneSignal
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* 1. The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* 2. All copies of substantial portions of the Software may only be used in connection
17+
* with services provided by OneSignal.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
package com.onesignal;
29+
30+
public class OSSubscriptionStateChanges {
31+
public OSSubscriptionState to, from;
32+
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSUtils.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import android.net.ConnectivityManager;
3535
import android.net.NetworkInfo;
3636
import android.os.Bundle;
37+
import android.os.Handler;
38+
import android.os.Looper;
3739
import android.support.v4.app.NotificationManagerCompat;
3840
import android.telephony.TelephonyManager;
3941

@@ -181,4 +183,13 @@ static boolean areNotificationsEnabled(Context context) {
181183

182184
return true;
183185
}
186+
187+
static void runOnMainUIThread(Runnable runnable) {
188+
if (Looper.getMainLooper().getThread() == Thread.currentThread())
189+
runnable.run();
190+
else {
191+
Handler handler = new Handler(Looper.getMainLooper());
192+
handler.post(runnable);
193+
}
194+
}
184195
}

0 commit comments

Comments
 (0)