diff --git a/firebase-installations/api.txt b/firebase-installations/api.txt index 1b73247dcfa..370cd50d1b5 100644 --- a/firebase-installations/api.txt +++ b/firebase-installations/api.txt @@ -33,6 +33,7 @@ package com.google.firebase.installations.local { } public enum PersistedFid.RegistrationStatus { + enum_constant public static final com.google.firebase.installations.local.PersistedFid.RegistrationStatus NOT_GENERATED; enum_constant public static final com.google.firebase.installations.local.PersistedFid.RegistrationStatus PENDING; enum_constant public static final com.google.firebase.installations.local.PersistedFid.RegistrationStatus REGISTERED; enum_constant public static final com.google.firebase.installations.local.PersistedFid.RegistrationStatus REGISTER_ERROR; @@ -44,10 +45,14 @@ package com.google.firebase.installations.local { method @NonNull public static com.google.firebase.installations.local.PersistedFidEntry.Builder builder(); method @Nullable public abstract String getAuthToken(); method public abstract long getExpiresInSecs(); - method @NonNull public abstract String getFirebaseInstallationId(); + method @Nullable public abstract String getFirebaseInstallationId(); method @Nullable public abstract String getRefreshToken(); method @NonNull public abstract com.google.firebase.installations.local.PersistedFid.RegistrationStatus getRegistrationStatus(); method public abstract long getTokenCreationEpochInSecs(); + method public boolean isErrored(); + method public boolean isNotGenerated(); + method public boolean isRegistered(); + method public boolean isUnregistered(); method @NonNull public abstract com.google.firebase.installations.local.PersistedFidEntry.Builder toBuilder(); } diff --git a/firebase-installations/src/androidTest/java/com/google/firebase/installations/FirebaseInstallationsInstrumentedTest.java b/firebase-installations/src/androidTest/java/com/google/firebase/installations/FirebaseInstallationsInstrumentedTest.java index f28b63517a4..f434b85a48f 100644 --- a/firebase-installations/src/androidTest/java/com/google/firebase/installations/FirebaseInstallationsInstrumentedTest.java +++ b/firebase-installations/src/androidTest/java/com/google/firebase/installations/FirebaseInstallationsInstrumentedTest.java @@ -15,6 +15,7 @@ package com.google.firebase.installations; import static com.google.common.truth.Truth.assertWithMessage; +import static com.google.firebase.installations.FisAndroidTestConstants.DEFAULT_PERSISTED_FID_ENTRY; import static com.google.firebase.installations.FisAndroidTestConstants.TEST_API_KEY; import static com.google.firebase.installations.FisAndroidTestConstants.TEST_APP_ID_1; import static com.google.firebase.installations.FisAndroidTestConstants.TEST_AUTH_TOKEN; @@ -89,7 +90,7 @@ public class FirebaseInstallationsInstrumentedTest { .setFirebaseInstallationId(TEST_FID_1) .setAuthToken(TEST_AUTH_TOKEN) .setRefreshToken(TEST_REFRESH_TOKEN) - .setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_2) + .setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_1) .setExpiresInSecs(TEST_TOKEN_EXPIRATION_TIMESTAMP) .setRegistrationStatus(PersistedFid.RegistrationStatus.REGISTERED) .build(); @@ -99,7 +100,7 @@ public class FirebaseInstallationsInstrumentedTest { .setFirebaseInstallationId(TEST_FID_1) .setAuthToken(TEST_AUTH_TOKEN) .setRefreshToken(TEST_REFRESH_TOKEN) - .setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_2) + .setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_1) .setExpiresInSecs(TEST_TOKEN_EXPIRATION_TIMESTAMP_2) .setRegistrationStatus(PersistedFid.RegistrationStatus.REGISTERED) .build(); @@ -109,7 +110,7 @@ public class FirebaseInstallationsInstrumentedTest { .setFirebaseInstallationId(TEST_FID_1) .setAuthToken("") .setRefreshToken("") - .setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_2) + .setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_1) .setExpiresInSecs(0) .setRegistrationStatus(PersistedFid.RegistrationStatus.UNREGISTERED) .build(); @@ -163,7 +164,8 @@ public void setUp() throws FirebaseInstallationServiceException { new FirebaseInstallationServiceException( "SDK Error", FirebaseInstallationServiceException.Status.SERVER_ERROR)); when(persistedFidReturnsError.insertOrUpdatePersistedFidEntry(any())).thenReturn(false); - when(persistedFidReturnsError.readPersistedFidEntryValue()).thenReturn(null); + when(persistedFidReturnsError.readPersistedFidEntryValue()) + .thenReturn(DEFAULT_PERSISTED_FID_ENTRY); when(mockUtils.createRandomFid()).thenReturn(TEST_FID_1); when(mockClock.currentTimeMillis()).thenReturn(TEST_CREATION_TIMESTAMP_1); // Mocks success on FIS deletion @@ -190,7 +192,7 @@ public void testGetId_PersistedFidOk_BackendOk() throws Exception { mockClock, executor, firebaseApp, backendClientReturnsOk, persistedFid, mockUtils); // No exception, means success. - assertWithMessage("getId Task fails.") + assertWithMessage("getId Task failed") .that(Tasks.await(firebaseInstallations.getId())) .isNotEmpty(); PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue(); @@ -217,7 +219,7 @@ public void testGetId_multipleCalls_sameFIDReturned() throws Exception { mockClock, executor, firebaseApp, backendClientReturnsOk, persistedFid, mockUtils); // No exception, means success. - assertWithMessage("getId Task fails.") + assertWithMessage("getId Task failed") .that(Tasks.await(firebaseInstallations.getId())) .isNotEmpty(); PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue(); @@ -290,6 +292,36 @@ public void testGetId_PersistedFidError_BackendOk() throws InterruptedException } } + @Test + public void testGetId_expiredAuthToken_refreshesAuthToken() throws Exception { + // Update local storage with fid entry that has auth token expired. + persistedFid.insertOrUpdatePersistedFidEntry(EXPIRED_AUTH_TOKEN_ENTRY); + FirebaseInstallations firebaseInstallations = + new FirebaseInstallations( + mockClock, executor, firebaseApp, backendClientReturnsOk, persistedFid, mockUtils); + + assertWithMessage("getId Task failed") + .that(Tasks.await(firebaseInstallations.getId())) + .isNotEmpty(); + PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue(); + assertWithMessage("Persisted Fid doesn't match") + .that(entryValue.getFirebaseInstallationId()) + .isEqualTo(TEST_FID_1); + + // Waiting for Task that generates auth token with the FIS Servers + executor.awaitTermination(500, TimeUnit.MILLISECONDS); + + // Validate that registration is complete with updated auth token + PersistedFidEntry updatedFidEntry = persistedFid.readPersistedFidEntryValue(); + assertWithMessage("Persisted Fid doesn't match") + .that(updatedFidEntry) + .isEqualTo(UPDATED_AUTH_TOKEN_FID_ENTRY); + verify(backendClientReturnsOk, never()) + .createFirebaseInstallation(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_APP_ID_1); + verify(backendClientReturnsOk, times(1)) + .generateAuthToken(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_REFRESH_TOKEN); + } + @Test public void testGetAuthToken_fidDoesNotExist_successful() throws Exception { FirebaseInstallations firebaseInstallations = @@ -418,18 +450,13 @@ public void testGetAuthToken_serverError_failure() throws Exception { @Test public void testGetAuthToken_multipleCallsDoNotForceRefresh_fetchedNewTokenOnce() throws Exception { - // Using mockPersistedFid to ensure the order of returning persistedFidEntry to 2 tasks - // triggered simultaneously. Task2 waits for Task1 to complete. On Task1 completion, task2 reads - // the UPDATED_AUTH_TOKEN_FID_ENTRY by Task1 on execution. - when(mockPersistedFid.readPersistedFidEntryValue()) - .thenReturn( - EXPIRED_AUTH_TOKEN_ENTRY, - EXPIRED_AUTH_TOKEN_ENTRY, - EXPIRED_AUTH_TOKEN_ENTRY, - UPDATED_AUTH_TOKEN_FID_ENTRY); + // Update local storage with fid entry that has auth token expired. When 2 tasks are triggered + // simultaneously, Task2 waits for Task1 to complete. On Task1 completion, task2 reads the + // UPDATED_AUTH_TOKEN_FID_ENTRY by Task1 on execution. + persistedFid.insertOrUpdatePersistedFidEntry(EXPIRED_AUTH_TOKEN_ENTRY); FirebaseInstallations firebaseInstallations = new FirebaseInstallations( - mockClock, executor, firebaseApp, backendClientReturnsOk, mockPersistedFid, mockUtils); + mockClock, executor, firebaseApp, backendClientReturnsOk, persistedFid, mockUtils); // Call getAuthToken multiple times with DO_NOT_FORCE_REFRESH option Task task1 = @@ -508,7 +535,9 @@ public void testDelete_registeredFID_successful() throws Exception { Tasks.await(firebaseInstallations.delete()); PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue(); - assertWithMessage("Persisted Fid Entry is not null.").that(entryValue).isNull(); + assertWithMessage("Persisted Fid Entry is not null.") + .that(entryValue) + .isEqualTo(DEFAULT_PERSISTED_FID_ENTRY); verify(backendClientReturnsOk, times(1)) .deleteFirebaseInstallation(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_REFRESH_TOKEN); } @@ -524,7 +553,9 @@ public void testDelete_unregisteredFID_successful() throws Exception { Tasks.await(firebaseInstallations.delete()); PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue(); - assertWithMessage("Persisted Fid Entry is not null.").that(entryValue).isNull(); + assertWithMessage("Persisted Fid Entry is not null.") + .that(entryValue) + .isEqualTo(DEFAULT_PERSISTED_FID_ENTRY); verify(backendClientReturnsOk, never()) .deleteFirebaseInstallation(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_REFRESH_TOKEN); } @@ -538,7 +569,9 @@ public void testDelete_emptyPersistedFidEntry_successful() throws Exception { Tasks.await(firebaseInstallations.delete()); PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue(); - assertWithMessage("Persisted Fid Entry is not null.").that(entryValue).isNull(); + assertWithMessage("Persisted Fid Entry is not null.") + .that(entryValue) + .isEqualTo(DEFAULT_PERSISTED_FID_ENTRY); verify(backendClientReturnsOk, never()) .deleteFirebaseInstallation(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_REFRESH_TOKEN); } diff --git a/firebase-installations/src/androidTest/java/com/google/firebase/installations/FisAndroidTestConstants.java b/firebase-installations/src/androidTest/java/com/google/firebase/installations/FisAndroidTestConstants.java index e77a2b1155b..f1d39cfa396 100644 --- a/firebase-installations/src/androidTest/java/com/google/firebase/installations/FisAndroidTestConstants.java +++ b/firebase-installations/src/androidTest/java/com/google/firebase/installations/FisAndroidTestConstants.java @@ -14,6 +14,8 @@ package com.google.firebase.installations; +import com.google.firebase.installations.local.PersistedFidEntry; + public final class FisAndroidTestConstants { public static final String TEST_FID_1 = "cccccccccccccccccccccc"; @@ -35,5 +37,8 @@ public final class FisAndroidTestConstants { public static final long TEST_TOKEN_EXPIRATION_TIMESTAMP_2 = 2000L; public static final long TEST_CREATION_TIMESTAMP_1 = 2000L; - public static final long TEST_CREATION_TIMESTAMP_2 = 2000L; + public static final long TEST_CREATION_TIMESTAMP_2 = 2L; + + public static final PersistedFidEntry DEFAULT_PERSISTED_FID_ENTRY = + PersistedFidEntry.builder().build(); } diff --git a/firebase-installations/src/androidTest/java/com/google/firebase/installations/local/PersistedFidTest.java b/firebase-installations/src/androidTest/java/com/google/firebase/installations/local/PersistedFidTest.java index f6aa77f45de..14b416ad71f 100644 --- a/firebase-installations/src/androidTest/java/com/google/firebase/installations/local/PersistedFidTest.java +++ b/firebase-installations/src/androidTest/java/com/google/firebase/installations/local/PersistedFidTest.java @@ -14,6 +14,7 @@ package com.google.firebase.installations.local; +import static com.google.firebase.installations.FisAndroidTestConstants.DEFAULT_PERSISTED_FID_ENTRY; import static com.google.firebase.installations.FisAndroidTestConstants.TEST_APP_ID_1; import static com.google.firebase.installations.FisAndroidTestConstants.TEST_APP_ID_2; import static com.google.firebase.installations.FisAndroidTestConstants.TEST_AUTH_TOKEN; @@ -23,7 +24,6 @@ import static com.google.firebase.installations.FisAndroidTestConstants.TEST_REFRESH_TOKEN; import static com.google.firebase.installations.FisAndroidTestConstants.TEST_TOKEN_EXPIRATION_TIMESTAMP; import static com.google.firebase.installations.local.PersistedFidEntrySubject.assertThat; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import androidx.test.core.app.ApplicationProvider; @@ -68,9 +68,9 @@ public void cleanUp() throws Exception { } @Test - public void testReadPersistedFidEntry_Null() { - assertNull(persistedFid0.readPersistedFidEntryValue()); - assertNull(persistedFid1.readPersistedFidEntryValue()); + public void testReadPersistedFidEntry_returnsDefault() { + assertThat(persistedFid0.readPersistedFidEntryValue()).isEqualTo(DEFAULT_PERSISTED_FID_ENTRY); + assertThat(persistedFid1.readPersistedFidEntryValue()).isEqualTo(DEFAULT_PERSISTED_FID_ENTRY); } @Test diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java index b2390ec8f06..436e3626c6e 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java @@ -123,8 +123,7 @@ public Task getId() { private Task getId(AwaitListener awaitListener) { return Tasks.call(executor, this::getPersistedFid) .continueWith(orElse(this::createAndPersistNewFid)) - .onSuccessTask( - persistedFidEntry -> registerFidIfNecessary(persistedFidEntry, awaitListener)); + .onSuccessTask(unused -> registerFidIfNecessary(awaitListener)); } /** @@ -179,18 +178,14 @@ String getName() { */ private PersistedFidEntry getPersistedFid() throws FirebaseInstallationsException { PersistedFidEntry persistedFidEntry = persistedFid.readPersistedFidEntryValue(); - if (persistedFidMissingOrInErrorState(persistedFidEntry)) { + + if (persistedFidEntry.isNotGenerated() || persistedFidEntry.isErrored()) { throw new FirebaseInstallationsException( "Failed to get existing fid.", FirebaseInstallationsException.Status.CLIENT_ERROR); } return persistedFidEntry; } - private static boolean persistedFidMissingOrInErrorState(PersistedFidEntry persistedFidEntry) { - return persistedFidEntry == null - || persistedFidEntry.getRegistrationStatus() == RegistrationStatus.REGISTER_ERROR; - } - @NonNull private static Continuation orElse(@NonNull Supplier supplier) { return t -> { @@ -235,50 +230,74 @@ private void persistFid(String fid) throws FirebaseInstallationsException { } /** - * Registers the FID with FIS servers if FID is in UNREGISTERED state. + * Registers the FID with FIS servers if FID is in UNREGISTERED state. Also, refreshes auth token + * if expired. * *

Updates FID registration status to PENDING to avoid multiple network calls to FIS Servers. */ - private Task registerFidIfNecessary( - PersistedFidEntry persistedFidEntry, AwaitListener listener) { - String fid = persistedFidEntry.getFirebaseInstallationId(); - - // Check if the fid is unregistered - if (persistedFidEntry.getRegistrationStatus() == RegistrationStatus.UNREGISTERED) { - updatePersistedFidWithPendingStatus(fid); - executeFidRegistration(persistedFidEntry, listener); - } else { - updateAwaitListenerIfRegisteredFid(persistedFidEntry, listener); + private Task registerFidIfNecessary(AwaitListener listener) + throws FirebaseInstallationsException { + boolean isNetworkCallRequired = false; + + synchronized (persistedFid) { + PersistedFidEntry persistedFidEntry = persistedFid.readPersistedFidEntryValue(); + + if (persistedFidEntry.isNotGenerated()) { + throw new FirebaseInstallationsException( + "Local storage has no persisted Fid entry.", + FirebaseInstallationsException.Status.CLIENT_ERROR); + } + + // If FID registration status is REGISTERED and auth token is expired, or registration status + // is UNREGISTERED network call is required. + if ((persistedFidEntry.isRegistered() && isAuthTokenExpired(persistedFidEntry)) + || persistedFidEntry.isUnregistered()) { + isNetworkCallRequired = true; + + // Update FID registration status to PENDING to avoid multiple network calls to FIS Servers. + persistedFid.insertOrUpdatePersistedFidEntry( + persistedFidEntry + .toBuilder() + .setRegistrationStatus(RegistrationStatus.PENDING) + .build()); + } } - return Tasks.forResult(fid); - } + PersistedFidEntry updatedPersistedFidEntry = persistedFid.readPersistedFidEntryValue(); + String fid = updatedPersistedFidEntry.getFirebaseInstallationId(); - private void updateAwaitListenerIfRegisteredFid( - PersistedFidEntry persistedFidEntry, AwaitListener listener) { - if (listener != null - && persistedFidEntry.getRegistrationStatus() == RegistrationStatus.REGISTERED) { - listener.onSuccess(); + if (!isNetworkCallRequired) { + + // If the Fid is registered, update the listener if awaiting + if (listener != null && updatedPersistedFidEntry.isRegistered()) { + listener.onSuccess(); + } + return Tasks.forResult(fid); } - } - /** - * Registers the FID with FIS servers in a background thread and updates the listener on - * completion. - */ - private void executeFidRegistration(PersistedFidEntry persistedFidEntry, AwaitListener listener) { - Task task = Tasks.call(executor, () -> registerAndSaveFid(persistedFidEntry)); - if (listener != null) { - task.addOnCompleteListener(listener); + // If fid registration for this firebase installation is incomplete without an expired auth + // token, execute Fid registration. + if (!isAuthTokenExpired(updatedPersistedFidEntry)) { + Task fidRegistrationTask = + Tasks.call(executor, () -> registerAndSaveFid(updatedPersistedFidEntry)); + + // Update the listener if awaiting + if (listener != null) { + fidRegistrationTask.addOnCompleteListener(listener); + } + return Tasks.forResult(fid); } - } - private void updatePersistedFidWithPendingStatus(String fid) { - persistedFid.insertOrUpdatePersistedFidEntry( - PersistedFidEntry.builder() - .setFirebaseInstallationId(fid) - .setRegistrationStatus(RegistrationStatus.PENDING) - .build()); + // If auth token is expired, refresh FID auth token with FIS servers in a background thread + // and updates the listener on completion + Task refreshAuthTokenTask = + Tasks.call(executor, () -> refreshAuthTokenIfNecessary(FORCE_REFRESH)); + + // Update the listener if awaiting + if (listener != null) { + refreshAuthTokenTask.addOnSuccessListener((unused) -> listener.onSuccess()); + } + return Tasks.forResult(fid); } /** Registers the created Fid with FIS servers and update the shared prefs. */ @@ -320,7 +339,9 @@ private InstallationTokenResult refreshAuthTokenIfNecessary(int authTokenOption) PersistedFidEntry persistedFidEntry = persistedFid.readPersistedFidEntryValue(); - if (!isPersistedFidRegistered(persistedFidEntry)) { + if (persistedFidEntry.isNotGenerated() + || persistedFidEntry.isUnregistered() + || persistedFidEntry.isErrored()) { throw new FirebaseInstallationsException( "Firebase Installation is not registered.", FirebaseInstallationsException.Status.SDK_INTERNAL_ERROR); @@ -353,11 +374,6 @@ private InstallationTokenResult getValidAuthToken(PersistedFidEntry persistedFid .build(); } - private boolean isPersistedFidRegistered(PersistedFidEntry persistedFidEntry) { - return persistedFidEntry != null - && persistedFidEntry.getRegistrationStatus() == RegistrationStatus.REGISTERED; - } - /** Calls the FIS servers to generate an auth token for this Firebase installation. */ private InstallationTokenResult fetchAuthTokenFromServer(PersistedFidEntry persistedFidEntry) throws FirebaseInstallationsException { @@ -409,7 +425,7 @@ private Void deleteFirebaseInstallationId() throws FirebaseInstallationsExceptio PersistedFidEntry persistedFidEntry = persistedFid.readPersistedFidEntryValue(); - if (isPersistedFidRegistered(persistedFidEntry)) { + if (persistedFidEntry.isRegistered()) { // Call the FIS servers to delete this firebase installation id. try { serviceClient.deleteFirebaseInstallation( diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/local/PersistedFid.java b/firebase-installations/src/main/java/com/google/firebase/installations/local/PersistedFid.java index 1da104fa350..d73219cd091 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/local/PersistedFid.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/local/PersistedFid.java @@ -31,6 +31,8 @@ public class PersistedFid { // NOTE: never change the ordinal of the enum values because the enum values are stored in shared // prefs as their ordinal numbers. public enum RegistrationStatus { + /** {@link PersistedFidEntry} default registration status */ + NOT_GENERATED, /** {@link PersistedFidEntry} is synced to FIS servers */ REGISTERED, /** {@link PersistedFidEntry} is not synced with FIS server */ @@ -75,17 +77,15 @@ public PersistedFid(@NonNull FirebaseApp firebaseApp) { @Nullable public PersistedFidEntry readPersistedFidEntryValue() { String fid = prefs.getString(getSharedPreferencesKey(FIREBASE_INSTALLATION_ID_KEY), null); - int status = prefs.getInt(getSharedPreferencesKey(PERSISTED_STATUS_KEY), -1); + int status = prefs.getInt(getSharedPreferencesKey(PERSISTED_STATUS_KEY), 0); String authToken = prefs.getString(getSharedPreferencesKey(AUTH_TOKEN_KEY), null); String refreshToken = prefs.getString(getSharedPreferencesKey(REFRESH_TOKEN_KEY), null); long tokenCreationTime = prefs.getLong(getSharedPreferencesKey(TOKEN_CREATION_TIME_IN_SECONDS_KEY), 0); long expiresIn = prefs.getLong(getSharedPreferencesKey(EXPIRES_IN_SECONDS_KEY), 0); - if (fid == null - || status == -1 - || !(status >= 0 && status < RegistrationStatus.values().length)) { - return null; + if (fid == null || !(status >= 0 && status < RegistrationStatus.values().length)) { + return PersistedFidEntry.builder().build(); } return PersistedFidEntry.builder() diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/local/PersistedFidEntry.java b/firebase-installations/src/main/java/com/google/firebase/installations/local/PersistedFidEntry.java index 4c8a9a56ec4..4019967cdb6 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/local/PersistedFidEntry.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/local/PersistedFidEntry.java @@ -25,7 +25,7 @@ @AutoValue public abstract class PersistedFidEntry { - @NonNull + @Nullable public abstract String getFirebaseInstallationId(); @NonNull @@ -41,6 +41,22 @@ public abstract class PersistedFidEntry { public abstract long getTokenCreationEpochInSecs(); + public boolean isRegistered() { + return getRegistrationStatus() == PersistedFid.RegistrationStatus.REGISTERED; + } + + public boolean isErrored() { + return getRegistrationStatus() == PersistedFid.RegistrationStatus.REGISTER_ERROR; + } + + public boolean isUnregistered() { + return getRegistrationStatus() == PersistedFid.RegistrationStatus.UNREGISTERED; + } + + public boolean isNotGenerated() { + return getRegistrationStatus() == PersistedFid.RegistrationStatus.NOT_GENERATED; + } + @NonNull public abstract Builder toBuilder(); @@ -49,6 +65,7 @@ public abstract class PersistedFidEntry { public static PersistedFidEntry.Builder builder() { return new AutoValue_PersistedFidEntry.Builder() .setTokenCreationEpochInSecs(0) + .setRegistrationStatus(PersistedFid.RegistrationStatus.NOT_GENERATED) .setExpiresInSecs(0); }