chromium/ios/chrome/browser/shared/model/browser_state/incognito_session_tracker.h

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef IOS_CHROME_BROWSER_SHARED_MODEL_BROWSER_STATE_INCOGNITO_SESSION_TRACKER_H_
#define IOS_CHROME_BROWSER_SHARED_MODEL_BROWSER_STATE_INCOGNITO_SESSION_TRACKER_H_

#import "base/callback_list.h"
#import "base/containers/flat_map.h"
#import "base/scoped_observation.h"
#import "base/sequence_checker.h"
#import "ios/chrome/browser/shared/model/profile/profile_manager_observer_ios.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios_forward.h"

class ProfileManagerIOS;

// Tracks whether there are any open off-the-record tabs open by any Profile in
// the application. Allow to be notified when the state changes or to poll it
// when needed.
class IncognitoSessionTracker final : public ProfileManagerObserverIOS {
 public:
  // Container for the callbacks registered with RegisterCallback().
  using SessionStateChangedCallbackList =
      base::RepeatingCallbackList<void(bool)>;

  // Type of the callbacks registered with RegisterCallback().
  using SessionStateChangedCallback =
      SessionStateChangedCallbackList::CallbackType;

  explicit IncognitoSessionTracker(ProfileManagerIOS* manager);
  ~IncognitoSessionTracker() final;

  // Returns whether there are any off-the-record tabs open.
  bool HasIncognitoSessionTabs() const;

  // Registers `callback` to be invoked when the presence of off-the-record
  // tabs has changed (e.g. the callback will not be called if the number of
  // open off-the-record tabs goes from two to three).
  base::CallbackListSubscription RegisterCallback(
      SessionStateChangedCallback callback);

  // ProfileManagerObserverIOS:
  void OnProfileManagerDestroyed(ProfileManagerIOS* manager) override;
  void OnProfileCreated(ProfileManagerIOS* manager,
                        ChromeBrowserState* profile) override;
  void OnProfileLoaded(ProfileManagerIOS* manager,
                       ChromeBrowserState* profile) override;

 private:
  // Forward-declaration of the observer used to track the state of
  // an individual Profile.
  class Observer;

  // Invoked when the state of invoked when the presence of off-the-record
  // tabs for a specific ChromeBrowserState has changed.
  void OnIncognitoSessionStateChanged(bool has_incognito_tabs);

  // Manage observing the ProfileManagerIOS.
  base::ScopedObservation<ProfileManagerIOS, ProfileManagerObserverIOS>
      scoped_manager_observation_{this};

  // Map from Profile to the observer used to track whether it has any open
  // off-the-record tabs.
  base::flat_map<ChromeBrowserState*, std::unique_ptr<Observer>> observers_;

  // List of registered callbacks.
  SessionStateChangedCallbackList callbacks_;

  // Whether any off-the-record tabs are open in any ChromeBrowserState.
  bool has_incognito_session_tabs_ = false;

  SEQUENCE_CHECKER(sequence_checker_);
};

#endif  // IOS_CHROME_BROWSER_SHARED_MODEL_BROWSER_STATE_INCOGNITO_SESSION_TRACKER_H_