assistant_controller_impl.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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_controller_impl.h"
  5. #include <algorithm>
  6. #include <utility>
  7. #include "ash/accessibility/accessibility_controller_impl.h"
  8. #include "ash/assistant/util/deep_link_util.h"
  9. #include "ash/capture_mode/capture_mode_controller.h"
  10. #include "ash/constants/ash_features.h"
  11. #include "ash/public/cpp/android_intent_helper.h"
  12. #include "ash/public/cpp/new_window_delegate.h"
  13. #include "ash/public/mojom/assistant_volume_control.mojom.h"
  14. #include "ash/session/session_controller_impl.h"
  15. #include "ash/shell.h"
  16. #include "base/bind.h"
  17. #include "base/memory/scoped_refptr.h"
  18. #include "chromeos/ash/services/assistant/public/cpp/assistant_browser_delegate.h"
  19. #include "chromeos/ash/services/assistant/public/cpp/assistant_prefs.h"
  20. #include "chromeos/ash/services/assistant/public/cpp/assistant_service.h"
  21. #include "chromeos/ash/services/assistant/public/cpp/features.h"
  22. #include "chromeos/services/libassistant/public/cpp/assistant_feedback.h"
  23. #include "components/prefs/pref_registry_simple.h"
  24. #include "net/traffic_annotation/network_traffic_annotation.h"
  25. #include "url/gurl.h"
  26. namespace ash {
  27. AssistantControllerImpl::AssistantControllerImpl() {
  28. assistant_state_controller_.AddObserver(this);
  29. CrasAudioHandler::Get()->AddAudioObserver(this);
  30. AddObserver(this);
  31. // The Assistant service needs to have accessibility state synced with ash
  32. // and be notified of any accessibility status changes in the future to
  33. // provide an opportunity to turn on/off A11Y features.
  34. Shell::Get()->accessibility_controller()->AddObserver(this);
  35. color_mode_observer_.Observe(DarkLightModeControllerImpl::Get());
  36. NotifyConstructed();
  37. }
  38. AssistantControllerImpl::~AssistantControllerImpl() {
  39. NotifyDestroying();
  40. CrasAudioHandler::Get()->RemoveAudioObserver(this);
  41. Shell::Get()->accessibility_controller()->RemoveObserver(this);
  42. assistant_state_controller_.RemoveObserver(this);
  43. RemoveObserver(this);
  44. }
  45. // static
  46. void AssistantControllerImpl::RegisterProfilePrefs(
  47. PrefRegistrySimple* registry) {
  48. AssistantInteractionControllerImpl::RegisterProfilePrefs(registry);
  49. AssistantUiControllerImpl::RegisterProfilePrefs(registry);
  50. }
  51. void AssistantControllerImpl::BindReceiver(
  52. mojo::PendingReceiver<mojom::AssistantVolumeControl> receiver) {
  53. assistant_volume_control_receiver_.Bind(std::move(receiver));
  54. }
  55. void AssistantControllerImpl::SetAssistant(assistant::Assistant* assistant) {
  56. assistant_ = assistant;
  57. // Provide reference to sub-controllers.
  58. assistant_alarm_timer_controller_.SetAssistant(assistant);
  59. assistant_interaction_controller_.SetAssistant(assistant);
  60. assistant_notification_controller_.SetAssistant(assistant);
  61. assistant_ui_controller_.SetAssistant(assistant);
  62. OnAccessibilityStatusChanged();
  63. bool dark_mode_enabled = false;
  64. if (ash::features::IsProductivityLauncherEnabled() ||
  65. ash::features::IsDarkLightModeEnabled()) {
  66. dark_mode_enabled = DarkLightModeControllerImpl::Get()->IsDarkModeEnabled();
  67. }
  68. OnColorModeChanged(dark_mode_enabled);
  69. if (assistant) {
  70. for (AssistantControllerObserver& observer : observers_)
  71. observer.OnAssistantReady();
  72. }
  73. }
  74. void AssistantControllerImpl::SendAssistantFeedback(
  75. bool assistant_debug_info_allowed,
  76. const std::string& feedback_description,
  77. const std::string& screenshot_png) {
  78. chromeos::assistant::AssistantFeedback assistant_feedback;
  79. assistant_feedback.assistant_debug_info_allowed =
  80. assistant_debug_info_allowed;
  81. assistant_feedback.description = feedback_description;
  82. assistant_feedback.screenshot_png =
  83. std::vector<uint8_t>(screenshot_png.begin(), screenshot_png.end());
  84. assistant_->SendAssistantFeedback(std::move(assistant_feedback));
  85. }
  86. void AssistantControllerImpl::StartSpeakerIdEnrollmentFlow() {
  87. setup_controller()->StartOnboarding(false /* relaunch */,
  88. FlowType::kSpeakerIdEnrollment);
  89. }
  90. void AssistantControllerImpl::DownloadImage(
  91. const GURL& url,
  92. ImageDownloader::DownloadCallback callback) {
  93. constexpr net::NetworkTrafficAnnotationTag kNetworkTrafficAnnotationTag =
  94. net::DefineNetworkTrafficAnnotation("image_downloader", R"(
  95. semantics {
  96. sender: "Google Assistant"
  97. description:
  98. "The Google Assistant requires dynamic loading of images to "
  99. "provide a media rich user experience. Images are downloaded "
  100. "on an as needed basis."
  101. trigger:
  102. "Generally triggered in direct response to a user issued "
  103. "query. A single query may necessitate the downloading of "
  104. "multiple images."
  105. data: "None."
  106. destination: GOOGLE_OWNED_SERVICE
  107. }
  108. policy {
  109. cookies_allowed: NO
  110. setting:
  111. "The Google Assistant can be enabled/disabled in Chrome "
  112. "Settings and is subject to eligibility requirements."
  113. policy_exception_justification:
  114. "The users can disable this feature. This does not send/store "
  115. "user data."
  116. })");
  117. ImageDownloader::Get()->Download(url, kNetworkTrafficAnnotationTag,
  118. std::move(callback));
  119. }
  120. void AssistantControllerImpl::AddObserver(
  121. AssistantControllerObserver* observer) {
  122. observers_.AddObserver(observer);
  123. }
  124. void AssistantControllerImpl::RemoveObserver(
  125. AssistantControllerObserver* observer) {
  126. observers_.RemoveObserver(observer);
  127. }
  128. void AssistantControllerImpl::OpenUrl(const GURL& url,
  129. bool in_background,
  130. bool from_server) {
  131. // app_list search result will be opened by `OpenUrl()`. However, the
  132. // `assistant_` may not be ready. Show a toast to indicate it.
  133. if (!assistant_) {
  134. assistant_ui_controller_.ShowUnboundErrorToast();
  135. return;
  136. }
  137. if (assistant::util::IsDeepLinkUrl(url)) {
  138. NotifyDeepLinkReceived(url);
  139. return;
  140. }
  141. auto* android_helper = AndroidIntentHelper::GetInstance();
  142. if (IsAndroidIntent(url) && !android_helper) {
  143. NOTREACHED();
  144. return;
  145. }
  146. // Give observers an opportunity to perform any necessary handling before we
  147. // open the specified |url| in a new browser tab.
  148. NotifyOpeningUrl(url, in_background, from_server);
  149. if (IsAndroidIntent(url)) {
  150. android_helper->LaunchAndroidIntent(url.spec());
  151. } else {
  152. assistant::AssistantBrowserDelegate::Get()->OpenUrl(url);
  153. }
  154. NotifyUrlOpened(url, from_server);
  155. }
  156. void AssistantControllerImpl::OpenAssistantSettings() {
  157. // Launch Assistant settings via deeplink.
  158. OpenUrl(assistant::util::CreateAssistantSettingsDeepLink(),
  159. /*in_background=*/false, /*from_server=*/false);
  160. }
  161. base::WeakPtr<ash::AssistantController> AssistantControllerImpl::GetWeakPtr() {
  162. return weak_factory_.GetWeakPtr();
  163. }
  164. void AssistantControllerImpl::OnDeepLinkReceived(
  165. assistant::util::DeepLinkType type,
  166. const std::map<std::string, std::string>& params) {
  167. using assistant::util::DeepLinkParam;
  168. using assistant::util::DeepLinkType;
  169. switch (type) {
  170. case DeepLinkType::kChromeSettings: {
  171. // Chrome Settings deep links are opened in a new browser tab.
  172. OpenUrl(
  173. assistant::util::GetChromeSettingsUrl(
  174. assistant::util::GetDeepLinkParam(params, DeepLinkParam::kPage)),
  175. /*in_background=*/false, /*from_server=*/false);
  176. break;
  177. }
  178. case DeepLinkType::kFeedback:
  179. NewWindowDelegate::GetInstance()->OpenFeedbackPage(
  180. NewWindowDelegate::FeedbackSource::kFeedbackSourceAssistant);
  181. // Close the assistant UI so that the feedback page is visible.
  182. assistant_ui_controller_.CloseUi(
  183. assistant::AssistantExitPoint::kUnspecified);
  184. break;
  185. case DeepLinkType::kScreenshot:
  186. // We close the UI before taking the screenshot as it's probably not the
  187. // user's intention to include the Assistant in the picture.
  188. assistant_ui_controller_.CloseUi(
  189. assistant::AssistantExitPoint::kScreenshot);
  190. CaptureModeController::Get()->CaptureScreenshotsOfAllDisplays();
  191. break;
  192. case DeepLinkType::kTaskManager:
  193. // Open task manager window.
  194. NewWindowDelegate::GetInstance()->ShowTaskManager();
  195. break;
  196. case DeepLinkType::kUnsupported:
  197. case DeepLinkType::kAlarmTimer:
  198. case DeepLinkType::kLists:
  199. case DeepLinkType::kNotes:
  200. case DeepLinkType::kOnboarding:
  201. case DeepLinkType::kQuery:
  202. case DeepLinkType::kReminders:
  203. case DeepLinkType::kSettings:
  204. // No action needed.
  205. break;
  206. }
  207. }
  208. void AssistantControllerImpl::SetVolume(int volume, bool user_initiated) {
  209. volume = std::min(100, volume);
  210. volume = std::max(volume, 0);
  211. CrasAudioHandler::Get()->SetOutputVolumePercent(volume);
  212. }
  213. void AssistantControllerImpl::SetMuted(bool muted) {
  214. CrasAudioHandler::Get()->SetOutputMute(muted);
  215. }
  216. void AssistantControllerImpl::AddVolumeObserver(
  217. mojo::PendingRemote<mojom::VolumeObserver> observer) {
  218. volume_observers_.Add(std::move(observer));
  219. int output_volume = CrasAudioHandler::Get()->GetOutputVolumePercent();
  220. bool mute = CrasAudioHandler::Get()->IsOutputMuted();
  221. OnOutputMuteChanged(mute);
  222. OnOutputNodeVolumeChanged(0 /* node */, output_volume);
  223. }
  224. void AssistantControllerImpl::OnOutputMuteChanged(bool mute_on) {
  225. for (auto& observer : volume_observers_)
  226. observer->OnMuteStateChanged(mute_on);
  227. }
  228. void AssistantControllerImpl::OnOutputNodeVolumeChanged(uint64_t node,
  229. int volume) {
  230. // |node| refers to the active volume device, which we don't care here.
  231. for (auto& observer : volume_observers_)
  232. observer->OnVolumeChanged(volume);
  233. }
  234. void AssistantControllerImpl::OnAccessibilityStatusChanged() {
  235. if (!assistant_)
  236. return;
  237. // The Assistant service needs to be informed of changes to accessibility
  238. // state so that it can turn on/off A11Y features appropriately.
  239. assistant_->OnAccessibilityStatusChanged(
  240. Shell::Get()->accessibility_controller()->spoken_feedback().enabled());
  241. }
  242. void AssistantControllerImpl::OnColorModeChanged(bool dark_mode_enabled) {
  243. if (!assistant_)
  244. return;
  245. assistant_->OnColorModeChanged(dark_mode_enabled);
  246. }
  247. bool AssistantControllerImpl::IsAssistantReady() const {
  248. return !!assistant_;
  249. }
  250. void AssistantControllerImpl::NotifyConstructed() {
  251. for (AssistantControllerObserver& observer : observers_)
  252. observer.OnAssistantControllerConstructed();
  253. }
  254. void AssistantControllerImpl::NotifyDestroying() {
  255. for (AssistantControllerObserver& observer : observers_)
  256. observer.OnAssistantControllerDestroying();
  257. }
  258. void AssistantControllerImpl::NotifyDeepLinkReceived(const GURL& deep_link) {
  259. using assistant::util::DeepLinkType;
  260. // Retrieve deep link type and parsed parameters.
  261. DeepLinkType type = assistant::util::GetDeepLinkType(deep_link);
  262. const std::map<std::string, std::string> params =
  263. assistant::util::GetDeepLinkParams(deep_link);
  264. for (AssistantControllerObserver& observer : observers_)
  265. observer.OnDeepLinkReceived(type, params);
  266. }
  267. void AssistantControllerImpl::NotifyOpeningUrl(const GURL& url,
  268. bool in_background,
  269. bool from_server) {
  270. for (AssistantControllerObserver& observer : observers_)
  271. observer.OnOpeningUrl(url, in_background, from_server);
  272. }
  273. void AssistantControllerImpl::NotifyUrlOpened(const GURL& url,
  274. bool from_server) {
  275. for (AssistantControllerObserver& observer : observers_)
  276. observer.OnUrlOpened(url, from_server);
  277. }
  278. void AssistantControllerImpl::OnAssistantStatusChanged(
  279. assistant::AssistantStatus status) {
  280. if (status == assistant::AssistantStatus::NOT_READY)
  281. assistant_ui_controller_.CloseUi(
  282. assistant::AssistantExitPoint::kUnspecified);
  283. }
  284. void AssistantControllerImpl::OnLockedFullScreenStateChanged(bool enabled) {
  285. if (enabled)
  286. assistant_ui_controller_.CloseUi(
  287. assistant::AssistantExitPoint::kUnspecified);
  288. }
  289. void AssistantControllerImpl::BindVolumeControl(
  290. mojo::PendingReceiver<mojom::AssistantVolumeControl> receiver) {
  291. Shell::Get()->assistant_controller()->BindReceiver(std::move(receiver));
  292. }
  293. } // namespace ash