11package com .iterable .iterableapi ;
22
33import android .util .Base64 ;
4+
5+ import androidx .annotation .Nullable ;
46import androidx .annotation .VisibleForTesting ;
57
68import org .json .JSONException ;
@@ -19,6 +21,7 @@ public class IterableAuthManager implements IterableActivityMonitor.AppStateCall
1921 private final IterableApi api ;
2022 private final IterableAuthHandler authHandler ;
2123 private final long expiringAuthTokenRefreshPeriod ;
24+ private final IterableActivityMonitor activityMonitor ;
2225 @ VisibleForTesting
2326 Timer timer ;
2427 private boolean hasFailedPriorAuth ;
@@ -28,7 +31,8 @@ public class IterableAuthManager implements IterableActivityMonitor.AppStateCall
2831 boolean pauseAuthRetry ;
2932 int retryCount ;
3033 private boolean isLastAuthTokenValid ;
31- private boolean isTimerScheduled ;
34+ private volatile boolean isTimerScheduled ;
35+ private volatile boolean isInForeground = true ; // Assume foreground initially
3236
3337 private final ExecutorService executor = Executors .newSingleThreadExecutor ();
3438
@@ -37,7 +41,8 @@ public class IterableAuthManager implements IterableActivityMonitor.AppStateCall
3741 this .authHandler = authHandler ;
3842 this .authRetryPolicy = authRetryPolicy ;
3943 this .expiringAuthTokenRefreshPeriod = expiringAuthTokenRefreshPeriod ;
40- IterableActivityMonitor .getInstance ().addCallback (this );
44+ this .activityMonitor = IterableActivityMonitor .getInstance ();
45+ this .activityMonitor .addCallback (this );
4146 }
4247
4348 public synchronized void requestNewAuthToken (boolean hasFailedPriorAuth ) {
@@ -52,7 +57,6 @@ public void pauseAuthRetries(boolean pauseRetry) {
5257 void reset () {
5358 clearRefreshTimer ();
5459 setIsLastAuthTokenValid (false );
55- IterableActivityMonitor .getInstance ().removeCallback (this );
5660 }
5761
5862 void setIsLastAuthTokenValid (boolean isValid ) {
@@ -97,6 +101,14 @@ public void run() {
97101 pendingAuth = false ;
98102 return ;
99103 }
104+
105+ // Only request new auth token if app is in foreground
106+ if (!isInForeground ) {
107+ IterableLogger .w (TAG , "Auth token request skipped - app is in background" );
108+ pendingAuth = false ;
109+ return ;
110+ }
111+
100112 final String authToken = authHandler .onAuthTokenRequested ();
101113 pendingAuth = false ;
102114 retryCount ++;
@@ -143,15 +155,23 @@ private void handleAuthTokenFailure(Throwable throwable) {
143155 scheduleAuthTokenRefresh (getNextRetryInterval (), false , null );
144156 }
145157
146- public void queueExpirationRefresh (String encodedJWT ) {
158+ public void queueExpirationRefresh (@ Nullable String encodedJWT ) {
147159 clearRefreshTimer ();
148160 try {
161+ if (encodedJWT == null ) {
162+ IterableLogger .d (TAG , "JWT is null. Scheduling token refresh" );
163+ if (!isTimerScheduled ) {
164+ scheduleAuthTokenRefresh (getNextRetryInterval (), false , null );
165+ }
166+ return ;
167+ }
168+
149169 long expirationTimeSeconds = decodedExpiration (encodedJWT );
150170 long triggerExpirationRefreshTime = expirationTimeSeconds * 1000L - expiringAuthTokenRefreshPeriod - IterableUtil .currentTimeMillis ();
151171 if (triggerExpirationRefreshTime > 0 ) {
152172 scheduleAuthTokenRefresh (triggerExpirationRefreshTime , true , null );
153173 } else {
154- IterableLogger . w ( TAG , "The expiringAuthTokenRefreshPeriod has already passed for the current JWT" );
174+ scheduleAuthTokenRefresh ( getNextRetryInterval (), true , null );
155175 }
156176 } catch (Exception e ) {
157177 IterableLogger .e (TAG , "Error while parsing JWT for the expiration" , e );
@@ -246,6 +266,20 @@ private static String getJson(String strEncoded) throws UnsupportedEncodingExcep
246266 return new String (decodedBytes , "UTF-8" );
247267 }
248268
269+ /**
270+ * Checks if the current auth token needs to be refreshed and handles any deferred auth requests.
271+ * This method is called when the app comes to foreground to ensure timely token refresh.
272+ */
273+ private void checkAndHandleAuthRefresh () {
274+ // First, check if current auth token needs refresh based on expiration
275+ if (api .getEmail () != null || api .getUserId () != null ) {
276+ String currentAuthToken = api .getAuthToken ();
277+ queueExpirationRefresh (currentAuthToken );
278+ } else {
279+ IterableLogger .d (TAG , "Email or userId is not available. Skipping token refresh" );
280+ }
281+ }
282+
249283 void clearRefreshTimer () {
250284 if (timer != null ) {
251285 timer .cancel ();
@@ -255,35 +289,24 @@ void clearRefreshTimer() {
255289 }
256290
257291 @ Override
258- public void onSwitchToBackground () {
292+ public void onSwitchToForeground () {
259293 try {
260- IterableLogger .v (TAG , "App switched to background. Clearing auth refresh timer." );
261- clearRefreshTimer ();
294+ IterableLogger .d (TAG , "App switched to foreground - enabling auth token requests" );
295+ isInForeground = true ;
296+ checkAndHandleAuthRefresh ();
262297 } catch (Exception e ) {
263- IterableLogger .e (TAG , "Error in onSwitchToBackground " , e );
298+ IterableLogger .e (TAG , "Error occurred in handling auth token refresh " , e );
264299 }
265300 }
266301
267302 @ Override
268- public void onSwitchToForeground () {
269- if (pendingAuth ) return ;
303+ public void onSwitchToBackground () {
270304 try {
271- IterableLogger .v (TAG , "App switched to foreground. Re-evaluating auth token refresh." );
272- String authToken = api .getAuthToken ();
273-
274- if (authToken != null ) {
275- queueExpirationRefresh (authToken );
276- // If queueExpirationRefresh didn't schedule a timer (expired token case), request new token
277- if (!isTimerScheduled && !pendingAuth ) {
278- IterableLogger .d (TAG , "Token expired, requesting new token on foreground" );
279- requestNewAuthToken (false , null , true );
280- }
281- } else if ((api .getEmail () != null || api .getUserId () != null ) && !pendingAuth ) {
282- IterableLogger .d (TAG , "App foregrounded, user identified, no auth token present. Requesting new token." );
283- requestNewAuthToken (false , null , true );
284- }
305+ IterableLogger .d (TAG , "App switched to background - disabling auth token requests" );
306+ isInForeground = false ;
307+ clearRefreshTimer ();
285308 } catch (Exception e ) {
286- IterableLogger .e (TAG , "Error in onSwitchToForeground " , e );
309+ IterableLogger .e (TAG , "Error while switching to background " , e );
287310 }
288311 }
289312}
0 commit comments