blob: 5b02ff7a654e75d2f13d9a42750faf89fa1132bc [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/assistant/assistant_cache_controller.h"
#include <utility>
#include <vector>
#include "ash/assistant/assistant_controller.h"
#include "ash/assistant/assistant_ui_controller.h"
#include "ash/assistant/util/assistant_util.h"
#include "ash/assistant/util/deep_link_util.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/voice_interaction/voice_interaction_controller.h"
#include "base/metrics/field_trial_params.h"
#include "base/rand_util.h"
#include "chromeos/services/assistant/public/mojom/assistant.mojom.h"
#include "ui/base/l10n/l10n_util.h"
namespace ash {
namespace {
// Conversation starters -------------------------------------------------------
const base::Feature kConversationStartersFeature{
"ChromeOSAssistantConversationStarters", base::FEATURE_ENABLED_BY_DEFAULT};
constexpr base::FeatureParam<bool> kImBoredChipEnabled{
&kConversationStartersFeature, "im-bored-chip-enabled", true};
constexpr base::FeatureParam<bool> kOpenFilesChipEnabled{
&kConversationStartersFeature, "open-files-chip-enabled", true};
constexpr base::FeatureParam<bool> kPlayMusicChipEnabled{
&kConversationStartersFeature, "play-music-chip-enabled", true};
constexpr base::FeatureParam<bool> kSendAnEmailChipEnabled{
&kConversationStartersFeature, "send-an-email-chip-enabled", true};
constexpr base::FeatureParam<bool> kSetAReminderChipEnabled{
&kConversationStartersFeature, "set-a-reminder-chip-enabled", true};
constexpr base::FeatureParam<bool> kWhatCanYouDoChipEnabled{
&kConversationStartersFeature, "what-can-you-do-chip-enabled", true};
constexpr base::FeatureParam<bool> kWhatsOnMyCalendarChipEnabled{
&kConversationStartersFeature, "whats-on-my-calendar-chip-enabled", true};
constexpr base::FeatureParam<bool> kWhatsOnMyScreenChipEnabled{
&kConversationStartersFeature, "whats-on-my-screen-chip-enabled", true};
constexpr base::FeatureParam<bool> kWhatsTheWeatherChipEnabled{
&kConversationStartersFeature, "whats-the-weather-chip-enabled", true};
constexpr int kMaxNumOfConversationStarters = 3;
} // namespace
// AssistantCacheController ----------------------------------------------------
AssistantCacheController::AssistantCacheController(
AssistantController* assistant_controller)
: assistant_controller_(assistant_controller) {
UpdateConversationStarters();
assistant_controller_->AddObserver(this);
Shell::Get()->voice_interaction_controller()->AddLocalObserver(this);
}
AssistantCacheController::~AssistantCacheController() {
assistant_controller_->RemoveObserver(this);
Shell::Get()->voice_interaction_controller()->RemoveLocalObserver(this);
}
void AssistantCacheController::AddModelObserver(
AssistantCacheModelObserver* observer) {
model_.AddObserver(observer);
}
void AssistantCacheController::RemoveModelObserver(
AssistantCacheModelObserver* observer) {
model_.RemoveObserver(observer);
}
void AssistantCacheController::OnAssistantControllerConstructed() {
assistant_controller_->ui_controller()->AddModelObserver(this);
}
void AssistantCacheController::OnAssistantControllerDestroying() {
assistant_controller_->ui_controller()->RemoveModelObserver(this);
}
void AssistantCacheController::OnUiVisibilityChanged(
AssistantVisibility new_visibility,
AssistantVisibility old_visibility,
base::Optional<AssistantEntryPoint> entry_point,
base::Optional<AssistantExitPoint> exit_point) {
// When Assistant is finishing a session, we update our cache of conversation
// starters so that they're fresh for the next launch.
if (assistant::util::IsFinishingSession(new_visibility))
UpdateConversationStarters();
}
void AssistantCacheController::OnVoiceInteractionContextEnabled(bool enabled) {
UpdateConversationStarters();
}
// TODO(dmblack): The conversation starter cache should receive its contents
// from the server. Hard-coding for the time being.
void AssistantCacheController::UpdateConversationStarters() {
if (!base::FeatureList::IsEnabled(kConversationStartersFeature))
return;
using chromeos::assistant::mojom::AssistantSuggestion;
using chromeos::assistant::mojom::AssistantSuggestionPtr;
std::vector<AssistantSuggestionPtr> conversation_starters;
auto AddConversationStarter = [&conversation_starters](
int message_id, GURL action_url = GURL()) {
AssistantSuggestionPtr starter = AssistantSuggestion::New();
starter->text = l10n_util::GetStringUTF8(message_id);
starter->action_url = action_url;
conversation_starters.push_back(std::move(starter));
};
// If enabled, always show the "What can you do?" conversation starter.
if (kWhatCanYouDoChipEnabled.Get())
AddConversationStarter(IDS_ASH_ASSISTANT_CHIP_WHAT_CAN_YOU_DO);
// If enabled, always show the "What's on my screen?" conversation starter.
if (kWhatsOnMyScreenChipEnabled.Get() &&
Shell::Get()->voice_interaction_controller()->context_enabled().value_or(
false)) {
AddConversationStarter(IDS_ASH_ASSISTANT_CHIP_WHATS_ON_MY_SCREEN,
assistant::util::CreateWhatsOnMyScreenDeepLink());
}
// The rest of the conversation starters will be shuffled...
std::vector<int> shuffled_message_ids;
if (kImBoredChipEnabled.Get())
shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_IM_BORED);
if (kOpenFilesChipEnabled.Get())
shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_OPEN_FILES);
if (kPlayMusicChipEnabled.Get())
shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_PLAY_MUSIC);
if (kSendAnEmailChipEnabled.Get())
shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_SEND_AN_EMAIL);
if (kSetAReminderChipEnabled.Get())
shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_SET_A_REMINDER);
if (kWhatsOnMyCalendarChipEnabled.Get())
shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_WHATS_ON_MY_CALENDAR);
if (kWhatsTheWeatherChipEnabled.Get())
shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_WHATS_THE_WEATHER);
base::RandomShuffle(shuffled_message_ids.begin(), shuffled_message_ids.end());
// ...and added until we have no more than |kMaxNumOfConversationStarters|.
for (int i = 0;
conversation_starters.size() < kMaxNumOfConversationStarters &&
i < static_cast<int>(shuffled_message_ids.size());
++i) {
AddConversationStarter(shuffled_message_ids[i]);
}
model_.SetConversationStarters(std::move(conversation_starters));
}
} // namespace ash