ambient_backend_controller_impl.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. // Copyright 2020 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/ambient/backdrop/ambient_backend_controller_impl.h"
  5. #include <array>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "ash/ambient/ambient_controller.h"
  10. #include "ash/ambient/util/ambient_util.h"
  11. #include "ash/constants/ash_features.h"
  12. #include "ash/public/cpp/ambient/ambient_backend_controller.h"
  13. #include "ash/public/cpp/ambient/ambient_client.h"
  14. #include "ash/public/cpp/ambient/ambient_metrics.h"
  15. #include "ash/public/cpp/ambient/ambient_prefs.h"
  16. #include "ash/public/cpp/ambient/common/ambient_settings.h"
  17. #include "ash/public/cpp/ambient/proto/photo_cache_entry.pb.h"
  18. #include "ash/session/session_controller_impl.h"
  19. #include "ash/shell.h"
  20. #include "base/barrier_closure.h"
  21. #include "base/base64.h"
  22. #include "base/bind.h"
  23. #include "base/guid.h"
  24. #include "base/logging.h"
  25. #include "base/time/time.h"
  26. #include "chromeos/assistant/internal/ambient/backdrop_client_config.h"
  27. #include "chromeos/assistant/internal/proto/backdrop/backdrop.pb.h"
  28. #include "chromeos/assistant/internal/proto/backdrop/imax_service.pb.h"
  29. #include "components/prefs/pref_service.h"
  30. #include "components/user_manager/user_manager.h"
  31. #include "net/base/load_flags.h"
  32. #include "net/base/net_errors.h"
  33. #include "net/base/url_util.h"
  34. #include "net/traffic_annotation/network_traffic_annotation.h"
  35. #include "services/data_decoder/public/cpp/data_decoder.h"
  36. #include "services/network/public/cpp/resource_request.h"
  37. #include "services/network/public/cpp/shared_url_loader_factory.h"
  38. #include "services/network/public/cpp/simple_url_loader.h"
  39. #include "services/network/public/mojom/url_response_head.mojom.h"
  40. #include "third_party/abseil-cpp/absl/types/optional.h"
  41. #include "url/gurl.h"
  42. namespace ash {
  43. namespace {
  44. using BackdropClientConfig = chromeos::ambient::BackdropClientConfig;
  45. constexpr char kProtoMimeType[] = "application/protobuf";
  46. // Max body size in bytes to download.
  47. constexpr int kMaxBodySizeBytes = 1 * 1024 * 1024; // 1 MiB
  48. std::string GetClientId() {
  49. PrefService* prefs =
  50. Shell::Get()->session_controller()->GetPrimaryUserPrefService();
  51. DCHECK(prefs);
  52. std::string client_id =
  53. prefs->GetString(ambient::prefs::kAmbientBackdropClientId);
  54. if (client_id.empty()) {
  55. client_id = base::GenerateGUID();
  56. prefs->SetString(ambient::prefs::kAmbientBackdropClientId, client_id);
  57. }
  58. return client_id;
  59. }
  60. std::unique_ptr<network::ResourceRequest> CreateResourceRequest(
  61. const BackdropClientConfig::Request& request) {
  62. auto resource_request = std::make_unique<network::ResourceRequest>();
  63. resource_request->url = GURL(request.url);
  64. resource_request->method = request.method;
  65. resource_request->load_flags =
  66. net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE;
  67. resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
  68. for (const auto& header : request.headers) {
  69. std::string encoded_value;
  70. if (header.needs_base_64_encoded)
  71. base::Base64Encode(header.value, &encoded_value);
  72. else
  73. encoded_value = header.value;
  74. resource_request->headers.SetHeader(header.name, encoded_value);
  75. }
  76. return resource_request;
  77. }
  78. std::string BuildBackdropTopicDetails(
  79. const backdrop::ScreenUpdate::Topic& backdrop_topic) {
  80. std::string result;
  81. if (backdrop_topic.has_metadata_line_1())
  82. result += backdrop_topic.metadata_line_1();
  83. if (backdrop_topic.has_metadata_line_2()) {
  84. if (!result.empty())
  85. result += " ";
  86. result += backdrop_topic.metadata_line_2();
  87. }
  88. // Do not include metadata_line_3.
  89. return result;
  90. }
  91. ::ambient::TopicType ToAmbientModeTopicType(
  92. const backdrop::ScreenUpdate_Topic& topic) {
  93. if (!topic.has_topic_type())
  94. return ::ambient::TopicType::kOther;
  95. switch (topic.topic_type()) {
  96. case backdrop::CURATED:
  97. return ::ambient::TopicType::kCurated;
  98. case backdrop::PERSONAL_PHOTO:
  99. return ::ambient::TopicType::kPersonal;
  100. case backdrop::FEATURED_PHOTO:
  101. return ::ambient::TopicType::kFeatured;
  102. case backdrop::GEO_PHOTO:
  103. return ::ambient::TopicType::kGeo;
  104. case backdrop::CULTURAL_INSTITUTE:
  105. return ::ambient::TopicType::kCulturalInstitute;
  106. case backdrop::RSS_TOPIC:
  107. return ::ambient::TopicType::kRss;
  108. case backdrop::CAPTURED_ON_PIXEL:
  109. return ::ambient::TopicType::kCapturedOnPixel;
  110. default:
  111. return ::ambient::TopicType::kOther;
  112. }
  113. }
  114. absl::optional<std::string> GetStringValue(const base::Value::List& values,
  115. size_t field_number) {
  116. if (values.empty() || values.size() < field_number)
  117. return absl::nullopt;
  118. const base::Value& v = values[field_number - 1];
  119. if (!v.is_string())
  120. return absl::nullopt;
  121. return v.GetString();
  122. }
  123. absl::optional<double> GetDoubleValue(const base::Value::List& values,
  124. size_t field_number) {
  125. if (values.empty() || values.size() < field_number)
  126. return absl::nullopt;
  127. const base::Value& v = values[field_number - 1];
  128. if (!v.is_double() && !v.is_int())
  129. return absl::nullopt;
  130. return v.GetDouble();
  131. }
  132. absl::optional<bool> GetBoolValue(const base::Value::List& values,
  133. size_t field_number) {
  134. if (values.empty() || values.size() < field_number)
  135. return absl::nullopt;
  136. const base::Value& v = values[field_number - 1];
  137. if (v.is_bool())
  138. return v.GetBool();
  139. if (v.is_int())
  140. return v.GetInt() > 0;
  141. return absl::nullopt;
  142. }
  143. absl::optional<WeatherInfo> ToWeatherInfo(const base::Value& result) {
  144. DCHECK(result.is_list());
  145. if (!result.is_list())
  146. return absl::nullopt;
  147. WeatherInfo weather_info;
  148. const auto& list_result = result.GetList();
  149. weather_info.condition_icon_url = GetStringValue(
  150. list_result, backdrop::WeatherInfo::kConditionIconUrlFieldNumber);
  151. weather_info.temp_f =
  152. GetDoubleValue(list_result, backdrop::WeatherInfo::kTempFFieldNumber);
  153. weather_info.show_celsius =
  154. GetBoolValue(list_result, backdrop::WeatherInfo::kShowCelsiusFieldNumber)
  155. .value_or(false);
  156. return weather_info;
  157. }
  158. // Helper function to save the information we got from the backdrop server to a
  159. // public struct so that they can be accessed by public codes.
  160. ScreenUpdate ToScreenUpdate(
  161. const backdrop::ScreenUpdate& backdrop_screen_update) {
  162. ScreenUpdate screen_update;
  163. // Parse |AmbientModeTopic|.
  164. int topics_size = backdrop_screen_update.next_topics_size();
  165. if (topics_size > 0) {
  166. for (auto& backdrop_topic : backdrop_screen_update.next_topics()) {
  167. DCHECK(backdrop_topic.has_url());
  168. auto topic_type = ToAmbientModeTopicType(backdrop_topic);
  169. if (!ambient::util::IsAmbientModeTopicTypeAllowed(topic_type)) {
  170. DVLOG(3) << "Filtering topic_type: "
  171. << backdrop::TopicSource_Name(backdrop_topic.topic_type());
  172. continue;
  173. }
  174. AmbientModeTopic ambient_topic;
  175. ambient_topic.topic_type = topic_type;
  176. // If the |portrait_image_url| field is not empty, we assume the image is
  177. // portrait.
  178. if (backdrop_topic.has_portrait_image_url()) {
  179. ambient_topic.url = backdrop_topic.portrait_image_url();
  180. ambient_topic.is_portrait = true;
  181. } else {
  182. ambient_topic.url = backdrop_topic.url();
  183. }
  184. if (backdrop_topic.has_related_topic()) {
  185. if (backdrop_topic.related_topic().has_portrait_image_url()) {
  186. ambient_topic.related_image_url =
  187. backdrop_topic.related_topic().portrait_image_url();
  188. } else {
  189. ambient_topic.related_image_url =
  190. backdrop_topic.related_topic().url();
  191. }
  192. }
  193. ambient_topic.details = BuildBackdropTopicDetails(backdrop_topic);
  194. ambient_topic.related_details =
  195. BuildBackdropTopicDetails(backdrop_topic.related_topic());
  196. screen_update.next_topics.emplace_back(ambient_topic);
  197. }
  198. }
  199. // Parse |WeatherInfo|.
  200. if (backdrop_screen_update.has_weather_info()) {
  201. backdrop::WeatherInfo backdrop_weather_info =
  202. backdrop_screen_update.weather_info();
  203. WeatherInfo weather_info;
  204. if (backdrop_weather_info.has_condition_icon_url()) {
  205. weather_info.condition_icon_url =
  206. backdrop_weather_info.condition_icon_url();
  207. }
  208. if (backdrop_weather_info.has_temp_f())
  209. weather_info.temp_f = backdrop_weather_info.temp_f();
  210. if (backdrop_weather_info.has_show_celsius())
  211. weather_info.show_celsius = backdrop_weather_info.show_celsius();
  212. screen_update.weather_info = weather_info;
  213. }
  214. return screen_update;
  215. }
  216. bool IsArtSettingVisible(const ArtSetting& art_setting) {
  217. const auto& album_id = art_setting.album_id;
  218. if (album_id == kAmbientModeStreetArtAlbumId)
  219. return chromeos::features::kAmbientModeStreetArtAlbumEnabled.Get();
  220. if (album_id == kAmbientModeCapturedOnPixelAlbumId)
  221. return chromeos::features::kAmbientModeCapturedOnPixelAlbumEnabled.Get();
  222. if (album_id == kAmbientModeEarthAndSpaceAlbumId)
  223. return chromeos::features::kAmbientModeEarthAndSpaceAlbumEnabled.Get();
  224. if (album_id == kAmbientModeFeaturedPhotoAlbumId)
  225. return chromeos::features::kAmbientModeFeaturedPhotoAlbumEnabled.Get();
  226. if (album_id == kAmbientModeFineArtAlbumId)
  227. return chromeos::features::kAmbientModeFineArtAlbumEnabled.Get();
  228. return false;
  229. }
  230. } // namespace
  231. // Helper class for handling Backdrop service requests.
  232. class BackdropURLLoader {
  233. public:
  234. BackdropURLLoader() = default;
  235. BackdropURLLoader(const BackdropURLLoader&) = delete;
  236. BackdropURLLoader& operator=(const BackdropURLLoader&) = delete;
  237. ~BackdropURLLoader() = default;
  238. // Starts downloading the proto. |request_body| is a serialized proto and
  239. // will be used as the upload body if it is a POST request.
  240. void Start(std::unique_ptr<network::ResourceRequest> resource_request,
  241. const absl::optional<std::string>& request_body,
  242. const net::NetworkTrafficAnnotationTag& traffic_annotation,
  243. network::SimpleURLLoader::BodyAsStringCallback callback) {
  244. // No ongoing downloading task.
  245. DCHECK(!simple_loader_);
  246. loader_factory_ = AmbientClient::Get()->GetURLLoaderFactory();
  247. simple_loader_ = network::SimpleURLLoader::Create(
  248. std::move(resource_request), traffic_annotation);
  249. if (request_body)
  250. simple_loader_->AttachStringForUpload(*request_body, kProtoMimeType);
  251. // |base::Unretained| is safe because this instance outlives
  252. // |simple_loader_|.
  253. simple_loader_->DownloadToString(
  254. loader_factory_.get(),
  255. base::BindOnce(&BackdropURLLoader::OnUrlDownloaded,
  256. base::Unretained(this), std::move(callback)),
  257. kMaxBodySizeBytes);
  258. }
  259. private:
  260. // Called when the download completes.
  261. void OnUrlDownloaded(network::SimpleURLLoader::BodyAsStringCallback callback,
  262. std::unique_ptr<std::string> response_body) {
  263. loader_factory_.reset();
  264. if (simple_loader_->NetError() == net::OK && response_body) {
  265. simple_loader_.reset();
  266. std::move(callback).Run(std::move(response_body));
  267. return;
  268. }
  269. int response_code = -1;
  270. if (simple_loader_->ResponseInfo() &&
  271. simple_loader_->ResponseInfo()->headers) {
  272. response_code = simple_loader_->ResponseInfo()->headers->response_code();
  273. }
  274. LOG(ERROR) << "Downloading Backdrop proto failed with error code: "
  275. << response_code << " with network error"
  276. << simple_loader_->NetError();
  277. simple_loader_.reset();
  278. std::move(callback).Run(std::make_unique<std::string>());
  279. }
  280. std::unique_ptr<network::SimpleURLLoader> simple_loader_;
  281. scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
  282. };
  283. AmbientBackendControllerImpl::AmbientBackendControllerImpl()
  284. : backdrop_client_config_(ash::AmbientClient::Get()->ShouldUseProdServer()
  285. ? BackdropClientConfig::ServerType::kProd
  286. : BackdropClientConfig::ServerType::kDev) {}
  287. AmbientBackendControllerImpl::~AmbientBackendControllerImpl() = default;
  288. void AmbientBackendControllerImpl::FetchScreenUpdateInfo(
  289. int num_topics,
  290. bool show_pair_personal_portraits,
  291. const gfx::Size& screen_size,
  292. OnScreenUpdateInfoFetchedCallback callback) {
  293. Shell::Get()->ambient_controller()->RequestAccessToken(base::BindOnce(
  294. &AmbientBackendControllerImpl::FetchScreenUpdateInfoInternal,
  295. weak_factory_.GetWeakPtr(), num_topics, show_pair_personal_portraits,
  296. screen_size, std::move(callback)));
  297. }
  298. void AmbientBackendControllerImpl::GetSettings(GetSettingsCallback callback) {
  299. Shell::Get()->ambient_controller()->RequestAccessToken(
  300. base::BindOnce(&AmbientBackendControllerImpl::StartToGetSettings,
  301. weak_factory_.GetWeakPtr(), std::move(callback)));
  302. }
  303. void AmbientBackendControllerImpl::UpdateSettings(
  304. const AmbientSettings& settings,
  305. UpdateSettingsCallback callback) {
  306. auto* ambient_controller = Shell::Get()->ambient_controller();
  307. // Clear disk cache when Settings changes.
  308. // TODO(wutao): Use observer pattern. Need to future narrow down
  309. // the clear up only on albums changes, not on temperature unit
  310. // changes. Do this synchronously and not in |OnUpdateSettings| to avoid
  311. // race condition with |AmbientPhotoController| possibly being destructed if
  312. // |kAmbientModeEnabled| pref is toggled off.
  313. auto* photo_controller = ambient_controller->ambient_photo_controller();
  314. CHECK(photo_controller) << "Photo controller is required to update settings";
  315. photo_controller->ClearCache();
  316. ambient_controller->RequestAccessToken(base::BindOnce(
  317. &AmbientBackendControllerImpl::StartToUpdateSettings,
  318. weak_factory_.GetWeakPtr(), settings, std::move(callback)));
  319. }
  320. void AmbientBackendControllerImpl::FetchPersonalAlbums(
  321. int banner_width,
  322. int banner_height,
  323. int num_albums,
  324. const std::string& resume_token,
  325. OnPersonalAlbumsFetchedCallback callback) {
  326. Shell::Get()->ambient_controller()->RequestAccessToken(
  327. base::BindOnce(&AmbientBackendControllerImpl::FetchPersonalAlbumsInternal,
  328. weak_factory_.GetWeakPtr(), banner_width, banner_height,
  329. num_albums, resume_token, std::move(callback)));
  330. }
  331. void AmbientBackendControllerImpl::FetchWeather(FetchWeatherCallback callback) {
  332. auto response_handler =
  333. [](FetchWeatherCallback callback,
  334. std::unique_ptr<BackdropURLLoader> backdrop_url_loader,
  335. std::unique_ptr<std::string> response) {
  336. constexpr char kJsonPrefix[] = ")]}'\n";
  337. if (response && response->length() > strlen(kJsonPrefix)) {
  338. auto json_handler =
  339. [](FetchWeatherCallback callback,
  340. data_decoder::DataDecoder::ValueOrError result) {
  341. if (result.has_value()) {
  342. std::move(callback).Run(ToWeatherInfo(*result));
  343. } else {
  344. DVLOG(1) << "Failed to parse weather json.";
  345. std::move(callback).Run(absl::nullopt);
  346. }
  347. };
  348. data_decoder::DataDecoder::ParseJsonIsolated(
  349. response->substr(strlen(kJsonPrefix)),
  350. base::BindOnce(json_handler, std::move(callback)));
  351. } else {
  352. std::move(callback).Run(absl::nullopt);
  353. }
  354. };
  355. const auto* user = user_manager::UserManager::Get()->GetActiveUser();
  356. DCHECK(user->HasGaiaAccount());
  357. BackdropClientConfig::Request request =
  358. backdrop_client_config_.CreateFetchWeatherInfoRequest(
  359. user->GetAccountId().GetGaiaId(), GetClientId());
  360. std::unique_ptr<network::ResourceRequest> resource_request =
  361. CreateResourceRequest(request);
  362. auto backdrop_url_loader = std::make_unique<BackdropURLLoader>();
  363. auto* loader_ptr = backdrop_url_loader.get();
  364. loader_ptr->Start(std::move(resource_request), /*request_body=*/absl::nullopt,
  365. NO_TRAFFIC_ANNOTATION_YET,
  366. base::BindOnce(response_handler, std::move(callback),
  367. std::move(backdrop_url_loader)));
  368. }
  369. const std::array<const char*, 2>&
  370. AmbientBackendControllerImpl::GetBackupPhotoUrls() const {
  371. return chromeos::ambient::kBackupPhotoUrls;
  372. }
  373. void AmbientBackendControllerImpl::FetchScreenUpdateInfoInternal(
  374. int num_topics,
  375. bool show_pair_personal_portraits,
  376. const gfx::Size& screen_size,
  377. OnScreenUpdateInfoFetchedCallback callback,
  378. const std::string& gaia_id,
  379. const std::string& access_token) {
  380. if (gaia_id.empty() || access_token.empty()) {
  381. LOG(ERROR) << "Failed to fetch access token for ScreenUpdate";
  382. // Returns an empty instance to indicate the failure.
  383. std::move(callback).Run(ash::ScreenUpdate());
  384. return;
  385. }
  386. BackdropClientConfig::Request request =
  387. backdrop_client_config_.CreateFetchScreenUpdateRequest({
  388. {/*gaia_id*/ gaia_id,
  389. /*token*/ access_token,
  390. /*client_id*/ GetClientId()},
  391. /*num_topics*/ num_topics,
  392. /*show_pair_personal_portraits*/ show_pair_personal_portraits,
  393. });
  394. auto resource_request = CreateResourceRequest(request);
  395. DCHECK(!screen_size.IsEmpty());
  396. resource_request->url =
  397. net::AppendQueryParameter(resource_request->url, "device-screen-width",
  398. base::NumberToString(screen_size.width()));
  399. resource_request->url =
  400. net::AppendQueryParameter(resource_request->url, "device-screen-height",
  401. base::NumberToString(screen_size.height()));
  402. auto backdrop_url_loader = std::make_unique<BackdropURLLoader>();
  403. auto* loader_ptr = backdrop_url_loader.get();
  404. loader_ptr->Start(
  405. std::move(resource_request), request.body, NO_TRAFFIC_ANNOTATION_YET,
  406. base::BindOnce(&AmbientBackendControllerImpl::OnScreenUpdateInfoFetched,
  407. weak_factory_.GetWeakPtr(), std::move(callback),
  408. std::move(backdrop_url_loader)));
  409. }
  410. void AmbientBackendControllerImpl::OnScreenUpdateInfoFetched(
  411. OnScreenUpdateInfoFetchedCallback callback,
  412. std::unique_ptr<BackdropURLLoader> backdrop_url_loader,
  413. std::unique_ptr<std::string> response) {
  414. DCHECK(backdrop_url_loader);
  415. // Parse the |ScreenUpdate| out from the response string.
  416. // Note that the |backdrop_screen_update| can be an empty instance if the
  417. // parsing has failed.
  418. backdrop::ScreenUpdate backdrop_screen_update =
  419. BackdropClientConfig::ParseScreenUpdateFromResponse(*response);
  420. // Store the information to a public struct and notify the caller.
  421. auto screen_update = ToScreenUpdate(backdrop_screen_update);
  422. std::move(callback).Run(screen_update);
  423. }
  424. void AmbientBackendControllerImpl::StartToGetSettings(
  425. GetSettingsCallback callback,
  426. const std::string& gaia_id,
  427. const std::string& access_token) {
  428. if (gaia_id.empty() || access_token.empty()) {
  429. std::move(callback).Run(/*topic_source=*/absl::nullopt);
  430. return;
  431. }
  432. std::string client_id = GetClientId();
  433. BackdropClientConfig::Request request =
  434. backdrop_client_config_.CreateGetSettingsRequest(gaia_id, access_token,
  435. client_id);
  436. auto resource_request = CreateResourceRequest(request);
  437. auto backdrop_url_loader = std::make_unique<BackdropURLLoader>();
  438. auto* loader_ptr = backdrop_url_loader.get();
  439. loader_ptr->Start(
  440. std::move(resource_request), request.body, NO_TRAFFIC_ANNOTATION_YET,
  441. base::BindOnce(&AmbientBackendControllerImpl::OnGetSettings,
  442. weak_factory_.GetWeakPtr(), std::move(callback),
  443. std::move(backdrop_url_loader)));
  444. }
  445. void AmbientBackendControllerImpl::OnGetSettings(
  446. GetSettingsCallback callback,
  447. std::unique_ptr<BackdropURLLoader> backdrop_url_loader,
  448. std::unique_ptr<std::string> response) {
  449. DCHECK(backdrop_url_loader);
  450. auto settings = BackdropClientConfig::ParseGetSettingsResponse(*response);
  451. // |art_settings| should not be empty if parsed successfully.
  452. if (settings.art_settings.empty()) {
  453. std::move(callback).Run(absl::nullopt);
  454. } else {
  455. for (auto& art_setting : settings.art_settings) {
  456. art_setting.visible = IsArtSettingVisible(art_setting);
  457. art_setting.enabled = art_setting.enabled && art_setting.visible;
  458. }
  459. std::move(callback).Run(settings);
  460. }
  461. }
  462. void AmbientBackendControllerImpl::StartToUpdateSettings(
  463. const AmbientSettings& settings,
  464. UpdateSettingsCallback callback,
  465. const std::string& gaia_id,
  466. const std::string& access_token) {
  467. if (gaia_id.empty() || access_token.empty()) {
  468. std::move(callback).Run(/*success=*/false);
  469. return;
  470. }
  471. std::string client_id = GetClientId();
  472. BackdropClientConfig::Request request =
  473. backdrop_client_config_.CreateUpdateSettingsRequest(gaia_id, access_token,
  474. client_id, settings);
  475. auto resource_request = CreateResourceRequest(request);
  476. auto backdrop_url_loader = std::make_unique<BackdropURLLoader>();
  477. auto* loader_ptr = backdrop_url_loader.get();
  478. loader_ptr->Start(
  479. std::move(resource_request), request.body, NO_TRAFFIC_ANNOTATION_YET,
  480. base::BindOnce(&AmbientBackendControllerImpl::OnUpdateSettings,
  481. weak_factory_.GetWeakPtr(), std::move(callback), settings,
  482. std::move(backdrop_url_loader)));
  483. }
  484. void AmbientBackendControllerImpl::OnUpdateSettings(
  485. UpdateSettingsCallback callback,
  486. const AmbientSettings& settings,
  487. std::unique_ptr<BackdropURLLoader> backdrop_url_loader,
  488. std::unique_ptr<std::string> response) {
  489. DCHECK(backdrop_url_loader);
  490. const bool success =
  491. BackdropClientConfig::ParseUpdateSettingsResponse(*response);
  492. if (success) {
  493. // Store information about the ambient mode settings in a user pref so that
  494. // it can be uploaded as a histogram.
  495. Shell::Get()->session_controller()->GetPrimaryUserPrefService()->SetInteger(
  496. ambient::prefs::kAmbientModePhotoSourcePref,
  497. static_cast<int>(ambient::AmbientSettingsToPhotoSource(settings)));
  498. }
  499. std::move(callback).Run(success);
  500. }
  501. void AmbientBackendControllerImpl::FetchPersonalAlbumsInternal(
  502. int banner_width,
  503. int banner_height,
  504. int num_albums,
  505. const std::string& resume_token,
  506. OnPersonalAlbumsFetchedCallback callback,
  507. const std::string& gaia_id,
  508. const std::string& access_token) {
  509. if (gaia_id.empty() || access_token.empty()) {
  510. DVLOG(2) << "Failed to fetch access token";
  511. // Returns an empty instance to indicate the failure.
  512. std::move(callback).Run(ash::PersonalAlbums());
  513. return;
  514. }
  515. BackdropClientConfig::Request request =
  516. backdrop_client_config_.CreateFetchPersonalAlbumsRequest(
  517. banner_width, banner_height, num_albums, resume_token, gaia_id,
  518. access_token);
  519. std::unique_ptr<network::ResourceRequest> resource_request =
  520. CreateResourceRequest(request);
  521. auto backdrop_url_loader = std::make_unique<BackdropURLLoader>();
  522. auto* loader_ptr = backdrop_url_loader.get();
  523. loader_ptr->Start(
  524. std::move(resource_request), /*request_body=*/absl::nullopt,
  525. NO_TRAFFIC_ANNOTATION_YET,
  526. base::BindOnce(&AmbientBackendControllerImpl::OnPersonalAlbumsFetched,
  527. weak_factory_.GetWeakPtr(), std::move(callback),
  528. std::move(backdrop_url_loader)));
  529. }
  530. void AmbientBackendControllerImpl::OnPersonalAlbumsFetched(
  531. OnPersonalAlbumsFetchedCallback callback,
  532. std::unique_ptr<BackdropURLLoader> backdrop_url_loader,
  533. std::unique_ptr<std::string> response) {
  534. DCHECK(backdrop_url_loader);
  535. // Parse the |PersonalAlbumsResponse| out from the response string.
  536. // Note that the |personal_albums| can be an empty instance if the parsing has
  537. // failed.
  538. ash::PersonalAlbums personal_albums =
  539. BackdropClientConfig::ParsePersonalAlbumsResponse(*response);
  540. std::move(callback).Run(std::move(personal_albums));
  541. }
  542. void AmbientBackendControllerImpl::FetchSettingsAndAlbums(
  543. int banner_width,
  544. int banner_height,
  545. int num_albums,
  546. OnSettingsAndAlbumsFetchedCallback callback) {
  547. auto on_done = base::BarrierClosure(
  548. /*num_callbacks=*/2,
  549. base::BindOnce(&AmbientBackendControllerImpl::OnSettingsAndAlbumsFetched,
  550. weak_factory_.GetWeakPtr(), std::move(callback)));
  551. GetSettings(base::BindOnce(&AmbientBackendControllerImpl::OnSettingsFetched,
  552. weak_factory_.GetWeakPtr(), on_done));
  553. FetchPersonalAlbums(
  554. banner_width, banner_height, num_albums, /*resume_token=*/"",
  555. base::BindOnce(&AmbientBackendControllerImpl::OnAlbumsFetched,
  556. weak_factory_.GetWeakPtr(), on_done));
  557. }
  558. void AmbientBackendControllerImpl::StartToGetGooglePhotosAlbumsPreview(
  559. const std::vector<std::string>& album_ids,
  560. int preview_width,
  561. int preview_height,
  562. int num_previews,
  563. GetGooglePhotosAlbumsPreviewCallback callback,
  564. const std::string& gaia_id,
  565. const std::string& access_token) {
  566. BackdropClientConfig::Request request =
  567. backdrop_client_config_.CreateGetGooglePhotosAlbumsPreviewRequest(
  568. gaia_id, access_token, album_ids, preview_width, preview_height,
  569. num_previews);
  570. std::unique_ptr<network::ResourceRequest> resource_request =
  571. CreateResourceRequest(request);
  572. auto backdrop_url_loader = std::make_unique<BackdropURLLoader>();
  573. auto* loader_ptr = backdrop_url_loader.get();
  574. loader_ptr->Start(
  575. std::move(resource_request), request.body, NO_TRAFFIC_ANNOTATION_YET,
  576. base::BindOnce(
  577. &AmbientBackendControllerImpl::OnGetGooglePhotosAlbumsPreview,
  578. weak_factory_.GetWeakPtr(), std::move(callback),
  579. std::move(backdrop_url_loader)));
  580. }
  581. void AmbientBackendControllerImpl::GetGooglePhotosAlbumsPreview(
  582. const std::vector<std::string>& album_ids,
  583. int preview_width,
  584. int preview_height,
  585. int num_previews,
  586. GetGooglePhotosAlbumsPreviewCallback callback) {
  587. Shell::Get()->ambient_controller()->RequestAccessToken(base::BindOnce(
  588. &AmbientBackendControllerImpl::StartToGetGooglePhotosAlbumsPreview,
  589. weak_factory_.GetWeakPtr(), album_ids, preview_width, preview_height,
  590. num_previews, std::move(callback)));
  591. }
  592. void AmbientBackendControllerImpl::OnSettingsFetched(
  593. base::RepeatingClosure on_done,
  594. const absl::optional<ash::AmbientSettings>& settings) {
  595. settings_ = settings;
  596. std::move(on_done).Run();
  597. }
  598. void AmbientBackendControllerImpl::OnAlbumsFetched(
  599. base::RepeatingClosure on_done,
  600. ash::PersonalAlbums personal_albums) {
  601. personal_albums_ = std::move(personal_albums);
  602. std::move(on_done).Run();
  603. }
  604. void AmbientBackendControllerImpl::OnSettingsAndAlbumsFetched(
  605. OnSettingsAndAlbumsFetchedCallback callback) {
  606. std::move(callback).Run(settings_, std::move(personal_albums_));
  607. }
  608. void AmbientBackendControllerImpl::OnGetGooglePhotosAlbumsPreview(
  609. GetGooglePhotosAlbumsPreviewCallback callback,
  610. std::unique_ptr<BackdropURLLoader> backdrop_url_loader,
  611. std::unique_ptr<std::string> response) {
  612. DCHECK(backdrop_url_loader);
  613. backdrop::GetGooglePhotosAlbumsPreviewResponse
  614. get_google_photos_albums_preview_response;
  615. if (!get_google_photos_albums_preview_response.ParseFromString(*response))
  616. std::move(callback).Run(std::vector<GURL>());
  617. std::vector<GURL> preview_urls;
  618. for (const std::string& preview_url :
  619. get_google_photos_albums_preview_response.preview_url()) {
  620. preview_urls.emplace_back(preview_url);
  621. }
  622. std::move(callback).Run(preview_urls);
  623. }
  624. } // namespace ash