5050import java .util .concurrent .ExecutionException ;
5151import java .util .concurrent .TimeUnit ;
5252import java .util .concurrent .TimeoutException ;
53+ import java .util .concurrent .CopyOnWriteArrayList ;
5354
5455import io .branch .indexing .BranchUniversalObject ;
5556import io .branch .interfaces .IBranchLoggingCallbacks ;
@@ -239,22 +240,18 @@ public class Branch {
239240 private static boolean isActivityLifeCycleCallbackRegistered_ = false ;
240241 private CustomTabsIntent customTabsIntentOverride ;
241242
242- /* Enumeration for defining session initialisation state. */
243- enum SESSION_STATE {
244- INITIALISED , INITIALISING , UNINITIALISED
245- }
246-
247-
248- enum INTENT_STATE {
249- PENDING ,
250- READY
251- }
243+ // Replace SESSION_STATE enum with SessionState
244+ // Legacy session state lock - kept for backward compatibility
245+ private final Object sessionStateLock = new Object ();
252246
253247 /* Holds the current intent state. Default is set to PENDING. */
254248 private INTENT_STATE intentState_ = INTENT_STATE .PENDING ;
255249
256250 /* Holds the current Session state. Default is set to UNINITIALISED. */
257251 SESSION_STATE initState_ = SESSION_STATE .UNINITIALISED ;
252+
253+ // New StateFlow-based session state manager
254+ private final BranchSessionStateManager sessionStateManager = BranchSessionStateManager .getInstance ();
258255
259256 /* */
260257 static boolean deferInitForPluginRuntime = false ;
@@ -626,6 +623,74 @@ static void shutDown() {
626623 public void resetUserSession () {
627624 setInitState (SESSION_STATE .UNINITIALISED );
628625 }
626+
627+ // ===== NEW STATEFLOW-BASED SESSION STATE API =====
628+
629+ /**
630+ * Add a listener to observe session state changes using the new StateFlow-based system.
631+ * This provides deterministic state observation for SDK clients.
632+ *
633+ * @param listener The listener to add
634+ */
635+ public void addSessionStateObserver (@ NonNull BranchSessionStateListener listener ) {
636+ sessionStateManager .addListener (listener , true );
637+ }
638+
639+ /**
640+ * Add a simple listener to observe session state changes.
641+ *
642+ * @param listener The simple listener to add
643+ */
644+ public void addSessionStateObserver (@ NonNull SimpleBranchSessionStateListener listener ) {
645+ sessionStateManager .addListener (listener , true );
646+ }
647+
648+ /**
649+ * Remove a session state observer.
650+ *
651+ * @param listener The listener to remove
652+ */
653+ public void removeSessionStateObserver (@ NonNull BranchSessionStateListener listener ) {
654+ sessionStateManager .removeListener (listener );
655+ }
656+
657+ /**
658+ * Get the current session state using the new StateFlow-based system.
659+ *
660+ * @return The current session state
661+ */
662+ @ NonNull
663+ public BranchSessionState getCurrentSessionState () {
664+ return sessionStateManager .getCurrentState ();
665+ }
666+
667+ /**
668+ * Check if the SDK can currently perform operations.
669+ *
670+ * @return true if operations can be performed, false otherwise
671+ */
672+ public boolean canPerformOperations () {
673+ return sessionStateManager .canPerformOperations ();
674+ }
675+
676+ /**
677+ * Check if there's an active session.
678+ *
679+ * @return true if there's an active session, false otherwise
680+ */
681+ public boolean hasActiveSession () {
682+ return sessionStateManager .hasActiveSession ();
683+ }
684+
685+ /**
686+ * Get the StateFlow for observing session state changes in Kotlin code.
687+ *
688+ * @return StateFlow of BranchSessionState
689+ */
690+ @ NonNull
691+ public kotlinx .coroutines .flow .StateFlow <BranchSessionState > getSessionStateFlow () {
692+ return sessionStateManager .getSessionState ();
693+ }
629694
630695 /**
631696 * Sets the max number of times to re-attempt a timed-out request to the Branch API, before
@@ -855,9 +920,8 @@ void clearPendingRequests() {
855920 * closed application event to the Branch API.</p>
856921 */
857922 private void executeClose () {
858- if (initState_ != SESSION_STATE .UNINITIALISED ) {
859- setInitState (SESSION_STATE .UNINITIALISED );
860- }
923+ // Reset session state via StateFlow system
924+ sessionStateManager .reset ();
861925 }
862926
863927 public static void registerPlugin (String name , String version ) {
@@ -1182,7 +1246,7 @@ public JSONObject getLatestReferringParams() {
11821246 public JSONObject getLatestReferringParamsSync () {
11831247 getLatestReferringParamsLatch = new CountDownLatch (1 );
11841248 try {
1185- if (initState_ != SESSION_STATE . INITIALISED ) {
1249+ if (sessionState != SessionState . INITIALIZED ) {
11861250 getLatestReferringParamsLatch .await (LATCH_WAIT_UNTIL , TimeUnit .MILLISECONDS );
11871251 }
11881252 } catch (InterruptedException e ) {
@@ -1402,7 +1466,22 @@ void setIntentState(INTENT_STATE intentState) {
14021466 }
14031467
14041468 void setInitState (SESSION_STATE initState ) {
1405- this .initState_ = initState ;
1469+ synchronized (sessionStateLock ) {
1470+ initState_ = initState ;
1471+ }
1472+
1473+ // Update the StateFlow-based session state manager
1474+ switch (initState ) {
1475+ case UNINITIALISED :
1476+ sessionStateManager .reset ();
1477+ break ;
1478+ case INITIALISING :
1479+ sessionStateManager .initialize ();
1480+ break ;
1481+ case INITIALISED :
1482+ sessionStateManager .initializeComplete ();
1483+ break ;
1484+ }
14061485 }
14071486
14081487 SESSION_STATE getInitState () {
@@ -1420,10 +1499,12 @@ public boolean isInstantDeepLinkPossible() {
14201499 private void initializeSession (ServerRequestInitSession initRequest , int delay ) {
14211500 BranchLogger .v ("initializeSession " + initRequest + " delay " + delay );
14221501 if ((prefHelper_ .getBranchKey () == null || prefHelper_ .getBranchKey ().equalsIgnoreCase (PrefHelper .NO_STRING_VALUE ))) {
1423- setInitState (SESSION_STATE .UNINITIALISED );
1502+ // Report key error using new StateFlow system
1503+ BranchError keyError = new BranchError ("Trouble initializing Branch." , BranchError .ERR_BRANCH_KEY_INVALID );
1504+ sessionStateManager .initializeFailed (keyError );
14241505 //Report Key error on callback
14251506 if (initRequest .callback_ != null ) {
1426- initRequest .callback_ .onInitFinished (null , new BranchError ( "Trouble initializing Branch." , BranchError . ERR_BRANCH_KEY_INVALID ) );
1507+ initRequest .callback_ .onInitFinished (null , keyError );
14271508 }
14281509 BranchLogger .w ("Warning: Please enter your branch_key in your project's manifest" );
14291510 return ;
@@ -1451,9 +1532,9 @@ private void initializeSession(ServerRequestInitSession initRequest, int delay)
14511532 Intent intent = getCurrentActivity () != null ? getCurrentActivity ().getIntent () : null ;
14521533 boolean forceBranchSession = isRestartSessionRequested (intent );
14531534
1454- SESSION_STATE sessionState = getInitState ();
1535+ BranchSessionState sessionState = getCurrentSessionState ();
14551536 BranchLogger .v ("Intent: " + intent + " forceBranchSession: " + forceBranchSession + " initState: " + sessionState );
1456- if (sessionState == SESSION_STATE . UNINITIALISED || forceBranchSession ) {
1537+ if (sessionState instanceof BranchSessionState . Uninitialized || forceBranchSession ) {
14571538 if (forceBranchSession && intent != null ) {
14581539 intent .removeExtra (Defines .IntentKeys .ForceNewBranchSession .getKey ()); // SDK-881, avoid double initialization
14591540 }
0 commit comments