blob: 6137c06f8fb273ab8b65a6541257311971f0521c [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_ASSISTIVE_SUGGESTER_H_
#define CHROME_BROWSER_ASH_INPUT_METHOD_ASSISTIVE_SUGGESTER_H_
#include <memory>
#include <string>
#include <vector>
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "chrome/browser/ash/input_method/assistive_suggester_switch.h"
#include "chrome/browser/ash/input_method/emoji_suggester.h"
#include "chrome/browser/ash/input_method/longpress_diacritics_suggester.h"
#include "chrome/browser/ash/input_method/multi_word_suggester.h"
#include "chrome/browser/ash/input_method/personal_info_suggester.h"
#include "chrome/browser/ash/input_method/suggester.h"
#include "chrome/browser/ash/input_method/suggestion_enums.h"
#include "chrome/browser/ash/input_method/suggestion_handler_interface.h"
#include "chrome/browser/ash/input_method/suggestions_source.h"
#include "chromeos/ash/services/ime/public/cpp/assistive_suggestions.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace ash {
namespace input_method {
// An agent to suggest assistive information when the user types, and adopt or
// dismiss the suggestion according to the user action.
class AssistiveSuggester : public SuggestionsSource {
public:
// Features handled by assistive suggester.
enum class AssistiveFeature {
kUnknown, // Includes features not handled by assistive suggester.
kEmojiSuggestion,
kMultiWordSuggestion,
kPersonalInfoSuggestion,
};
// personal_data_manager is only used for testing to override the default
// autofill data for PersonalInfoSuggester.
AssistiveSuggester(SuggestionHandlerInterface* suggestion_handler,
Profile* profile,
std::unique_ptr<AssistiveSuggesterSwitch> suggester_switch,
autofill::PersonalDataManager*
personal_data_manager_for_testing = nullptr);
~AssistiveSuggester() override;
bool IsAssistiveFeatureEnabled();
// Fetches enabled suggestions in the current browser context then run
// callback.
void FetchEnabledSuggestionsFromBrowserContextThen(
AssistiveSuggesterSwitch::FetchEnabledSuggestionsCallback callback);
// SuggestionsSource overrides
std::vector<ime::AssistiveSuggestion> GetSuggestions() override;
// Called when a new input engine is activated by the system.
void OnActivate(const std::string& engine_id);
// Called when a text field gains focus, and suggester starts working.
void OnFocus(int context_id);
// Called when a text field loses focus, and suggester stops working.
void OnBlur();
// Called when a surrounding text is changed.
// Returns true if it changes the surrounding text, e.g. a suggestion is
// generated or dismissed.
void OnSurroundingTextChanged(const std::u16string& text,
int cursor_pos,
int anchor_pos);
// Called when the user pressed a key.
// Returns true if it should stop further processing of event.
bool OnKeyEvent(const ui::KeyEvent& event);
// Called when suggestions are generated outside of the assistive framework.
void OnExternalSuggestionsUpdated(
const std::vector<ime::AssistiveSuggestion>& suggestions);
// Accepts the suggestion at a given index if a suggester is currently
// active.
void AcceptSuggestion(size_t index);
// Check if suggestion is being shown.
bool IsSuggestionShown();
EmojiSuggester* get_emoji_suggester_for_testing() {
return &emoji_suggester_;
}
absl::optional<AssistiveSuggesterSwitch::EnabledSuggestions>
get_enabled_suggestion_from_last_onfocus_for_testing() {
return enabled_suggestions_from_last_onfocus_;
}
private:
// Callback that is run after enabled_suggestions is received.
void ProcessOnSurroundingTextChanged(
const std::u16string& text,
int cursor_pos,
int anchor_pos,
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
// Returns if any suggestion text should be displayed according to the
// surrounding text information.
bool TrySuggestWithSurroundingText(
const std::u16string& text,
int cursor_pos,
int anchor_pos,
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
void DismissSuggestion();
bool IsAssistPersonalInfoEnabled();
bool IsEmojiSuggestAdditionEnabled();
bool IsEnhancedEmojiSuggestEnabled();
bool IsMultiWordSuggestEnabled();
bool IsExpandedMultiWordSuggestEnabled();
bool IsDiacriticsOnPhysicalKeyboardLongpressEnabled();
// Checks the text before cursor, emits metric if any assistive prefix is
// matched.
void RecordAssistiveMatchMetrics(
const std::u16string& text,
int cursor_pos,
int anchor_pos,
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
void RecordAssistiveMatchMetricsForAssistiveType(
AssistiveType type,
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
// Only the first applicable reason in DisabledReason enum is returned.
DisabledReason GetDisabledReasonForEmoji(
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
// Only the first applicable reason in DisabledReason enum is returned.
DisabledReason GetDisabledReasonForPersonalInfo(
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
// Only the first applicable reason in DisabledReason enum is returned.
DisabledReason GetDisabledReasonForMultiWord(
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
AssistiveFeature GetAssistiveFeatureForType(AssistiveType type);
bool IsAssistiveTypeEnabled(AssistiveType type);
bool IsAssistiveTypeAllowedInBrowserContext(
AssistiveType type,
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
bool WithinGrammarFragment(int cursor_pos, int anchor_pos);
void ProcessExternalSuggestions(
const std::vector<ime::AssistiveSuggestion>& suggestions,
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
// This records any text input state metrics for each relevant assistive
// feature. It is called once when a text field gains focus.
void RecordTextInputStateMetrics(
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
// Does longpress related processing (if enabled).
// Returns true if we block the keyevent from passing to IME, and stop
// dispatch.
// Returns false, if we want IME to process the event and dispatch it.
bool HandleLongpressEnabledKeyEvent(const ui::KeyEvent& key_character);
void HandleEnabledSuggestionsOnFocus(
const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions);
void OnLongpressDetected();
Profile* profile_;
PersonalInfoSuggester personal_info_suggester_;
EmojiSuggester emoji_suggester_;
MultiWordSuggester multi_word_suggester_;
LongpressDiacriticsSuggester longpress_diacritics_suggester_;
std::unique_ptr<AssistiveSuggesterSwitch> suggester_switch_;
// The id of the currently active input engine.
std::string active_engine_id_;
// ID of the focused text field, nullopt if none focused.
absl::optional<int> focused_context_id_;
// KeyEvent of the held down key at key down. nullopt if no longpress in
// progress.
absl::optional<ui::KeyEvent> current_longpress_keydown_;
// Timer for longpress. Starts when key is held down. Fires when successfully
// held down for a specified longpress duration.
base::OneShotTimer longpress_timer_;
// The current suggester in use, nullptr means no suggestion is shown.
Suggester* current_suggester_ = nullptr;
absl::optional<AssistiveSuggesterSwitch::EnabledSuggestions>
enabled_suggestions_from_last_onfocus_;
std::u16string last_surrounding_text_ = u"";
int last_cursor_pos_ = 0;
base::WeakPtrFactory<AssistiveSuggester> weak_ptr_factory_{this};
};
} // namespace input_method
} // namespace ash
#endif // CHROME_BROWSER_ASH_INPUT_METHOD_ASSISTIVE_SUGGESTER_H_