Skip to content

Commit ecbe38b

Browse files
committed
Fix Permission observer not being called
* When the user swaps from the app to the setting and enables/disable notification fast enough no avoid onLostFocus runnable, the permission observer was not being fired * Add new lifecycle event tracking, onStart, and onStop * Check permission under on Start
1 parent 45729ae commit ecbe38b

File tree

6 files changed

+84
-13
lines changed

6 files changed

+84
-13
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ void onActivityCreated(Activity activity) {
8585
}
8686

8787
void onActivityStarted(Activity activity) {
88+
focusHandler.startOnStartFocusWork();
8889
}
8990

9091
void onActivityResumed(Activity activity) {
@@ -106,6 +107,7 @@ void onActivityPaused(Activity activity) {
106107

107108
void onActivityStopped(Activity activity) {
108109
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "onActivityStopped: " + activity);
110+
focusHandler.startOnStopFocusWork();
109111

110112
if (activity == curActivity) {
111113
curActivity = null;
@@ -184,8 +186,7 @@ private void handleFocus() {
184186
if (focusHandler.hasBackgrounded() || nextResumeIsFirstActivity) {
185187
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.DEBUG, "ActivityLifecycleHandler reset background state, call app focus");
186188
nextResumeIsFirstActivity = false;
187-
focusHandler.resetBackgroundState();
188-
OneSignal.onAppFocus();
189+
focusHandler.startOnFocusWork();
189190
} else {
190191
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.DEBUG, "ActivityLifecycleHandler cancel background lost focus worker");
191192
focusHandler.cancelOnLostFocusWorker(FOCUS_LOST_WORKER_TAG, OneSignal.appContext);

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSFocusHandler.kt

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,38 @@
2828
package com.onesignal
2929

3030
import android.content.Context
31+
import android.os.Handler
3132
import androidx.work.*
3233
import java.util.concurrent.TimeUnit
3334

3435
class OSFocusHandler {
3536

37+
private var stopRunnable: Runnable? = null
38+
3639
fun hasBackgrounded() = backgrounded
3740

3841
fun hasCompleted() = completed
3942

40-
fun resetBackgroundState() {
41-
backgrounded = false
43+
fun startOnFocusWork() {
44+
resetBackgroundState()
45+
OneSignal.onAppFocus()
46+
}
47+
48+
fun startOnStartFocusWork() {
49+
if (stopped) {
50+
stopped = false
51+
OSTimeoutHandler.getTimeoutHandler().destroyTimeout(stopRunnable)
52+
stopRunnable = null
53+
OneSignal.onAppStartFocusLogic()
54+
}
55+
}
56+
57+
fun startOnStopFocusWork() {
58+
stopRunnable = Runnable {
59+
stopped = true
60+
}.also {
61+
OSTimeoutHandler.getTimeoutHandler().startTimeout(stopDelay, it)
62+
}
4263
}
4364

4465
fun startOnLostFocusWorker(tag: String, delay: Long, context: Context) {
@@ -60,6 +81,10 @@ class OSFocusHandler {
6081
WorkManager.getInstance(context).cancelAllWorkByTag(tag)
6182
}
6283

84+
private fun resetBackgroundState() {
85+
backgrounded = false
86+
}
87+
6388
private fun buildConstraints(): Constraints {
6489
return Constraints.Builder()
6590
.setRequiredNetworkType(NetworkType.CONNECTED)
@@ -75,6 +100,8 @@ class OSFocusHandler {
75100
}
76101

77102
companion object {
103+
private const val stopDelay = 1500L
104+
private var stopped = false
78105
private var backgrounded = false
79106
private var completed = false
80107

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,7 @@ static void logHttpError(String errorString, int statusCode, Throwable throwable
12961296
Log(LOG_LEVEL.WARN, "HTTP code: " + statusCode + " " + errorString + jsonError, throwable);
12971297
}
12981298

1299-
// Returns true if there is active time that is unsynced.
1299+
// Returns true if there is active time that is non synced.
13001300
@WorkerThread
13011301
static void onAppLostFocus() {
13021302
Log(LOG_LEVEL.DEBUG, "Application lost focus initDone: " + initDone);
@@ -1375,6 +1375,10 @@ static void onAppFocus() {
13751375
onAppFocusLogic();
13761376
}
13771377

1378+
static void onAppStartFocusLogic() {
1379+
getCurrentPermissionState(appContext).refreshAsTo();
1380+
}
1381+
13781382
private static void onAppFocusLogic() {
13791383
// Make sure without privacy consent, onAppFocus returns early
13801384
if (shouldLogUserPrivacyConsentErrorMessageForMethodName("onAppFocus"))

OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowFocusHandler.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,32 @@ import android.content.Context
3535
import com.onesignal.OSFocusHandler.Companion.onLostFocusDoWork
3636
import org.robolectric.annotation.Implementation
3737
import org.robolectric.annotation.Implements
38+
import org.robolectric.annotation.RealObject
3839

3940
@Implements(OSFocusHandler::class)
4041
class ShadowFocusHandler {
42+
43+
@Implementation
44+
fun startOnStartFocusWork() {
45+
hasStopped = false
46+
OneSignal.onAppStartFocusLogic()
47+
}
48+
49+
@Implementation
50+
fun startOnStopFocusWork() {
51+
hasStopped = true
52+
}
53+
4154
@Implementation
4255
fun startOnLostFocusWorker(tag: String, delay: Long, context: Context) {
4356
onLostFocusDoWork()
4457
}
58+
59+
companion object {
60+
var hasStopped = false
61+
62+
fun resetStatics() {
63+
hasStopped = false
64+
}
65+
}
4566
}

OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
import static com.test.onesignal.TestHelpers.pauseActivity;
164164
import static com.test.onesignal.TestHelpers.restartAppAndElapseTimeToNextSession;
165165
import static com.test.onesignal.TestHelpers.startRemoteNotificationReceivedHandlerService;
166+
import static com.test.onesignal.TestHelpers.stopActivity;
166167
import static com.test.onesignal.TestHelpers.threadAndTaskWait;
167168
import static junit.framework.Assert.assertEquals;
168169
import static junit.framework.Assert.assertFalse;
@@ -686,6 +687,20 @@ public void testAppTwiceOnFocusNeededAfterOnSessionCallFail() throws Exception {
686687
assertRestCalls(4);
687688
}
688689

690+
@Test
691+
public void testAppStartFocus() throws Exception {
692+
OneSignalInit();
693+
threadAndTaskWait();
694+
695+
assertTrue(ShadowOneSignalRestClient.lastUrl.matches("players"));
696+
697+
stopActivity(blankActivityController);
698+
assertTrue(ShadowFocusHandler.Companion.getHasStopped());
699+
700+
blankActivityController.resume();
701+
assertFalse(ShadowFocusHandler.Companion.getHasStopped());
702+
}
703+
689704
private void setOneSignalContextOpenAppThenBackgroundAndResume() throws Exception {
690705
// 1. Context could be set by the app like this; Or on it's own when a push or other event happens
691706
OneSignal.initWithContext(blankActivity.getApplication());
@@ -3196,22 +3211,18 @@ public void shouldFirePermissionObserverWhenUserDisablesNotifications() throws E
31963211
OneSignalInit();
31973212
threadAndTaskWait();
31983213

3199-
OSPermissionObserver permissionObserver = new OSPermissionObserver() {
3200-
@Override
3201-
public void onOSPermissionChanged(OSPermissionStateChanges stateChanges) {
3202-
lastPermissionStateChanges = stateChanges;
3203-
currentPermission = stateChanges.getTo().areNotificationsEnabled();
3204-
}
3214+
OSPermissionObserver permissionObserver = stateChanges -> {
3215+
lastPermissionStateChanges = stateChanges;
3216+
currentPermission = stateChanges.getTo().areNotificationsEnabled();
32053217
};
32063218
OneSignal.addPermissionObserver(permissionObserver);
32073219
lastPermissionStateChanges = null;
32083220
// Make sure garbage collection doesn't nuke any observers.
32093221
Runtime.getRuntime().gc();
32103222

3211-
pauseActivity(blankActivityController);
3223+
stopActivity(blankActivityController);
32123224
ShadowNotificationManagerCompat.enabled = false;
32133225
blankActivityController.resume();
3214-
threadAndTaskWait();
32153226

32163227
assertTrue(lastPermissionStateChanges.getFrom().areNotificationsEnabled());
32173228
assertFalse(lastPermissionStateChanges.getTo().areNotificationsEnabled());

OneSignalSDK/unittest/src/test/java/com/test/onesignal/TestHelpers.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.onesignal.ShadowDynamicTimer;
3030
import com.onesignal.ShadowFCMBroadcastReceiver;
3131
import com.onesignal.ShadowFirebaseAnalytics;
32+
import com.onesignal.ShadowFocusHandler;
3233
import com.onesignal.ShadowFusedLocationApiWrapper;
3334
import com.onesignal.ShadowGenerateNotification;
3435
import com.onesignal.ShadowGoogleApiClientCompatProxy;
@@ -129,6 +130,7 @@ static void beforeTestInitAndCleanup() throws Exception {
129130
ShadowNotificationReceivedEvent.resetStatics();
130131
ShadowOneSignalNotificationManager.resetStatics();
131132
ShadowBadgeCountUpdater.resetStatics();
133+
ShadowFocusHandler.Companion.resetStatics();
132134

133135
lastException = null;
134136
}
@@ -588,6 +590,11 @@ public static void pauseActivity(ActivityController activityController) throws E
588590
threadAndTaskWait();
589591
}
590592

593+
public static void stopActivity(ActivityController activityController) throws Exception {
594+
activityController.stop();
595+
threadAndTaskWait();
596+
}
597+
591598
public static void assertAndRunSyncService() throws Exception {
592599
// There should be a SyncJobService service scheduled
593600
assertNumberOfServicesAvailable(1);

0 commit comments

Comments
 (0)