Skip to content

Commit 4c9cce1

Browse files
authored
Merge pull request #214 from OneSignal/permission_and_subscription_observers
* Added new permission and subscription observers - Includes addPermissionObserver and addSubscriptionObserver * Added getPermissionSubscriptionState * Badges are cleared and no longer set if user disables notifications in Settings. * Added unsubscribeWhenNotificationsAreDisabled option
2 parents 2ce40ab + 3655b0d commit 4c9cce1

21 files changed

+1100
-39
lines changed

OneSignalSDK/onesignal/consumer-proguard-rules.pro

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@
88
-keep public interface android.app.OnActivityPausedListener {*;}
99
-keep class com.onesignal.ActivityLifecycleListenerCompat** {*;}
1010

11+
-keep class com.onesignal.OSSubscriptionState {
12+
void changed(com.onesignal.OSPermissionState);
13+
}
14+
15+
-keep class com.onesignal.OSPermissionChangedInternalObserver {
16+
void changed(com.onesignal.OSPermissionState);
17+
}
18+
19+
-keep class com.onesignal.OSSubscriptionChangedInternalObserver {
20+
void changed(com.onesignal.OSSubscriptionState);
21+
}
22+
23+
-keep class ** implements com.onesignal.OSPermissionObserver {
24+
void onOSPermissionChanged(com.onesignal.OSPermissionStateChanges);
25+
}
26+
27+
-keep class ** implements com.onesignal.OSSubscriptionObserver {
28+
void onOSSubscriptionChanged(com.onesignal.OSSubscriptionStateChanges);
29+
}
1130

1231
-keep class com.onesignal.shortcutbadger.impl.AdwHomeBadger { <init>(...); }
1332
-keep class com.onesignal.shortcutbadger.impl.ApexHomeBadger { <init>(...); }

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class BadgeCountUpdater {
4141
// Cache for manifest setting.
4242
private static int badgesEnabled = -1;
4343

44-
private static boolean isBadgesEnabled(Context context) {
44+
private static boolean areBadgeSettingsEnabled(Context context) {
4545
if (badgesEnabled != -1)
4646
return (badgesEnabled == 1);
4747

@@ -57,9 +57,13 @@ private static boolean isBadgesEnabled(Context context) {
5757

5858
return (badgesEnabled == 1);
5959
}
60+
61+
private static boolean areBadgesEnabled(Context context) {
62+
return areBadgeSettingsEnabled(context) && OSUtils.areNotificationsEnabled(context);
63+
}
6064

6165
static void update(SQLiteDatabase readableDb, Context context) {
62-
if (!isBadgesEnabled(context))
66+
if (!areBadgesEnabled(context))
6367
return;
6468

6569
Cursor cursor = readableDb.query(
@@ -79,7 +83,7 @@ static void update(SQLiteDatabase readableDb, Context context) {
7983
}
8084

8185
static void updateCount(int count, Context context) {
82-
if (!isBadgesEnabled(context))
86+
if (!areBadgeSettingsEnabled(context))
8387
return;
8488

8589
// Can throw if badges are not support on the device.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
import java.lang.ref.WeakReference;
31+
import java.lang.reflect.Method;
32+
import java.util.ArrayList;
33+
import java.util.List;
34+
35+
class OSObservable<ObserverType, StateType> {
36+
private String methodName;
37+
private List<Object> observers;
38+
private boolean fireOnMainThread;
39+
40+
OSObservable(String methodName, boolean fireOnMainThread) {
41+
this.methodName = methodName;
42+
this.fireOnMainThread = fireOnMainThread;
43+
observers = new ArrayList<>();
44+
}
45+
46+
void addObserver(ObserverType observer) {
47+
observers.add(new WeakReference<>(observer));
48+
}
49+
50+
void addObserverStrong(ObserverType observer){
51+
observers.add(observer);
52+
}
53+
54+
void removeObserver(ObserverType observer) {
55+
for(int i = 0; i < observers.size(); i++) {
56+
Object anObserver = ((WeakReference)observers.get(i)).get();
57+
if (anObserver.equals(observer)) {
58+
observers.remove(i);
59+
break;
60+
}
61+
}
62+
}
63+
64+
boolean notifyChange(final StateType state) {
65+
boolean notified = false;
66+
67+
for(Object observer : observers) {
68+
final Object strongRefObserver;
69+
if (observer instanceof WeakReference)
70+
strongRefObserver = ((WeakReference)observer).get();
71+
else
72+
strongRefObserver = observer;
73+
74+
if (strongRefObserver != null) {
75+
try {
76+
Class<?> clazz = strongRefObserver.getClass();
77+
final Method method = clazz.getDeclaredMethod(methodName, state.getClass());
78+
method.setAccessible(true);
79+
if (fireOnMainThread) {
80+
OSUtils.runOnMainUIThread(
81+
new Runnable() {
82+
@Override
83+
public void run() {
84+
try {
85+
method.invoke(strongRefObserver, state);
86+
}
87+
catch (Throwable t) {
88+
t.printStackTrace();
89+
}
90+
}
91+
});
92+
93+
}
94+
else
95+
method.invoke(strongRefObserver, state);
96+
notified = true;
97+
} catch (Throwable t) {
98+
t.printStackTrace();
99+
}
100+
}
101+
}
102+
103+
return notified;
104+
}
105+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 OSPermissionChangedInternalObserver {
31+
void changed(OSPermissionState state) {
32+
handleInternalChanges(state);
33+
fireChangesToPublicObserver(state);
34+
}
35+
36+
static void handleInternalChanges(OSPermissionState state) {
37+
if (!state.getEnabled())
38+
BadgeCountUpdater.updateCount(0, OneSignal.appContext);
39+
OneSignalStateSynchronizer.setPermission(OneSignal.areNotificationsEnabledForSubscribedState());
40+
}
41+
42+
// Handles firing a public facing PermissionStateChangesObserver
43+
// 1. Generates a OSPermissionStateChanges object and sets to and from states
44+
// 2. Persists acknowledgement
45+
// - Prevents duplicated events
46+
// - Notifies if changes were made outside of the app
47+
static void fireChangesToPublicObserver(OSPermissionState state) {
48+
OSPermissionStateChanges stateChanges = new OSPermissionStateChanges();
49+
stateChanges.from = OneSignal.lastPermissionState;
50+
stateChanges.to = (OSPermissionState)state.clone();
51+
52+
boolean hasReceiver = OneSignal.getPermissionStateChangesObserver().notifyChange(stateChanges);
53+
if (hasReceiver) {
54+
OneSignal.lastPermissionState = (OSPermissionState)state.clone();
55+
OneSignal.lastPermissionState.persistAsFrom();
56+
}
57+
}
58+
}
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 OSPermissionObserver {
31+
void onOSPermissionChanged(OSPermissionStateChanges stateChanges);
32+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
import android.content.SharedPreferences;
31+
32+
import static com.onesignal.OneSignal.appContext;
33+
import static com.onesignal.OneSignal.getGcmPreferences;
34+
35+
public class OSPermissionState implements Cloneable {
36+
37+
OSObservable<Object, OSPermissionState> observable;
38+
39+
OSPermissionState(boolean asFrom) {
40+
// Java 8 method reference can be used in the future with Android Studio 2.4.0
41+
// OSPermissionChangedInternalObserver::changed
42+
observable = new OSObservable<>("changed", false);
43+
44+
if (asFrom) {
45+
final SharedPreferences prefs = getGcmPreferences(appContext);
46+
enabled = prefs.getBoolean("ONESIGNAL_ACCEPTED_NOTIFICATION_LAST", false);
47+
}
48+
else
49+
refreshAsTo();
50+
}
51+
52+
private boolean enabled;
53+
54+
void refreshAsTo() {
55+
setEnabled(OSUtils.areNotificationsEnabled(appContext));
56+
}
57+
58+
public boolean getEnabled() {
59+
return enabled;
60+
}
61+
62+
private void setEnabled(boolean set) {
63+
boolean changed = enabled != set;
64+
enabled = set;
65+
if (changed)
66+
observable.notifyChange(this);
67+
}
68+
69+
void persistAsFrom() {
70+
final SharedPreferences prefs = getGcmPreferences(appContext);
71+
SharedPreferences.Editor editor = prefs.edit();
72+
editor.putBoolean("ONESIGNAL_ACCEPTED_NOTIFICATION_LAST", enabled);
73+
editor.commit();
74+
}
75+
76+
boolean compare(OSPermissionState from) {
77+
return enabled != from.enabled;
78+
}
79+
80+
protected Object clone() {
81+
try {
82+
return super.clone();
83+
} catch (Throwable t) {}
84+
return null;
85+
}
86+
87+
88+
// FUTURE: Can add a list of categories here for Android O.
89+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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 OSPermissionStateChanges {
31+
OSPermissionState to, from;
32+
33+
public OSPermissionState getTo() {
34+
return to;
35+
}
36+
37+
public OSPermissionState getFrom() {
38+
return from;
39+
}
40+
}

0 commit comments

Comments
 (0)