1919import android .util .Log ;
2020import androidx .annotation .GuardedBy ;
2121import androidx .annotation .VisibleForTesting ;
22+ import com .google .android .gms .common .util .Clock ;
23+ import com .google .android .gms .common .util .DefaultClock ;
2224import com .google .android .gms .tasks .Task ;
2325import com .google .android .gms .tasks .Tasks ;
2426import com .google .firebase .remoteconfig .ConfigUpdate ;
3133import java .io .InputStream ;
3234import java .io .InputStreamReader ;
3335import java .net .HttpURLConnection ;
36+ import java .util .Date ;
3437import java .util .Random ;
3538import java .util .Set ;
3639import java .util .concurrent .ScheduledExecutorService ;
@@ -43,6 +46,7 @@ public class ConfigAutoFetch {
4346 private static final int MAXIMUM_FETCH_ATTEMPTS = 3 ;
4447 private static final String TEMPLATE_VERSION_KEY = "latestTemplateVersionNumber" ;
4548 private static final String REALTIME_DISABLED_KEY = "featureDisabled" ;
49+ private static final String REALTIME_RETRY_INTERVAL = "retryIntervalSeconds" ;
4650
4751 @ GuardedBy ("this" )
4852 private final Set <ConfigUpdateListener > eventListeners ;
@@ -54,6 +58,8 @@ public class ConfigAutoFetch {
5458 private final ConfigUpdateListener retryCallback ;
5559 private final ScheduledExecutorService scheduledExecutorService ;
5660 private final Random random ;
61+ private final Clock clock ;
62+ private final ConfigSharedPrefsClient sharedPrefsClient ;
5763 private boolean isInBackground ;
5864
5965 public ConfigAutoFetch (
@@ -62,7 +68,8 @@ public ConfigAutoFetch(
6268 ConfigCacheClient activatedCache ,
6369 Set <ConfigUpdateListener > eventListeners ,
6470 ConfigUpdateListener retryCallback ,
65- ScheduledExecutorService scheduledExecutorService ) {
71+ ScheduledExecutorService scheduledExecutorService ,
72+ ConfigSharedPrefsClient sharedPrefsClient ) {
6673 this .httpURLConnection = httpURLConnection ;
6774 this .configFetchHandler = configFetchHandler ;
6875 this .activatedCache = activatedCache ;
@@ -71,6 +78,19 @@ public ConfigAutoFetch(
7178 this .scheduledExecutorService = scheduledExecutorService ;
7279 this .random = new Random ();
7380 this .isInBackground = false ;
81+ this .sharedPrefsClient = sharedPrefsClient ;
82+ this .clock = DefaultClock .getInstance ();
83+ }
84+
85+ // Increase the backoff duration with a new end time based on Retry Interval
86+ private synchronized void updateBackoffMetadataWithRetryInterval (
87+ int realtimeRetryIntervalInSeconds ) {
88+ Date currentTime = new Date (clock .currentTimeMillis ());
89+ long backoffDurationInMillis = realtimeRetryIntervalInSeconds * 1000L ;
90+ Date backoffEndTime = new Date (currentTime .getTime () + backoffDurationInMillis );
91+
92+ // Persist the new values to disk-backed metadata.
93+ sharedPrefsClient .setRealtimeBackoffEndTime (backoffEndTime );
7494 }
7595
7696 private synchronized void propagateErrors (FirebaseRemoteConfigException exception ) {
@@ -190,6 +210,15 @@ private void handleNotifications(InputStream inputStream) throws IOException {
190210 autoFetch (MAXIMUM_FETCH_ATTEMPTS , targetTemplateVersion );
191211 }
192212 }
213+
214+ // This field in the response indicates that the realtime request should retry after the
215+ // specified interval to establish a long-lived connection. This interval extends the
216+ // backoff duration without affecting the number of retries, so it will not enter an
217+ // exponential backoff state.
218+ if (jsonObject .has (REALTIME_RETRY_INTERVAL )) {
219+ int realtimeRetryIntervalInSeconds = jsonObject .getInt (REALTIME_RETRY_INTERVAL );
220+ updateBackoffMetadataWithRetryInterval (realtimeRetryIntervalInSeconds );
221+ }
193222 } catch (JSONException ex ) {
194223 // Message was mangled up and so it was unable to be parsed. User is notified of this
195224 // because it there could be a new configuration that needs to be fetched.
0 commit comments