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

#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

#include "ash/ash_export.h"
#include "ash/quick_insert/metrics/quick_insert_feature_usage_metrics.h"
#include "ash/quick_insert/metrics/quick_insert_session_metrics.h"
#include "ash/quick_insert/model/quick_insert_emoji_history_model.h"
#include "ash/quick_insert/model/quick_insert_emoji_suggester.h"
#include "ash/quick_insert/model/quick_insert_model.h"
#include "ash/quick_insert/quick_insert_asset_fetcher_impl_delegate.h"
#include "ash/quick_insert/quick_insert_caps_lock_bubble_controller.h"
#include "ash/quick_insert/quick_insert_insert_media_request.h"
#include "ash/quick_insert/quick_insert_search_result.h"
#include "ash/quick_insert/quick_insert_suggestions_controller.h"
#include "ash/quick_insert/quick_insert_web_paste_target.h"
#include "ash/quick_insert/search/quick_insert_search_controller.h"
#include "ash/quick_insert/views/quick_insert_feature_tour.h"
#include "ash/quick_insert/views/quick_insert_view_delegate.h"
#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "ui/base/emoji/emoji_panel_helper.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/input_device_event_observer.h"
#include "ui/views/view_observer.h"
#include "ui/views/widget/unique_widget_ptr.h"

class PrefRegistrySimple;
class PrefService;

namespace input_method {
class ImeKeyboard;
}

namespace ui {
class TextInputClient;
}

namespace network {
class SharedURLLoaderFactory;
}  // namespace network

namespace ash {

class QuickInsertAssetFetcher;
class QuickInsertClient;
class QuickInsertModel;
class QuickInsertPasteRequest;
class QuickInsertActionOnNextFocusRequest;

// Controls a Quick Insert widget.
class ASH_EXPORT QuickInsertController
    : public QuickInsertViewDelegate,
      public views::ViewObserver,
      public QuickInsertAssetFetcherImplDelegate {
 public:
  QuickInsertController();
  QuickInsertController(const QuickInsertController&) = delete;
  QuickInsertController& operator=(const QuickInsertController&) = delete;
  ~QuickInsertController() override;

  // Maximum time to wait for focus to be regained after completing the feature
  // tour. If this timeout is reached, we stop waiting for focus and show the
  // Quick Insert widget regardless of the focus state.
  static constexpr base::TimeDelta kShowWidgetPostFeatureTourTimeout =
      base::Seconds(2);

  // Time from when the insert is issued and when we give up inserting.
  static constexpr base::TimeDelta kInsertMediaTimeout = base::Seconds(2);

  // Time from when a search starts to when the first set of results are
  // published.
  static constexpr base::TimeDelta kBurnInPeriod = base::Milliseconds(200);

  // Registers Quick Insert prefs to the provided `registry`.
  static void RegisterProfilePrefs(PrefRegistrySimple* registry);

  // Sets the `client` used by this class and the widget to communicate with the
  // browser. `client` may be set to null, which will close the Widget if it's
  // open, and may call "stop search" methods on the PREVIOUS client.
  // If `client` is not null, then it must remain valid for the lifetime of this
  // class, or until AFTER `SetClient` is called with a different client.
  // Caution: If `client` outlives this class, the client should avoid calling
  // this method on a destructed class instance to avoid a use after free.
  void SetClient(QuickInsertClient* client);

  // This should be run when the Prefs from the client is ready.
  void OnClientPrefsSet(PrefService* prefs);

  // Toggles the visibility of the Quick Insert widget.
  // This must only be called after `SetClient` is called with a valid client.
  // `trigger_event_timestamp` is the timestamp of the event that triggered the
  // Widget to be toggled. For example, if the feature was triggered by a mouse
  // click, then it should be the timestamp of the click. By default, the
  // timestamp is the time this function is called.
  void ToggleWidget(
      base::TimeTicks trigger_event_timestamp = base::TimeTicks::Now());

  // Returns the Quick Insert widget for tests.
  views::Widget* widget_for_testing() { return widget_.get(); }
  QuickInsertFeatureTour& feature_tour_for_testing() { return feature_tour_; }
  QuickInsertCapsLockBubbleController&
  caps_lock_bubble_controller_for_testing() {
    return caps_lock_bubble_controller_;
  }

  // QuickInsertViewDelegate:
  std::vector<QuickInsertCategory> GetAvailableCategories() override;
  void GetZeroStateSuggestedResults(SuggestedResultsCallback callback) override;
  void GetResultsForCategory(QuickInsertCategory category,
                             SearchResultsCallback callback) override;
  void StartSearch(std::u16string_view query,
                   std::optional<QuickInsertCategory> category,
                   SearchResultsCallback callback) override;
  void StopSearch() override;
  void StartEmojiSearch(std::u16string_view,
                        EmojiSearchResultsCallback callback) override;
  void CloseWidgetThenInsertResultOnNextFocus(
      const QuickInsertSearchResult& result) override;
  void OpenResult(const QuickInsertSearchResult& result) override;
  void ShowEmojiPicker(ui::EmojiPickerCategory category,
                       std::u16string_view query) override;
  void ShowEditor(std::optional<std::string> preset_query_id,
                  std::optional<std::string> freeform_text) override;
  void ShowLobster(std::optional<std::string> freeform_text) override;
  QuickInsertAssetFetcher* GetAssetFetcher() override;
  QuickInsertSessionMetrics& GetSessionMetrics() override;
  QuickInsertActionType GetActionForResult(
      const QuickInsertSearchResult& result) override;
  std::vector<QuickInsertEmojiResult> GetSuggestedEmoji() override;
  bool IsGifsEnabled() override;
  QuickInsertModeType GetMode() override;
  QuickInsertCapsLockPosition GetCapsLockPosition() override;

  // views:ViewObserver:
  void OnViewIsDeleting(views::View* view) override;

  // QuickInsertAssetFetcherImplDelegate:
  scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory()
      override;
  void FetchFileThumbnail(const base::FilePath& path,
                          const gfx::Size& size,
                          FetchFileThumbnailCallback callback) override;

  // Disables the feature tour. Only works in tests.
  static void DisableFeatureTourForTesting();

 private:
  // Trigger source for showing the Quick Insert widget. This is used to
  // determine how the widget should be shown on the screen.
  enum class WidgetTriggerSource {
    // The user triggered Quick Insert as part of their usual user flow, e.g.
    // toggled Quick Insert with a key press.
    kDefault,
    // The user triggered Quick Insert by completing the feature tour.
    kFeatureTour,
  };

  // Active Quick Insert session tied to the lifetime of the QuickInsertWidget.
  struct Session {
    QuickInsertModel model;
    QuickInsertEmojiHistoryModel emoji_history_model;
    QuickInsertEmojiSuggester emoji_suggester;
    QuickInsertSessionMetrics session_metrics;
    // Periodically records usage metrics based on the Standard Feature Usage
    // Logging (SFUL) framework.
    QuickInsertFeatureUsageMetrics feature_usage_metrics;

    Session(PrefService* prefs,
            ui::TextInputClient* focused_client,
            input_method::ImeKeyboard* ime_keyboard,
            QuickInsertModel::EditorStatus editor_status,
            QuickInsertModel::LobsterStatus lobster_status,
            QuickInsertEmojiSuggester::GetNameCallback get_name);
    ~Session();
  };

  void ShowWidget(base::TimeTicks trigger_event_timestamp,
                  WidgetTriggerSource trigger_source);
  void CloseWidget();
  void ShowWidgetPostFeatureTour();
  void InsertResultOnNextFocus(const QuickInsertSearchResult& result);
  void OnInsertCompleted(const QuickInsertRichMedia& media,
                         QuickInsertInsertMediaRequest::Result result);
  PrefService* GetPrefs();

  std::optional<QuickInsertWebPasteTarget> GetWebPasteTarget();

  QuickInsertFeatureTour feature_tour_;
  QuickInsertCapsLockBubbleController caps_lock_bubble_controller_;
  std::unique_ptr<Session> session_;
  views::UniqueWidgetPtr widget_;
  std::unique_ptr<QuickInsertAssetFetcher> asset_fetcher_;
  std::unique_ptr<QuickInsertInsertMediaRequest> insert_media_request_;
  std::unique_ptr<QuickInsertPasteRequest> paste_request_;
  std::unique_ptr<QuickInsertActionOnNextFocusRequest> caps_lock_request_;
  QuickInsertSuggestionsController suggestions_controller_;
  QuickInsertSearchController search_controller_;

  raw_ptr<QuickInsertClient> client_ = nullptr;

  base::OnceCallback<void(std::optional<std::string> preset_query_id,
                          std::optional<std::string> freeform_text)>
      show_editor_callback_;

  base::OnceCallback<void(std::optional<std::string> freeform_text)>
      show_lobster_callback_;

  // Timer used to delay closing the Widget for accessibility.
  base::OneShotTimer close_widget_delay_timer_;

  base::ScopedObservation<views::View, views::ViewObserver> view_observation_{
      this};

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

}  // namespace ash

#endif  // ASH_QUICK_INSERT_QUICK_INSERT_CONTROLLER_H_