#ifndef COMPONENTS_COLLABORATION_INTERNAL_COLLABORATION_CONTROLLER_H_
#define COMPONENTS_COLLABORATION_INTERNAL_COLLABORATION_CONTROLLER_H_
#include <array>
#include <map>
#include <memory>
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "components/collaboration/public/collaboration_controller_delegate.h"
#include "components/collaboration/public/collaboration_flow_type.h"
#include "components/collaboration/public/collaboration_service.h"
#include "components/data_sharing/public/data_sharing_service.h"
#include "components/data_sharing/public/group_data.h"
#include "components/saved_tab_groups/public/tab_group_sync_service.h"
#include "components/saved_tab_groups/public/types.h"
#include "components/signin/public/identity_manager/identity_manager.h"
namespace syncer {
class SyncService;
}
namespace collaboration {
class ControllerState;
class CollaborationController
: public tab_groups::TabGroupSyncService::Observer,
public CollaborationService::Observer {
public:
enum class StateId {
kPending,
kWaitingForPolicyUpdate,
kAuthenticating,
kWaitingForServicesToInitialize,
kCheckingFlowRequirements,
kAddingUserToGroup,
kWaitingForSyncAndDataSharingGroup,
kOpeningLocalTabGroup,
kShowingShareScreen,
kMakingTabGroupShared,
kSharingTabGroupUrl,
kShowingManageScreen,
kLeavingGroup,
kDeletingGroup,
kCleaningUpSharedTabGroup,
kCancel,
kError,
};
class Flow {
public:
Flow(FlowType type, const data_sharing::GroupToken& token);
Flow(FlowType type, const tab_groups::EitherGroupID& either_id);
~Flow();
Flow(const Flow&);
const FlowType type;
const data_sharing::GroupToken& join_token() const {
DCHECK_EQ(type, FlowType::kJoin);
return join_token_;
}
const tab_groups::EitherGroupID& either_id() const {
return either_id_;
}
const data_sharing::GroupToken& share_token() const {
DCHECK_EQ(type, FlowType::kShareOrManage);
CHECK(share_token_.IsValid());
return share_token_;
}
void set_share_token(const data_sharing::GroupToken& token) {
share_token_ = token;
}
private:
const data_sharing::GroupToken join_token_;
const tab_groups::EitherGroupID either_id_;
data_sharing::GroupToken share_token_;
};
using FinishCallback = base::OnceCallback<void(const void*)>;
explicit CollaborationController(
const Flow& flow,
CollaborationService* collaboration_service,
data_sharing::DataSharingService* data_sharing_service,
tab_groups::TabGroupSyncService* tab_group_sync_service,
syncer::SyncService* sync_service,
signin::IdentityManager* identity_manager,
std::unique_ptr<CollaborationControllerDelegate> delegate,
FinishCallback finish_and_delete);
~CollaborationController() override;
CollaborationController(const CollaborationController&) = delete;
CollaborationController& operator=(const CollaborationController&) = delete;
CollaborationControllerDelegate* delegate() { return delegate_.get(); }
data_sharing::DataSharingService* data_sharing_service() {
return data_sharing_service_.get();
}
tab_groups::TabGroupSyncService* tab_group_sync_service() {
return tab_group_sync_service_.get();
}
syncer::SyncService* sync_service() { return sync_service_.get(); }
signin::IdentityManager* identity_manager() {
return identity_manager_.get();
}
CollaborationService* collaboration_service() {
return collaboration_service_.get();
}
Flow& flow() { return flow_; }
base::Time flow_start_time() const { return flow_start_time_; }
void TransitionTo(StateId state,
const CollaborationControllerDelegate::ErrorInfo& error =
CollaborationControllerDelegate::ErrorInfo());
void PromoteCurrentSession();
void Exit();
void Cancel();
void SetStateForTesting(StateId state);
StateId GetStateForTesting();
void OnTabGroupRemoved(const tab_groups::LocalTabGroupID& local_id,
tab_groups::TriggerSource source) override;
void OnTabGroupRemoved(const base::Uuid& sync_id,
tab_groups::TriggerSource source) override;
void OnTabGroupMigrated(const tab_groups::SavedTabGroup& new_group,
const base::Uuid& old_sync_id,
tab_groups::TriggerSource source) override;
void OnServiceStatusChanged(
const CollaborationService::Observer::ServiceStatusUpdate& update)
override;
private:
base::Time flow_start_time_;
static constexpr std::array<std::pair<StateId, StateId>, 53>
kValidTransitions = {{
{StateId::kPending, StateId::kCancel},
{StateId::kWaitingForPolicyUpdate, StateId::kCancel},
{StateId::kAuthenticating, StateId::kCancel},
{StateId::kWaitingForServicesToInitialize, StateId::kCancel},
{StateId::kCheckingFlowRequirements, StateId::kCancel},
{StateId::kAddingUserToGroup, StateId::kCancel},
{StateId::kWaitingForSyncAndDataSharingGroup, StateId::kCancel},
{StateId::kOpeningLocalTabGroup, StateId::kCancel},
{StateId::kShowingShareScreen, StateId::kCancel},
{StateId::kMakingTabGroupShared, StateId::kCancel},
{StateId::kSharingTabGroupUrl, StateId::kCancel},
{StateId::kShowingManageScreen, StateId::kCancel},
{StateId::kLeavingGroup, StateId::kCancel},
{StateId::kDeletingGroup, StateId::kCancel},
{StateId::kCleaningUpSharedTabGroup, StateId::kCancel},
{StateId::kError, StateId::kCancel},
{StateId::kPending, StateId::kAuthenticating},
{StateId::kPending, StateId::kWaitingForPolicyUpdate},
{StateId::kPending, StateId::kWaitingForServicesToInitialize},
{StateId::kPending, StateId::kError},
{StateId::kWaitingForPolicyUpdate, StateId::kAuthenticating},
{StateId::kWaitingForPolicyUpdate,
StateId::kCheckingFlowRequirements},
{StateId::kWaitingForPolicyUpdate, StateId::kError},
{StateId::kAuthenticating, StateId::kWaitingForPolicyUpdate},
{StateId::kAuthenticating, StateId::kWaitingForServicesToInitialize},
{StateId::kAuthenticating, StateId::kError},
{StateId::kWaitingForServicesToInitialize,
StateId::kCheckingFlowRequirements},
{StateId::kWaitingForServicesToInitialize, StateId::kError},
{StateId::kCheckingFlowRequirements, StateId::kAddingUserToGroup},
{StateId::kCheckingFlowRequirements,
StateId::kWaitingForSyncAndDataSharingGroup},
{StateId::kCheckingFlowRequirements, StateId::kOpeningLocalTabGroup},
{StateId::kCheckingFlowRequirements, StateId::kShowingShareScreen},
{StateId::kCheckingFlowRequirements, StateId::kShowingManageScreen},
{StateId::kCheckingFlowRequirements, StateId::kLeavingGroup},
{StateId::kCheckingFlowRequirements, StateId::kDeletingGroup},
{StateId::kCheckingFlowRequirements, StateId::kError},
{StateId::kAddingUserToGroup,
StateId::kWaitingForSyncAndDataSharingGroup},
{StateId::kAddingUserToGroup, StateId::kOpeningLocalTabGroup},
{StateId::kAddingUserToGroup, StateId::kError},
{StateId::kWaitingForSyncAndDataSharingGroup,
StateId::kOpeningLocalTabGroup},
{StateId::kWaitingForSyncAndDataSharingGroup, StateId::kError},
{StateId::kOpeningLocalTabGroup, StateId::kError},
{StateId::kShowingShareScreen, StateId::kMakingTabGroupShared},
{StateId::kShowingShareScreen, StateId::kError},
{StateId::kMakingTabGroupShared, StateId::kSharingTabGroupUrl},
{StateId::kMakingTabGroupShared, StateId::kError},
{StateId::kSharingTabGroupUrl, StateId::kError},
{StateId::kShowingManageScreen, StateId::kCleaningUpSharedTabGroup},
{StateId::kShowingManageScreen, StateId::kError},
{StateId::kLeavingGroup, StateId::kCleaningUpSharedTabGroup},
{StateId::kLeavingGroup, StateId::kError},
{StateId::kDeletingGroup, StateId::kCleaningUpSharedTabGroup},
{StateId::kDeletingGroup, StateId::kError},
}};
void CancelShareOrManageFlow(const tab_groups::EitherGroupID& either_id);
bool IsValidStateTransition(StateId from, StateId to);
std::unique_ptr<ControllerState> CreateStateObject(StateId state);
void Start();
THREAD_CHECKER(thread_checker_);
std::unique_ptr<ControllerState> current_state_;
Flow flow_;
bool is_deleting_{false};
const raw_ptr<CollaborationService> collaboration_service_;
const raw_ptr<data_sharing::DataSharingService> data_sharing_service_;
const raw_ptr<tab_groups::TabGroupSyncService> tab_group_sync_service_;
const raw_ptr<syncer::SyncService> sync_service_;
const raw_ptr<signin::IdentityManager> identity_manager_;
std::unique_ptr<CollaborationControllerDelegate> delegate_;
FinishCallback finish_and_delete_;
base::ScopedObservation<tab_groups::TabGroupSyncService,
tab_groups::TabGroupSyncService::Observer>
tab_group_sync_service_observer_{this};
base::ScopedObservation<CollaborationService, CollaborationService::Observer>
collaboration_service_observer_{this};
base::WeakPtrFactory<CollaborationController> weak_ptr_factory_{this};
};
}
#endif