assistant_suggestions_controller_impl.cc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/assistant/assistant_suggestions_controller_impl.h"
  5. #include <algorithm>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "ash/assistant/model/assistant_ui_model.h"
  10. #include "ash/assistant/util/assistant_util.h"
  11. #include "ash/assistant/util/deep_link_util.h"
  12. #include "ash/assistant/util/resource_util.h"
  13. #include "ash/public/cpp/assistant/controller/assistant_ui_controller.h"
  14. #include "ash/shell.h"
  15. #include "ash/strings/grit/ash_strings.h"
  16. #include "base/bind.h"
  17. #include "base/containers/cxx20_erase.h"
  18. #include "base/rand_util.h"
  19. #include "base/unguessable_token.h"
  20. #include "chromeos/ash/services/assistant/public/cpp/assistant_prefs.h"
  21. #include "chromeos/ash/services/assistant/public/cpp/features.h"
  22. #include "chromeos/services/libassistant/public/cpp/assistant_suggestion.h"
  23. #include "ui/base/l10n/l10n_util.h"
  24. namespace ash {
  25. namespace {
  26. using assistant::prefs::AssistantOnboardingMode;
  27. using chromeos::assistant::AssistantSuggestion;
  28. using chromeos::assistant::AssistantSuggestionType;
  29. // Conversation starters -------------------------------------------------------
  30. constexpr int kMaxNumOfConversationStarters = 3;
  31. } // namespace
  32. // AssistantSuggestionsControllerImpl ------------------------------------------
  33. AssistantSuggestionsControllerImpl::AssistantSuggestionsControllerImpl() {
  34. UpdateConversationStarters();
  35. assistant_controller_observation_.Observe(AssistantController::Get());
  36. }
  37. AssistantSuggestionsControllerImpl::~AssistantSuggestionsControllerImpl() =
  38. default;
  39. const AssistantSuggestionsModel* AssistantSuggestionsControllerImpl::GetModel()
  40. const {
  41. return &model_;
  42. }
  43. void AssistantSuggestionsControllerImpl::OnAssistantControllerConstructed() {
  44. AssistantUiController::Get()->GetModel()->AddObserver(this);
  45. AssistantState::Get()->AddObserver(this);
  46. }
  47. void AssistantSuggestionsControllerImpl::OnAssistantControllerDestroying() {
  48. AssistantState::Get()->RemoveObserver(this);
  49. AssistantUiController::Get()->GetModel()->RemoveObserver(this);
  50. }
  51. void AssistantSuggestionsControllerImpl::OnUiVisibilityChanged(
  52. AssistantVisibility new_visibility,
  53. AssistantVisibility old_visibility,
  54. absl::optional<AssistantEntryPoint> entry_point,
  55. absl::optional<AssistantExitPoint> exit_point) {
  56. // When Assistant is finishing a session, we update our cache of conversation
  57. // starters so that they're fresh for the next launch.
  58. if (assistant::util::IsFinishingSession(new_visibility))
  59. UpdateConversationStarters();
  60. }
  61. void AssistantSuggestionsControllerImpl::OnAssistantContextEnabled(
  62. bool enabled) {
  63. // We currently assume that the context setting is not being modified while
  64. // Assistant UI is visible.
  65. DCHECK_NE(AssistantVisibility::kVisible,
  66. AssistantUiController::Get()->GetModel()->visibility());
  67. UpdateConversationStarters();
  68. }
  69. void AssistantSuggestionsControllerImpl::OnAssistantOnboardingModeChanged(
  70. AssistantOnboardingMode onboarding_mode) {
  71. UpdateOnboardingSuggestions();
  72. }
  73. void AssistantSuggestionsControllerImpl::UpdateConversationStarters() {
  74. std::vector<AssistantSuggestion> conversation_starters;
  75. // Adds a conversation starter for the given |message_id| and |action_url|.
  76. auto AddConversationStarter = [&conversation_starters](
  77. int message_id, GURL action_url = GURL()) {
  78. AssistantSuggestion starter;
  79. starter.id = base::UnguessableToken::Create();
  80. starter.type = AssistantSuggestionType::kConversationStarter;
  81. starter.text = l10n_util::GetStringUTF8(message_id);
  82. starter.action_url = action_url;
  83. conversation_starters.push_back(std::move(starter));
  84. };
  85. // Always show the "What can you do?" conversation starter.
  86. AddConversationStarter(IDS_ASH_ASSISTANT_CHIP_WHAT_CAN_YOU_DO);
  87. // The rest of the conversation starters will be shuffled...
  88. std::vector<int> shuffled_message_ids;
  89. shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_IM_BORED);
  90. shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_OPEN_FILES);
  91. shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_PLAY_MUSIC);
  92. shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_SEND_AN_EMAIL);
  93. shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_SET_A_REMINDER);
  94. shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_TELL_ME_A_JOKE);
  95. shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_WHATS_ON_MY_CALENDAR);
  96. shuffled_message_ids.push_back(IDS_ASH_ASSISTANT_CHIP_WHATS_THE_WEATHER);
  97. base::RandomShuffle(shuffled_message_ids.begin(), shuffled_message_ids.end());
  98. // ...and added until we have no more than |kMaxNumOfConversationStarters|.
  99. for (int i = 0;
  100. conversation_starters.size() < kMaxNumOfConversationStarters &&
  101. i < static_cast<int>(shuffled_message_ids.size());
  102. ++i) {
  103. AddConversationStarter(shuffled_message_ids[i]);
  104. }
  105. model_.SetConversationStarters(std::move(conversation_starters));
  106. }
  107. void AssistantSuggestionsControllerImpl::UpdateOnboardingSuggestions() {
  108. auto CreateIconResourceLink = [](int message_id) {
  109. switch (message_id) {
  110. case IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_CONVERSION:
  111. return assistant::util::CreateIconResourceLink(
  112. assistant::util::IconName::kConversionPath);
  113. case IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_KNOWLEDGE:
  114. return assistant::util::CreateIconResourceLink(
  115. assistant::util::IconName::kPersonPinCircle);
  116. case IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_KNOWLEDGE_EDU:
  117. return assistant::util::CreateIconResourceLink(
  118. assistant::util::IconName::kStraighten);
  119. case IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_LANGUAGE:
  120. return assistant::util::CreateIconResourceLink(
  121. assistant::util::IconName::kTranslate);
  122. case IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_MATH:
  123. return assistant::util::CreateIconResourceLink(
  124. assistant::util::IconName::kCalculate);
  125. case IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_PERSONALITY:
  126. return assistant::util::CreateIconResourceLink(
  127. assistant::util::IconName::kSentimentVerySatisfied);
  128. case IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_PRODUCTIVITY:
  129. return assistant::util::CreateIconResourceLink(
  130. assistant::util::IconName::kTimer);
  131. case IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_TECHNICAL:
  132. return assistant::util::CreateIconResourceLink(
  133. assistant::util::IconName::kScreenshot);
  134. default:
  135. NOTREACHED();
  136. return GURL();
  137. }
  138. };
  139. std::vector<AssistantSuggestion> onboarding_suggestions;
  140. using chromeos::assistant::AssistantBetterOnboardingType;
  141. auto AddSuggestion = [&CreateIconResourceLink, &onboarding_suggestions](
  142. int message_id, AssistantBetterOnboardingType type) {
  143. onboarding_suggestions.emplace_back();
  144. auto& suggestion = onboarding_suggestions.back();
  145. suggestion.id = base::UnguessableToken::Create();
  146. suggestion.type = AssistantSuggestionType::kBetterOnboarding;
  147. suggestion.better_onboarding_type = type;
  148. suggestion.text = l10n_util::GetStringUTF8(message_id);
  149. suggestion.icon_url = CreateIconResourceLink(message_id);
  150. suggestion.action_url = GURL();
  151. };
  152. switch (AssistantState::Get()->onboarding_mode().value_or(
  153. AssistantOnboardingMode::kDefault)) {
  154. case AssistantOnboardingMode::kEducation:
  155. AddSuggestion(IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_MATH,
  156. AssistantBetterOnboardingType::kMath);
  157. AddSuggestion(IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_KNOWLEDGE_EDU,
  158. AssistantBetterOnboardingType::kKnowledgeEdu);
  159. break;
  160. case AssistantOnboardingMode::kDefault:
  161. AddSuggestion(IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_CONVERSION,
  162. AssistantBetterOnboardingType::kConversion);
  163. AddSuggestion(IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_KNOWLEDGE,
  164. AssistantBetterOnboardingType::kKnowledge);
  165. break;
  166. }
  167. AddSuggestion(IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_PRODUCTIVITY,
  168. AssistantBetterOnboardingType::kProductivity);
  169. AddSuggestion(IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_PERSONALITY,
  170. AssistantBetterOnboardingType::kPersonality);
  171. AddSuggestion(IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_LANGUAGE,
  172. AssistantBetterOnboardingType::kLanguage);
  173. AddSuggestion(IDS_ASH_ASSISTANT_ONBOARDING_SUGGESTION_TECHNICAL,
  174. AssistantBetterOnboardingType::kTechnical);
  175. model_.SetOnboardingSuggestions(std::move(onboarding_suggestions));
  176. }
  177. } // namespace ash