chromium/ash/system/phonehub/phone_hub_ui_controller.h

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

#ifndef ASH_SYSTEM_PHONEHUB_PHONE_HUB_UI_CONTROLLER_H_
#define ASH_SYSTEM_PHONEHUB_PHONE_HUB_UI_CONTROLLER_H_

#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
#include "ash/system/phonehub/onboarding_view.h"
#include "ash/system/phonehub/phone_hub_content_view.h"
#include "ash/system/phonehub/phone_status_view.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/timer/timer.h"
#include "chromeos/ash/components/phonehub/app_stream_launcher_data_model.h"
#include "chromeos/ash/components/phonehub/feature_status_provider.h"
#include "chromeos/ash/components/phonehub/onboarding_ui_tracker.h"
#include "chromeos/ash/components/phonehub/phone_model.h"

namespace views {
class View;
}  // namespace views

namespace ash {

namespace phonehub {
class PhoneHubManager;
}

// This controller translates the state received from PhoneHubManager into the
// corresponding main content view to be displayed in the tray bubble.
class ASH_EXPORT PhoneHubUiController
    : public phonehub::FeatureStatusProvider::Observer,
      public phonehub::OnboardingUiTracker::Observer,
      public phonehub::PhoneModel::Observer,
      public phonehub::AppStreamLauncherDataModel::Observer,
      public SessionObserver {
 public:
  class Observer : public base::CheckedObserver {
   public:
    ~Observer() override = default;

    virtual void OnPhoneHubUiStateChanged() = 0;
  };

  // All the possible states that the main content view can be in. Each state
  // has a corresponding view class.
  enum class UiState {
    kHidden = 0,
    kOnboardingWithoutPhone,
    kOnboardingWithPhone,
    kBluetoothDisabled,
    kPhoneConnecting,
    kPhoneDisconnected,
    kPhoneConnected,
    kTetherConnectionPending,
    kMiniLauncher,
    kMaxValue = kMiniLauncher
  };

  PhoneHubUiController();
  PhoneHubUiController(const PhoneHubUiController&) = delete;
  ~PhoneHubUiController() override;
  PhoneHubUiController& operator=(const PhoneHubUiController&) = delete;

  // Sets the PhoneHubManager that provides the data to drive the UI.
  void SetPhoneHubManager(phonehub::PhoneHubManager* phone_hub_manager);

  // Creates the corresponding content view for the current UI state.
  // |bubble_view| will be the parent the created content view.
  std::unique_ptr<PhoneHubContentView> CreateContentView(
      OnboardingView::Delegate* delegate);

  // Creates the header view displaying the phone status.
  std::unique_ptr<views::View> CreateStatusHeaderView(
      PhoneStatusView::Delegate* delegate);

  // Handler for when the bubble is opened. Requests a connection to the phone
  // if there is no current connection, and records metrics.
  void HandleBubbleOpened();

  // Observer functions.
  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  UiState ui_state() const { return ui_state_; }

 private:
  // phonehub::FeatureStatusProvider::Observer:
  void OnFeatureStatusChanged() override;

  // phonehub::OnboardingUiTracker::Observer:
  void OnShouldShowOnboardingUiChanged() override;

  // phonehub::AppStreamLauncherDataModel::Observer:
  void OnShouldShowMiniLauncherChanged() override;

  // phonehub::PhoneModel::Observer:
  void OnModelChanged() override;

  // SessionObserver:
  void OnActiveUserSessionChanged(const AccountId& account_id) override;

  // Updates the current UI state and notifies observers.
  void UpdateUiState(PhoneHubUiController::UiState new_state);

  // Returns the UiState from the PhoneHubManager.
  UiState GetUiStateFromPhoneHubManager();

  // Returns the UiState from the PhoneHubManager.
  UiState GetUiStateFromPhoneHubManagerInternal();

  // Cleans up |phone_hub_manager_| by removing all observers.
  void CleanUpPhoneHubManager();

  // When |connecting_view_grace_period_timer_| ends, triggers a change in
  // the content view to show a disconnected view.
  void OnConnectingViewTimerEnd();

  void RecordStatusOnBubbleOpened();
  void OnGetHostLastSeenTimestamp(UiState ui_state_when_opened,
                                  std::optional<base::Time> timestamp);

  // The PhoneHubManager that provides data for the UI.
  raw_ptr<phonehub::PhoneHubManager> phone_hub_manager_ = nullptr;

  // The current UI state.
  UiState ui_state_ = UiState::kHidden;

  // This value becomes true the first time the user opens the PhoneHub UI
  // when the feature is in the enabled state, and a tether scan request is
  // made.
  bool has_requested_tether_scan_during_session_ = false;

  // Registered observers.
  base::ObserverList<Observer> observer_list_;

  // The timer that dictates how long to show |kConnecting| after disconnect
  // so when the connection fails on the first attempt and retries, it is not
  // confusing to users when it shows disconnecting view, rather, it will show
  // connecting view on this occasion.
  base::OneShotTimer connecting_view_grace_period_timer_;

  base::WeakPtrFactory<PhoneHubUiController> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // ASH_SYSTEM_PHONEHUB_PHONE_HUB_UI_CONTROLLER_H_