910e62b5创建于 1月15日历史提交
// 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 ASH_SCANNER_SCANNER_CONTROLLER_H_
#define ASH_SCANNER_SCANNER_CONTROLLER_H_

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
#include "ash/scanner/scanner_action_view_model.h"
#include "ash/scanner/scanner_session.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"

class PrefRegistrySimple;

namespace manta::proto {
class ScannerAction;
}

namespace ash {

class ScannerCommandDelegateImpl;
class ScannerDelegate;
class ScreenPinningController;
class SessionControllerImpl;

// This is the top level controller used for Scanner. It acts as a mediator
// between Scanner and any consuming features.
class ASH_EXPORT ScannerController : public SessionObserver {
 public:
  using OnActionFinishedCallback = base::OnceCallback<void(bool success)>;

  // `screen_pinning_controller` must outlive this class.
  // It must only be null in tests.
  explicit ScannerController(
      std::unique_ptr<ScannerDelegate> delegate,
      SessionControllerImpl& session_controller,
      const ScreenPinningController* screen_pinning_controller);
  ScannerController(const ScannerController&) = delete;
  ScannerController& operator=(const ScannerController&) = delete;
  ~ScannerController() override;

  static void RegisterProfilePrefs(PrefRegistrySimple* registry);

  // Returns whether Scanner-related UI can be shown. This function checks
  // `CanShowUi` for the `Shell`-global `ScannerController`.
  //
  // Do NOT use this method if your feature is using
  // `SunfishScannerFeatureWatcher`, use its `CanShowScannerUi` method instead.
  static bool CanShowUiForShell();

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

  // Checks system level constraints (e.g. feature flags) and returns
  // true if the constraints allow the scanner UI to show.
  // Note that this ignores consent status.
  bool CanShowUi();

  // Checks system level constraints (e.g. feature flags) and returns
  // true if the constraints allow a Scanner settings toggle to be shown.
  bool CanShowFeatureSettingsToggle();

  // Checks system level constraints (e.g. prefs, feature flags) and returns
  // true if the constraints allow a Scanner session to be created.
  bool CanStartSession();

  // Creates a new ScannerSession and returns a pointer to the created session.
  // If the Scanner cannot be initialized due to system level constraints (e.g.
  // pref disabled, feature not allowed), then no session is created and
  // `nullptr` is returned instead. Note that calling `StartNewSession` will end
  // the current session if there is one.
  ScannerSession* StartNewSession();

  // Fetches Scanner actions that are available based on the current
  // `scanner_session_` and the contents of `jpeg_bytes`, and returns whether a
  // session was active. The actions are returned via `callback`. If no session
  // is active, then `callback` will be run with an empty list of actions.
  bool FetchActionsForImage(scoped_refptr<base::RefCountedMemory> jpeg_bytes,
                            ScannerSession::FetchActionsCallback callback);

  // Should be called when the user has finished interacting with a Scanner
  // session. This will trigger relevant cleanup and eventually destroy the
  // scanner session.
  void OnSessionUIClosed();

  // Executes the action described by `scanner_action`.
  void ExecuteAction(const ScannerActionViewModel& scanner_action);

  // Opens a feedback dialog for an action that has been performed, and the
  // (resized) screenshot which initiated the action.
  // WARNING: This function does not check whether the account has feedback
  // enabled or not!
  void OpenFeedbackDialog(const AccountId& account_id,
                          manta::proto::ScannerAction action,
                          scoped_refptr<base::RefCountedMemory> screenshot);

  // Sets mock ScannerOutput data for testing.
  void SetScannerResponsesForTesting(const std::vector<std::string> responses);

  bool HasActiveSessionForTesting() const;

  ScannerDelegate* delegate_for_testing() { return delegate_.get(); }

  void SetOnActionFinishedForTesting(OnActionFinishedCallback callback);

 private:
  // Should be called when an action finishes execution.
  void OnActionFinished(
      manta::proto::ScannerAction::ActionCase action_case,
      scoped_refptr<base::RefCountedMemory> downscaled_jpeg_bytes,
      manta::proto::ScannerAction populated_action,
      bool success);

  std::unique_ptr<ScannerDelegate> delegate_;

  // Delegate to handle Scanner commands for actions fetched during a session.
  // `command_delegate_` should outlive `scanner_session_`, to allow commands to
  // be completed in the background after the session UI has been closed.
  std::unique_ptr<ScannerCommandDelegateImpl> command_delegate_;

  // May hold an active Scanner session, to allow access to the Scanner feature.
  std::unique_ptr<ScannerSession> scanner_session_;

  OnActionFinishedCallback on_action_finished_for_testing_;

  // External dependencies not owned by this class:
  // Session controller, stored in `Shell`. Always outlives this class.
  raw_ref<SessionControllerImpl> session_controller_;
  // Screen pinning controller, stored in `Shell`. Always outlives this class.
  // If this pointer is null, then we are in a test.
  const raw_ptr<const ScreenPinningController> screen_pinning_controller_;

  // Holds mock ScannerOutput data for testing.
  std::vector<std::string> mock_scanner_responses_for_testing_;

  ScopedSessionObserver session_observer_{this};

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

}  // namespace ash

#endif  // ASH_SCANNER_SCANNER_CONTROLLER_H_