blob: 31f837463d7b2cce3c1807cb537b9eef6187ad98 [file] [log] [blame]
// 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_