From 7e7750326e56bee68ffac8a83e17597f595b1a1f Mon Sep 17 00:00:00 2001 From: eldhosembabu Date: Wed, 20 May 2026 12:41:44 -0700 Subject: [PATCH 1/4] Fixing fidchangelistener behavior to get invoked for new fid creations as well --- .../installations/FirebaseInstallations.java | 19 +++--- .../FirebaseInstallationsTest.java | 59 +++++++++++++++++++ 2 files changed, 71 insertions(+), 7 deletions(-) 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 d0edf5240bc..346196b3ef3 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 @@ -392,9 +392,11 @@ private void doNetworkCallIfNecessary(boolean forceRefresh) { // be registered with the server or the FID is registered but we need a fresh authtoken. // Registering will also result in a fresh authtoken. Do the appropriate step here. PersistedInstallationEntry updatedPrefs; + boolean isNewFID = false; try { if (prefs.isErrored() || prefs.isUnregistered()) { updatedPrefs = registerFidWithServer(prefs); + isNewFID = true; } else if (forceRefresh || utils.isAuthTokenExpired(prefs)) { updatedPrefs = fetchAuthTokenFromServer(prefs); } else { @@ -409,8 +411,12 @@ private void doNetworkCallIfNecessary(boolean forceRefresh) { // Store the prefs to persist the result of the previous step. insertOrUpdatePrefs(updatedPrefs); - // Update FidListener if a fid has changed. - updateFidListener(prefs, updatedPrefs); + // Update FidListener if a fid is new or has changed. + if (isNewFID + || !TextUtils.equals( + prefs.getFirebaseInstallationId(), updatedPrefs.getFirebaseInstallationId())) { + updateFidListener(updatedPrefs); + } prefs = updatedPrefs; @@ -431,11 +437,10 @@ private void doNetworkCallIfNecessary(boolean forceRefresh) { } } - private synchronized void updateFidListener( - PersistedInstallationEntry prefs, PersistedInstallationEntry updatedPrefs) { - if (fidListeners.size() != 0 - && !TextUtils.equals( - prefs.getFirebaseInstallationId(), updatedPrefs.getFirebaseInstallationId())) { + private synchronized void updateFidListener(@NonNull PersistedInstallationEntry updatedPrefs) { + if (!fidListeners.isEmpty() + && !TextUtils.isEmpty(updatedPrefs.getFirebaseInstallationId()) + && updatedPrefs.isRegistered()) { // Update all the registered FidListener about fid changes. for (FidListener listener : fidListeners) { listener.onFidChanged(updatedPrefs.getFirebaseInstallationId()); diff --git a/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java b/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java index e344c9459eb..8fd55f580aa 100644 --- a/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java +++ b/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java @@ -500,6 +500,65 @@ public void testFidListener_fidChanged_successful() throws Exception { assertNull(fidListener2.getLatestFid()); } + @Test + public void testFidListener_fidRegistered_sameFid_successful() throws Exception { + when(mockIidStore.readIid()).thenReturn(null); + when(mockIidStore.readToken()).thenReturn(null); + when(mockBackend.createFirebaseInstallation( + anyString(), anyString(), anyString(), anyString(), any())) + .thenReturn(TEST_INSTALLATION_RESPONSE); + + FakeFidListener fidListener = new FakeFidListener(); + + // Register the FidListener + firebaseInstallations.registerFidListener(fidListener); + + // Do the actual getId() call under test. + TestOnCompleteListener onCompleteListener = new TestOnCompleteListener<>(); + Task task = firebaseInstallations.getId(); + + task.addOnCompleteListener(backgroundExecutor, onCompleteListener); + String fid = onCompleteListener.await(); + assertWithMessage("getId Task failed.").that(fid).isEqualTo(TEST_FID_1); + + // Waiting for Task that registers FID on the FIS Servers + backgroundExecutor.awaitTermination(500, TimeUnit.MILLISECONDS); + PersistedInstallationEntry entry = persistedInstallation.readPersistedInstallationEntryValue(); + assertThat(entry.getFirebaseInstallationId()).isEqualTo(TEST_FID_1); + + // Verify FidListener receives fid registration notification. + assertThat(fidListener.getLatestFid()).isEqualTo(TEST_FID_1); + } + + @Test + public void testFidListener_alreadyRegistered_noFidChange_notNotified() throws Exception { + persistedInstallation.insertOrUpdatePersistedInstallationEntry( + PersistedInstallationEntry.INSTANCE.withRegisteredFid( + TEST_FID_1, + TEST_REFRESH_TOKEN, + utils.currentTimeInSecs(), + TEST_AUTH_TOKEN, + TEST_TOKEN_EXPIRATION_TIMESTAMP)); + + FakeFidListener fidListener = new FakeFidListener(); + + // Register the FidListener + firebaseInstallations.registerFidListener(fidListener); + + // Do the actual getId() call under test. + TestOnCompleteListener onCompleteListener = new TestOnCompleteListener<>(); + Task task = firebaseInstallations.getId(); + task.addOnCompleteListener(backgroundExecutor, onCompleteListener); + String fid = onCompleteListener.await(); + assertWithMessage("getId Task failed.").that(fid).isEqualTo(TEST_FID_1); + + backgroundExecutor.awaitTermination(500, TimeUnit.MILLISECONDS); + + // Verify FidListener does not receive any notification since the FID was already registered + // and didn't change. + assertNull(fidListener.getLatestFid()); + } + @Test public void testGetId_migrateIid_successful() throws Exception { when(mockIidStore.readIid()).thenReturn(TEST_INSTANCE_ID_1); From 5531bcd3309e69ebce51df8016613dea338a1ef3 Mon Sep 17 00:00:00 2001 From: eldhosembabu Date: Thu, 21 May 2026 12:16:35 -0700 Subject: [PATCH 2/4] updating CHANGELOG.md --- firebase-installations/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firebase-installations/CHANGELOG.md b/firebase-installations/CHANGELOG.md index 60e36bdf786..5735b11bd1e 100644 --- a/firebase-installations/CHANGELOG.md +++ b/firebase-installations/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- [fixed] FIDchangelistener not getting invoked when a FID is created. + # 19.1.0 - [fixed] Mitigated FIS ID duplication issue from backup data. (#7025) From ff28ce10e081eb8527ba7034363d1ff8f8da5313 Mon Sep 17 00:00:00 2001 From: eldhosembabu Date: Tue, 26 May 2026 14:54:34 -0700 Subject: [PATCH 3/4] Code review changes --- .../installations/FirebaseInstallations.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) 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 346196b3ef3..53c6b401714 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 @@ -392,11 +392,9 @@ private void doNetworkCallIfNecessary(boolean forceRefresh) { // be registered with the server or the FID is registered but we need a fresh authtoken. // Registering will also result in a fresh authtoken. Do the appropriate step here. PersistedInstallationEntry updatedPrefs; - boolean isNewFID = false; try { if (prefs.isErrored() || prefs.isUnregistered()) { updatedPrefs = registerFidWithServer(prefs); - isNewFID = true; } else if (forceRefresh || utils.isAuthTokenExpired(prefs)) { updatedPrefs = fetchAuthTokenFromServer(prefs); } else { @@ -412,9 +410,7 @@ private void doNetworkCallIfNecessary(boolean forceRefresh) { insertOrUpdatePrefs(updatedPrefs); // Update FidListener if a fid is new or has changed. - if (isNewFID - || !TextUtils.equals( - prefs.getFirebaseInstallationId(), updatedPrefs.getFirebaseInstallationId())) { + if (shouldNotifyFidListener(prefs, updatedPrefs)) { updateFidListener(updatedPrefs); } @@ -437,6 +433,21 @@ private void doNetworkCallIfNecessary(boolean forceRefresh) { } } + private boolean shouldNotifyFidListener( + PersistedInstallationEntry prefs, PersistedInstallationEntry updatedPrefs) { + if (updatedPrefs.isRegistered() + && !TextUtils.isEmpty(updatedPrefs.getFirebaseInstallationId())) { + if (!TextUtils.equals( + prefs.getFirebaseInstallationId(), updatedPrefs.getFirebaseInstallationId())) { + // Fid has changed + return true; + } + // A new FID is just registered/An errored FID got registered/re-registered. + return !prefs.isRegistered(); + } + return false; + } + private synchronized void updateFidListener(@NonNull PersistedInstallationEntry updatedPrefs) { if (!fidListeners.isEmpty() && !TextUtils.isEmpty(updatedPrefs.getFirebaseInstallationId()) From 5ff86930ab69fe86755bdebc7a1a74da15c8aa05 Mon Sep 17 00:00:00 2001 From: eldhosembabu Date: Fri, 29 May 2026 12:11:53 -0700 Subject: [PATCH 4/4] Code refactor --- .../installations/FirebaseInstallations.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) 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 53c6b401714..60a982d6891 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 @@ -409,10 +409,8 @@ private void doNetworkCallIfNecessary(boolean forceRefresh) { // Store the prefs to persist the result of the previous step. insertOrUpdatePrefs(updatedPrefs); - // Update FidListener if a fid is new or has changed. - if (shouldNotifyFidListener(prefs, updatedPrefs)) { - updateFidListener(updatedPrefs); - } + // Update FidListener if a fid is new or changed its registration to registered. + checkAndUpdateFidListeners(prefs, updatedPrefs); prefs = updatedPrefs; @@ -448,10 +446,9 @@ private boolean shouldNotifyFidListener( return false; } - private synchronized void updateFidListener(@NonNull PersistedInstallationEntry updatedPrefs) { - if (!fidListeners.isEmpty() - && !TextUtils.isEmpty(updatedPrefs.getFirebaseInstallationId()) - && updatedPrefs.isRegistered()) { + private synchronized void checkAndUpdateFidListeners( + PersistedInstallationEntry prefs, PersistedInstallationEntry updatedPrefs) { + if (!fidListeners.isEmpty() && shouldNotifyFidListener(prefs, updatedPrefs)) { // Update all the registered FidListener about fid changes. for (FidListener listener : fidListeners) { listener.onFidChanged(updatedPrefs.getFirebaseInstallationId());