desk_template_conversion.cc 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  1. // Copyright 2021 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 "components/desks_storage/core/desk_template_conversion.h"
  5. #include "base/guid.h"
  6. #include "base/json/json_reader.h"
  7. #include "base/json/values_util.h"
  8. #include "base/notreached.h"
  9. #include "base/strings/string_number_conversions.h"
  10. #include "base/strings/utf_string_conversions.h"
  11. #include "base/time/time.h"
  12. #include "components/app_constants/constants.h"
  13. #include "components/app_restore/app_launch_info.h"
  14. #include "components/app_restore/restore_data.h"
  15. #include "components/app_restore/tab_group_info.h"
  16. #include "components/app_restore/window_info.h"
  17. #include "components/services/app_service/public/cpp/app_registry_cache.h"
  18. #include "components/services/app_service/public/cpp/app_types.h"
  19. #include "components/sync/protocol/proto_enum_conversions.h"
  20. #include "components/tab_groups/tab_group_color.h"
  21. #include "components/tab_groups/tab_group_visual_data.h"
  22. #include "third_party/abseil-cpp/absl/types/optional.h"
  23. #include "ui/gfx/geometry/rect.h"
  24. #if !BUILDFLAG(IS_CHROMEOS_LACROS)
  25. #include "chromeos/crosapi/cpp/lacros_startup_state.h" // nogncheck
  26. #endif // !BUILDFLAG(IS_CHROMEOS_LACROS)
  27. namespace {
  28. using SyncWindowOpenDisposition =
  29. sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition;
  30. using SyncLaunchContainer = sync_pb::WorkspaceDeskSpecifics_LaunchContainer;
  31. using GroupColor = tab_groups::TabGroupColorId;
  32. // JSON value keys.
  33. constexpr char kActiveTabIndex[] = "active_tab_index";
  34. constexpr char kAppId[] = "app_id";
  35. constexpr char kApps[] = "apps";
  36. constexpr char kAppName[] = "app_name";
  37. constexpr char kAppType[] = "app_type";
  38. constexpr char kAppTypeArc[] = "ARC";
  39. constexpr char kAppTypeBrowser[] = "BROWSER";
  40. constexpr char kAppTypeChrome[] = "CHROME_APP";
  41. constexpr char kAppTypeProgressiveWeb[] = "PWA";
  42. constexpr char kAppTypeUnsupported[] = "UNSUPPORTED";
  43. constexpr char kBoundsInRoot[] = "bounds_in_root";
  44. constexpr char kCreatedTime[] = "created_time_usec";
  45. constexpr char kDesk[] = "desk";
  46. constexpr char kDeskType[] = "desk_type";
  47. constexpr char kDeskTypeTemplate[] = "TEMPLATE";
  48. constexpr char kDeskTypeSaveAndRecall[] = "SAVE_AND_RECALL";
  49. constexpr char kDeskTypeUnknown[] = "UNKNOWN";
  50. constexpr char kDisplayId[] = "display_id";
  51. constexpr char kEventFlag[] = "event_flag";
  52. constexpr char kFirstNonPinnedTabIndex[] = "first_non_pinned_tab_index";
  53. constexpr char kIsAppTypeBrowser[] = "is_app";
  54. constexpr char kLaunchContainer[] = "launch_container";
  55. constexpr char kLaunchContainerWindow[] = "LAUNCH_CONTAINER_WINDOW";
  56. constexpr char kLaunchContainerUnspecified[] = "LAUNCH_CONTAINER_UNSPECIFIED";
  57. constexpr char kLaunchContainerPanelDeprecated[] = "LAUNCH_CONTAINER_PANEL";
  58. constexpr char kLaunchContainerTab[] = "LAUNCH_CONTAINER_TAB";
  59. constexpr char kLaunchContainerNone[] = "LAUNCH_CONTAINER_NONE";
  60. constexpr char kMaximumSize[] = "maximum_size";
  61. constexpr char kMinimumSize[] = "minimum_size";
  62. constexpr char kName[] = "name";
  63. constexpr char kPreMinimizedWindowState[] = "pre_minimized_window_state";
  64. constexpr char kTabRangeFirstIndex[] = "first_index";
  65. constexpr char kTabRangeLastIndex[] = "last_index";
  66. constexpr char kSizeHeight[] = "height";
  67. constexpr char kSizeWidth[] = "width";
  68. constexpr char kSnapPercentage[] = "snap_percent";
  69. constexpr char kTabs[] = "tabs";
  70. constexpr char kTabGroups[] = "tab_groups";
  71. constexpr char kTabUrl[] = "url";
  72. constexpr char kTitle[] = "title";
  73. constexpr char kUpdatedTime[] = "updated_time_usec";
  74. constexpr char kUuid[] = "uuid";
  75. constexpr char kVersion[] = "version";
  76. constexpr char kTabGroupTitleKey[] = "title";
  77. constexpr char kTabGroupColorKey[] = "color";
  78. constexpr char kTabGroupIsCollapsed[] = "is_collapsed";
  79. constexpr char kWindowId[] = "window_id";
  80. constexpr char kWindowBound[] = "window_bound";
  81. constexpr char kWindowBoundHeight[] = "height";
  82. constexpr char kWindowBoundLeft[] = "left";
  83. constexpr char kWindowBoundTop[] = "top";
  84. constexpr char kWindowBoundWidth[] = "width";
  85. constexpr char kWindowOpenDisposition[] = "window_open_disposition";
  86. constexpr char kWindowOpenDispositionUnknown[] = "UNKOWN";
  87. constexpr char kWindowOpenDispositionCurrentTab[] = "CURRENT_TAB";
  88. constexpr char kWindowOpenDispositionSingletonTab[] = "SINGLETON_TAB";
  89. constexpr char kWindowOpenDispositionNewForegroundTab[] = "NEW_FOREGROUND_TAB";
  90. constexpr char kWindowOpenDispositionNewBackgroundTab[] = "NEW_BACKGROUND_TAB";
  91. constexpr char kWindowOpenDispositionNewPopup[] = "NEW_POPUP";
  92. constexpr char kWindowOpenDispositionNewWindow[] = "NEW_WINDOW";
  93. constexpr char kWindowOpenDispositionSaveToDisk[] = "SAVE_TO_DISK";
  94. constexpr char kWindowOpenDispositionOffTheRecord[] = "OFF_THE_RECORD";
  95. constexpr char kWindowOpenDispositionIgnoreAction[] = "IGNORE_ACTION";
  96. constexpr char kWindowOpenDispositionSwitchToTab[] = "SWITCH_TO_TAB";
  97. constexpr char kWindowOpenDispositionNewPictureInPicture[] =
  98. "NEW_PICTURE_IN_PICTURE";
  99. constexpr char kWindowState[] = "window_state";
  100. constexpr char kWindowStateNormal[] = "NORMAL";
  101. constexpr char kWindowStateMinimized[] = "MINIMIZED";
  102. constexpr char kWindowStateMaximized[] = "MAXIMIZED";
  103. constexpr char kWindowStateFullscreen[] = "FULLSCREEN";
  104. constexpr char kWindowStatePrimarySnapped[] = "PRIMARY_SNAPPED";
  105. constexpr char kWindowStateSecondarySnapped[] = "SECONDARY_SNAPPED";
  106. constexpr char kZIndex[] = "z_index";
  107. // Valid value sets.
  108. const std::set<std::string> kValidDeskTypes = {kDeskTypeTemplate,
  109. kDeskTypeSaveAndRecall};
  110. const std::set<std::string> kValidLaunchContainers = {
  111. kLaunchContainerWindow, kLaunchContainerPanelDeprecated,
  112. kLaunchContainerTab, kLaunchContainerNone, kLaunchContainerUnspecified};
  113. const std::set<std::string> kValidWindowOpenDispositions = {
  114. kWindowOpenDispositionUnknown,
  115. kWindowOpenDispositionCurrentTab,
  116. kWindowOpenDispositionSingletonTab,
  117. kWindowOpenDispositionNewForegroundTab,
  118. kWindowOpenDispositionNewBackgroundTab,
  119. kWindowOpenDispositionNewPopup,
  120. kWindowOpenDispositionNewWindow,
  121. kWindowOpenDispositionSaveToDisk,
  122. kWindowOpenDispositionOffTheRecord,
  123. kWindowOpenDispositionIgnoreAction,
  124. kWindowOpenDispositionSwitchToTab,
  125. kWindowOpenDispositionNewPictureInPicture};
  126. const std::set<std::string> kValidWindowStates = {kWindowStateNormal,
  127. kWindowStateMinimized,
  128. kWindowStateMaximized,
  129. kWindowStateFullscreen,
  130. kWindowStatePrimarySnapped,
  131. kWindowStateSecondarySnapped,
  132. kZIndex};
  133. const std::set<std::string> kValidTabGroupColors = {
  134. app_restore::kTabGroupColorUnknown, app_restore::kTabGroupColorGrey,
  135. app_restore::kTabGroupColorBlue, app_restore::kTabGroupColorRed,
  136. app_restore::kTabGroupColorYellow, app_restore::kTabGroupColorGreen,
  137. app_restore::kTabGroupColorPink, app_restore::kTabGroupColorPurple,
  138. app_restore::kTabGroupColorCyan, app_restore::kTabGroupColorOrange};
  139. // Version number.
  140. constexpr int kVersionNum = 1;
  141. // Conversion to desk methods.
  142. bool GetString(const base::Value* dict, const char* key, std::string* out) {
  143. const base::Value* value =
  144. dict->FindKeyOfType(key, base::Value::Type::STRING);
  145. if (!value)
  146. return false;
  147. *out = value->GetString();
  148. return true;
  149. }
  150. bool GetString(const base::Value& dict, const char* key, std::string* out) {
  151. return GetString(&dict, key, out);
  152. }
  153. bool GetInt(const base::Value* dict, const char* key, int* out) {
  154. const base::Value* value =
  155. dict->FindKeyOfType(key, base::Value::Type::INTEGER);
  156. if (!value)
  157. return false;
  158. *out = value->GetInt();
  159. return true;
  160. }
  161. bool GetInt(const base::Value& dict, const char* key, int* out) {
  162. return GetInt(&dict, key, out);
  163. }
  164. bool GetBool(const base::Value* dict, const char* key, bool* out) {
  165. const base::Value* value =
  166. dict->FindKeyOfType(key, base::Value::Type::BOOLEAN);
  167. if (!value)
  168. return false;
  169. *out = value->GetBool();
  170. return true;
  171. }
  172. bool GetBool(const base::Value& dict, const char* key, bool* out) {
  173. return GetBool(&dict, key, out);
  174. }
  175. // Get App ID from App proto.
  176. std::string GetJsonAppId(const base::Value& app) {
  177. std::string app_type;
  178. if (!GetString(app, kAppType, &app_type))
  179. return std::string(); // App Type must be specified.
  180. if (app_type == kAppTypeBrowser) {
  181. // Return the primary browser's known app ID.
  182. const bool is_lacros =
  183. #if BUILDFLAG(IS_CHROMEOS_LACROS)
  184. true;
  185. #else
  186. // Note that this will launch the browser as lacros if it is enabled,
  187. // even if it was saved as a non-lacros window (and vice-versa).
  188. crosapi::lacros_startup_state::IsLacrosEnabled() &&
  189. crosapi::lacros_startup_state::IsLacrosPrimaryEnabled();
  190. #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
  191. // Browser app has a known app ID.
  192. return std::string(is_lacros ? app_constants::kLacrosAppId
  193. : app_constants::kChromeAppId);
  194. } else if (app_type == kAppTypeChrome || app_type == kAppTypeProgressiveWeb ||
  195. app_type == kAppTypeArc) {
  196. // Read the provided app ID
  197. std::string app_id;
  198. if (GetString(app, kAppId, &app_id)) {
  199. return app_id;
  200. }
  201. }
  202. // Unsupported type
  203. return std::string();
  204. }
  205. // Convert a TabGroupInfo object to a base::Value dictionary.
  206. base::Value ConvertTabGroupInfoToValue(
  207. const app_restore::TabGroupInfo& group_info) {
  208. base::Value tab_group_dict(base::Value::Type::DICTIONARY);
  209. tab_group_dict.SetIntKey(kTabRangeFirstIndex, group_info.tab_range.start());
  210. tab_group_dict.SetIntKey(kTabRangeLastIndex, group_info.tab_range.end());
  211. tab_group_dict.SetStringKey(
  212. kTabGroupTitleKey, base::UTF16ToUTF8(group_info.visual_data.title()));
  213. tab_group_dict.SetStringKey(
  214. kTabGroupColorKey,
  215. app_restore::TabGroupColorToString(group_info.visual_data.color()));
  216. tab_group_dict.SetBoolKey(kTabGroupIsCollapsed,
  217. group_info.visual_data.is_collapsed());
  218. return tab_group_dict;
  219. }
  220. bool IsValidGroupColor(const std::string& group_color) {
  221. return base::Contains(kValidTabGroupColors, group_color);
  222. }
  223. GroupColor ConvertGroupColorStringToGroupColor(const std::string& group_color) {
  224. if (group_color == app_restore::kTabGroupColorGrey) {
  225. return GroupColor::kGrey;
  226. } else if (group_color == app_restore::kTabGroupColorBlue) {
  227. return GroupColor::kBlue;
  228. } else if (group_color == app_restore::kTabGroupColorRed) {
  229. return GroupColor::kRed;
  230. } else if (group_color == app_restore::kTabGroupColorYellow) {
  231. return GroupColor::kYellow;
  232. } else if (group_color == app_restore::kTabGroupColorGreen) {
  233. return GroupColor::kGreen;
  234. } else if (group_color == app_restore::kTabGroupColorPink) {
  235. return GroupColor::kPink;
  236. } else if (group_color == app_restore::kTabGroupColorPurple) {
  237. return GroupColor::kPurple;
  238. } else if (group_color == app_restore::kTabGroupColorCyan) {
  239. return GroupColor::kCyan;
  240. } else if (group_color == app_restore::kTabGroupColorOrange) {
  241. return GroupColor::kOrange;
  242. // There is no UNKNOWN equivalent in GroupColor, simply default
  243. // to grey.
  244. } else if (group_color == app_restore::kTabGroupColorUnknown) {
  245. return GroupColor::kGrey;
  246. } else {
  247. NOTREACHED();
  248. return GroupColor::kGrey;
  249. }
  250. }
  251. // Constructs a GroupVisualData from value `group_visual_data` IFF all fields
  252. // are present and valid in the value parameter. Returns true on success, false
  253. // on failure.
  254. bool MakeTabGroupVisualDataFromValue(
  255. const base::Value& tab_group,
  256. tab_groups::TabGroupVisualData* out_visual_data) {
  257. std::string tab_group_title;
  258. std::string group_color_string;
  259. bool is_collapsed;
  260. if (GetString(tab_group, kTabGroupTitleKey, &tab_group_title) &&
  261. GetBool(tab_group, kTabGroupIsCollapsed, &is_collapsed) &&
  262. GetString(tab_group, kTabGroupColorKey, &group_color_string) &&
  263. IsValidGroupColor(group_color_string)) {
  264. *out_visual_data = tab_groups::TabGroupVisualData(
  265. base::UTF8ToUTF16(tab_group_title),
  266. ConvertGroupColorStringToGroupColor(group_color_string), is_collapsed);
  267. return true;
  268. }
  269. return false;
  270. }
  271. // Constructs a gfx::Range from value `group_range` IFF all fields are
  272. // present and valid in the value parameter. Returns true on success, false on
  273. // failure.
  274. bool MakeTabGroupRangeFromValue(const base::Value& tab_group,
  275. gfx::Range* out_range) {
  276. int32_t range_start;
  277. int32_t range_end;
  278. if (GetInt(tab_group, kTabRangeFirstIndex, &range_start) &&
  279. GetInt(tab_group, kTabRangeLastIndex, &range_end)) {
  280. *out_range = gfx::Range(range_start, range_end);
  281. return true;
  282. }
  283. return false;
  284. }
  285. // Constructs a TabGroupInfo from `tab_group` IFF all fields are present
  286. // and valid in the value parameter. Returns true on success, false on failure.
  287. absl::optional<app_restore::TabGroupInfo> MakeTabGroupInfoFromDict(
  288. const base::Value& tab_group) {
  289. absl::optional<app_restore::TabGroupInfo> tab_group_info = absl::nullopt;
  290. tab_groups::TabGroupVisualData visual_data;
  291. gfx::Range range;
  292. if (MakeTabGroupRangeFromValue(tab_group, &range) &&
  293. MakeTabGroupVisualDataFromValue(tab_group, &visual_data)) {
  294. tab_group_info.emplace(range, visual_data);
  295. }
  296. return tab_group_info;
  297. }
  298. // Returns true if launch container string value is valid.
  299. bool IsValidLaunchContainer(const std::string& launch_container) {
  300. return base::Contains(kValidLaunchContainers, launch_container);
  301. }
  302. // Returns a casted apps::LaunchContainer to be set as an app restore data's
  303. // container field.
  304. int32_t StringToLaunchContainer(const std::string& launch_container) {
  305. if (launch_container == kLaunchContainerWindow) {
  306. return static_cast<int32_t>(apps::LaunchContainer::kLaunchContainerWindow);
  307. } else if (launch_container == kLaunchContainerPanelDeprecated) {
  308. return static_cast<int32_t>(
  309. apps::LaunchContainer::kLaunchContainerPanelDeprecated);
  310. } else if (launch_container == kLaunchContainerTab) {
  311. return static_cast<int32_t>(apps::LaunchContainer::kLaunchContainerTab);
  312. } else if (launch_container == kLaunchContainerNone) {
  313. return static_cast<int32_t>(apps::LaunchContainer::kLaunchContainerNone);
  314. } else if (launch_container == kLaunchContainerUnspecified) {
  315. return static_cast<int32_t>(apps::LaunchContainer::kLaunchContainerWindow);
  316. // Dcheck if our container isn't valid. We should not reach here.
  317. } else {
  318. DCHECK(IsValidLaunchContainer(launch_container));
  319. return static_cast<int32_t>(apps::LaunchContainer::kLaunchContainerWindow);
  320. }
  321. }
  322. // Returns true if the disposition is a valid value.
  323. bool IsValidWindowOpenDisposition(const std::string& disposition) {
  324. return base::Contains(kValidWindowOpenDispositions, disposition);
  325. }
  326. // Returns a casted WindowOpenDisposition to be set in the app restore data.
  327. int32_t StringToWindowOpenDisposition(const std::string& disposition) {
  328. if (disposition == kWindowOpenDispositionUnknown) {
  329. return static_cast<int32_t>(WindowOpenDisposition::UNKNOWN);
  330. } else if (disposition == kWindowOpenDispositionCurrentTab) {
  331. return static_cast<int32_t>(WindowOpenDisposition::CURRENT_TAB);
  332. } else if (disposition == kWindowOpenDispositionSingletonTab) {
  333. return static_cast<int32_t>(WindowOpenDisposition::SINGLETON_TAB);
  334. } else if (disposition == kWindowOpenDispositionNewForegroundTab) {
  335. return static_cast<int32_t>(WindowOpenDisposition::NEW_FOREGROUND_TAB);
  336. } else if (disposition == kWindowOpenDispositionNewBackgroundTab) {
  337. return static_cast<int32_t>(WindowOpenDisposition::NEW_BACKGROUND_TAB);
  338. } else if (disposition == kWindowOpenDispositionNewPopup) {
  339. return static_cast<int32_t>(WindowOpenDisposition::NEW_POPUP);
  340. } else if (disposition == kWindowOpenDispositionNewWindow) {
  341. return static_cast<int32_t>(WindowOpenDisposition::NEW_WINDOW);
  342. } else if (disposition == kWindowOpenDispositionSaveToDisk) {
  343. return static_cast<int32_t>(WindowOpenDisposition::SAVE_TO_DISK);
  344. } else if (disposition == kWindowOpenDispositionOffTheRecord) {
  345. return static_cast<int32_t>(WindowOpenDisposition::OFF_THE_RECORD);
  346. } else if (disposition == kWindowOpenDispositionIgnoreAction) {
  347. return static_cast<int32_t>(WindowOpenDisposition::IGNORE_ACTION);
  348. } else if (disposition == kWindowOpenDispositionNewPictureInPicture) {
  349. return static_cast<int32_t>(WindowOpenDisposition::NEW_PICTURE_IN_PICTURE);
  350. // Dcheck that the disposition is valid, we should never get here unless
  351. // the disposition is invalid.
  352. } else {
  353. DCHECK(IsValidWindowOpenDisposition(disposition));
  354. return static_cast<int32_t>(WindowOpenDisposition::UNKNOWN);
  355. }
  356. }
  357. // Convert App JSON to `app_restore::AppLaunchInfo`.
  358. std::unique_ptr<app_restore::AppLaunchInfo> ConvertJsonToAppLaunchInfo(
  359. const base::Value& app) {
  360. int32_t window_id;
  361. if (!GetInt(app, kWindowId, &window_id))
  362. return nullptr;
  363. const std::string app_id = GetJsonAppId(app);
  364. if (app_id.empty())
  365. return nullptr;
  366. std::unique_ptr<app_restore::AppLaunchInfo> app_launch_info =
  367. std::make_unique<app_restore::AppLaunchInfo>(app_id, window_id);
  368. std::string display_id_string;
  369. int64_t display_id;
  370. if (GetString(app, kDisplayId, &display_id_string) &&
  371. base::StringToInt64(display_id_string, &display_id)) {
  372. app_launch_info->display_id = display_id;
  373. }
  374. std::string app_type;
  375. if (!GetString(app, kAppType, &app_type)) {
  376. // This should never happen. `APP_NOT_SET` corresponds to empty `app_id`.
  377. // This method will early return when `app_id` is empty.
  378. NOTREACHED();
  379. return nullptr;
  380. }
  381. std::string launch_container;
  382. if (GetString(app, kLaunchContainer, &launch_container) &&
  383. IsValidLaunchContainer(launch_container)) {
  384. app_launch_info->container = StringToLaunchContainer(launch_container);
  385. }
  386. std::string disposition;
  387. if (GetString(app, kWindowOpenDisposition, &disposition) &&
  388. IsValidWindowOpenDisposition(disposition)) {
  389. app_launch_info->disposition = StringToWindowOpenDisposition(disposition);
  390. }
  391. std::string app_name;
  392. if (GetString(app, kAppName, &app_name))
  393. app_launch_info->app_name = app_name;
  394. // TODO(crbug.com/1311801): Add support for actual event_flag values.
  395. app_launch_info->event_flag = 0;
  396. bool app_type_browser;
  397. if (GetBool(app, kIsAppTypeBrowser, &app_type_browser))
  398. app_launch_info->app_type_browser = app_type_browser;
  399. if (app_type == kAppTypeBrowser) {
  400. int active_tab_index;
  401. if (GetInt(app, kActiveTabIndex, &active_tab_index))
  402. app_launch_info->active_tab_index = active_tab_index;
  403. int first_non_pinned_tab_index;
  404. if (GetInt(app, kFirstNonPinnedTabIndex, &first_non_pinned_tab_index))
  405. app_launch_info->first_non_pinned_tab_index = first_non_pinned_tab_index;
  406. // Fill in the URL list
  407. app_launch_info->urls.emplace();
  408. const base::Value* tabs = app.FindKeyOfType(kTabs, base::Value::Type::LIST);
  409. if (tabs) {
  410. for (auto& tab : tabs->GetListDeprecated()) {
  411. std::string url;
  412. if (GetString(tab, kTabUrl, &url)) {
  413. app_launch_info->urls.value().emplace_back(url);
  414. }
  415. }
  416. }
  417. // Fill the tab groups
  418. app_launch_info->tab_group_infos.emplace();
  419. const base::Value* tab_groups =
  420. app.FindKeyOfType(kTabGroups, base::Value::Type::LIST);
  421. if (tab_groups) {
  422. for (auto& tab : tab_groups->GetList()) {
  423. absl::optional<app_restore::TabGroupInfo> tab_group =
  424. MakeTabGroupInfoFromDict(tab);
  425. if (tab_group.has_value()) {
  426. app_launch_info->tab_group_infos->push_back(
  427. std::move(tab_group.value()));
  428. }
  429. }
  430. }
  431. }
  432. // For Chrome apps and PWAs, the `app_id` is sufficient for identification.
  433. return app_launch_info;
  434. }
  435. bool IsValidWindowState(const std::string& window_state) {
  436. return base::Contains(kValidWindowStates, window_state);
  437. }
  438. // Convert JSON string WindowState `state` to ui::WindowShowState used by
  439. // the app_restore::WindowInfo struct.
  440. ui::WindowShowState ToUiWindowState(const std::string& window_state) {
  441. if (window_state == kWindowStateNormal)
  442. return ui::WindowShowState::SHOW_STATE_NORMAL;
  443. else if (window_state == kWindowStateMinimized)
  444. return ui::WindowShowState::SHOW_STATE_MINIMIZED;
  445. else if (window_state == kWindowStateMaximized)
  446. return ui::WindowShowState::SHOW_STATE_MAXIMIZED;
  447. else if (window_state == kWindowStateFullscreen)
  448. return ui::WindowShowState::SHOW_STATE_FULLSCREEN;
  449. else if (window_state == kWindowStatePrimarySnapped)
  450. return ui::WindowShowState::SHOW_STATE_NORMAL;
  451. else if (window_state == kWindowStateSecondarySnapped)
  452. return ui::WindowShowState::SHOW_STATE_NORMAL;
  453. // We should never reach here unless we have been passed an invalid window
  454. // state
  455. DCHECK(IsValidWindowState(window_state));
  456. return ui::WindowShowState::SHOW_STATE_NORMAL;
  457. }
  458. // Convert JSON string WindowState `state` to chromeos::WindowStateType used by
  459. // the app_restore::WindowInfo struct.
  460. chromeos::WindowStateType ToChromeOsWindowState(
  461. const std::string& window_state) {
  462. if (window_state == kWindowStateNormal)
  463. return chromeos::WindowStateType::kNormal;
  464. else if (window_state == kWindowStateMinimized)
  465. return chromeos::WindowStateType::kMinimized;
  466. else if (window_state == kWindowStateMaximized)
  467. return chromeos::WindowStateType::kMaximized;
  468. else if (window_state == kWindowStateFullscreen)
  469. return chromeos::WindowStateType::kFullscreen;
  470. else if (window_state == kWindowStatePrimarySnapped)
  471. return chromeos::WindowStateType::kPrimarySnapped;
  472. else if (window_state == kWindowStateSecondarySnapped)
  473. return chromeos::WindowStateType::kSecondarySnapped;
  474. // We should never reach here unless we have been passed an invalid window
  475. // state.
  476. DCHECK(IsValidWindowState(window_state));
  477. return chromeos::WindowStateType::kNormal;
  478. }
  479. void FillArcExtraWindowInfoFromJson(
  480. const base::Value& app,
  481. app_restore::WindowInfo::ArcExtraInfo* out_window_info) {
  482. const base::Value* bounds_in_root = app.FindDictKey(kBoundsInRoot);
  483. int top;
  484. int left;
  485. int bounds_width;
  486. int bounds_height;
  487. if (bounds_in_root && GetInt(bounds_in_root, kWindowBoundTop, &top) &&
  488. GetInt(bounds_in_root, kWindowBoundLeft, &left) &&
  489. GetInt(bounds_in_root, kWindowBoundWidth, &bounds_width) &&
  490. GetInt(bounds_in_root, kWindowBoundHeight, &bounds_height))
  491. out_window_info->bounds_in_root.emplace(left, top, bounds_width,
  492. bounds_height);
  493. const base::Value* maximum_size = app.FindDictKey(kMaximumSize);
  494. int max_width;
  495. int max_height;
  496. if (maximum_size && GetInt(maximum_size, kSizeWidth, &max_width) &&
  497. GetInt(maximum_size, kSizeHeight, &max_height))
  498. out_window_info->maximum_size.emplace(max_width, max_height);
  499. const base::Value* minimum_size = app.FindDictKey(kMinimumSize);
  500. int min_width;
  501. int min_height;
  502. if (minimum_size && GetInt(minimum_size, kSizeWidth, &min_width) &&
  503. GetInt(minimum_size, kSizeHeight, &min_height)) {
  504. out_window_info->minimum_size.emplace(min_width, min_height);
  505. }
  506. }
  507. // Fill `out_window_info` with information from JSON `app`.
  508. void FillWindowInfoFromJson(const base::Value& app,
  509. app_restore::WindowInfo* out_window_info) {
  510. std::string window_state;
  511. chromeos::WindowStateType cros_window_state =
  512. chromeos::WindowStateType::kDefault;
  513. if (GetString(app, kWindowState, &window_state) &&
  514. IsValidWindowState(window_state)) {
  515. cros_window_state = ToChromeOsWindowState(window_state);
  516. out_window_info->window_state_type.emplace(cros_window_state);
  517. }
  518. std::string app_type;
  519. if (GetString(app, kAppType, &app_type) && app_type == kAppTypeArc) {
  520. FillArcExtraWindowInfoFromJson(app,
  521. &out_window_info->arc_extra_info.emplace());
  522. }
  523. const base::Value* window_bound = app.FindDictKey(kWindowBound);
  524. int top;
  525. int left;
  526. int width;
  527. int height;
  528. if (window_bound && GetInt(window_bound, kWindowBoundTop, &top) &&
  529. GetInt(window_bound, kWindowBoundLeft, &left) &&
  530. GetInt(window_bound, kWindowBoundWidth, &width) &&
  531. GetInt(window_bound, kWindowBoundHeight, &height)) {
  532. out_window_info->current_bounds.emplace(left, top, width, height);
  533. }
  534. int z_index;
  535. if (GetInt(app, kZIndex, &z_index))
  536. out_window_info->activation_index.emplace(z_index);
  537. std::string display_id_string;
  538. int64_t display_id;
  539. if (GetString(app, kDisplayId, &display_id_string) &&
  540. base::StringToInt64(display_id_string, &display_id)) {
  541. out_window_info->display_id = display_id;
  542. }
  543. std::string pre_minimized_window_state;
  544. if (GetString(app, kPreMinimizedWindowState, &pre_minimized_window_state) &&
  545. IsValidWindowState(pre_minimized_window_state) &&
  546. cros_window_state == chromeos::WindowStateType::kMinimized) {
  547. out_window_info->pre_minimized_show_state_type.emplace(
  548. ToUiWindowState(pre_minimized_window_state));
  549. }
  550. int snap_percentage;
  551. if (GetInt(app, kSnapPercentage, &snap_percentage))
  552. out_window_info->snap_percentage.emplace(snap_percentage);
  553. std::string title;
  554. if (GetString(app, kTitle, &title))
  555. out_window_info->app_title.emplace(base::UTF8ToUTF16(title));
  556. }
  557. // Convert a desk template to `app_restore::RestoreData`.
  558. std::unique_ptr<app_restore::RestoreData> ConvertJsonToRestoreData(
  559. const base::Value* desk) {
  560. std::unique_ptr<app_restore::RestoreData> restore_data =
  561. std::make_unique<app_restore::RestoreData>();
  562. const base::Value* apps = desk->FindListKey(kApps);
  563. if (apps) {
  564. for (const auto& app : apps->GetListDeprecated()) {
  565. std::unique_ptr<app_restore::AppLaunchInfo> app_launch_info =
  566. ConvertJsonToAppLaunchInfo(app);
  567. if (!app_launch_info)
  568. continue; // Skip unsupported app.
  569. int window_id;
  570. if (!GetInt(app, kWindowId, &window_id))
  571. return nullptr;
  572. const std::string app_id = app_launch_info->app_id;
  573. restore_data->AddAppLaunchInfo(std::move(app_launch_info));
  574. app_restore::WindowInfo app_window_info;
  575. FillWindowInfoFromJson(app, &app_window_info);
  576. restore_data->ModifyWindowInfo(app_id, window_id, app_window_info);
  577. }
  578. }
  579. return restore_data;
  580. }
  581. // Conversion to value methods.
  582. base::Value ConvertWindowBoundToValue(const gfx::Rect& rect) {
  583. base::Value rectangle_value(base::Value::Type::DICTIONARY);
  584. rectangle_value.SetKey(kWindowBoundTop, base::Value(rect.y()));
  585. rectangle_value.SetKey(kWindowBoundLeft, base::Value(rect.x()));
  586. rectangle_value.SetKey(kWindowBoundHeight, base::Value(rect.height()));
  587. rectangle_value.SetKey(kWindowBoundWidth, base::Value(rect.width()));
  588. return rectangle_value;
  589. }
  590. base::Value ConvertSizeToValue(const gfx::Size& size) {
  591. base::Value size_value(base::Value::Type::DICTIONARY);
  592. size_value.SetKey(kSizeWidth, base::Value(size.width()));
  593. size_value.SetKey(kSizeHeight, base::Value(size.height()));
  594. return size_value;
  595. }
  596. // Convert ui::WindowStateType `window_state` to std::string used by the
  597. // base::Value representation.
  598. std::string ChromeOsWindowStateToString(
  599. const chromeos::WindowStateType& window_state) {
  600. switch (window_state) {
  601. case chromeos::WindowStateType::kNormal:
  602. return kWindowStateNormal;
  603. case chromeos::WindowStateType::kMinimized:
  604. return kWindowStateMinimized;
  605. case chromeos::WindowStateType::kMaximized:
  606. return kWindowStateMaximized;
  607. case chromeos::WindowStateType::kFullscreen:
  608. return kWindowStateFullscreen;
  609. case chromeos::WindowStateType::kPrimarySnapped:
  610. return kWindowStatePrimarySnapped;
  611. case chromeos::WindowStateType::kSecondarySnapped:
  612. return kWindowStateSecondarySnapped;
  613. default:
  614. // Available states in JSON representation is a subset of all window
  615. // states enumerated by WindowStateType. Default to normal if not
  616. // supported.
  617. return kWindowStateNormal;
  618. }
  619. }
  620. // Convert ui::WindowShowState `state` to JSON used by the base::Value
  621. // representation.
  622. std::string UiWindowStateToString(const ui::WindowShowState& window_state) {
  623. switch (window_state) {
  624. case ui::WindowShowState::SHOW_STATE_NORMAL:
  625. return kWindowStateNormal;
  626. case ui::WindowShowState::SHOW_STATE_MINIMIZED:
  627. return kWindowStateMinimized;
  628. case ui::WindowShowState::SHOW_STATE_MAXIMIZED:
  629. return kWindowStateMaximized;
  630. case ui::WindowShowState::SHOW_STATE_FULLSCREEN:
  631. return kWindowStateFullscreen;
  632. default:
  633. // available states in JSON representation is a subset
  634. // of all window states enumerated by WindowShowState.
  635. // Default to normal if not supported.
  636. return kWindowStateNormal;
  637. }
  638. }
  639. // Returns a string WindowOpenDisposition when given a value of the
  640. // WindowOpenDisposition passed into this function. Assumes the caller
  641. // casts the disposition from a int32_t.
  642. std::string WindowOpenDispositionToString(WindowOpenDisposition disposition) {
  643. switch (disposition) {
  644. case WindowOpenDisposition::UNKNOWN:
  645. return kWindowOpenDispositionUnknown;
  646. case WindowOpenDisposition::CURRENT_TAB:
  647. return kWindowOpenDispositionCurrentTab;
  648. case WindowOpenDisposition::SINGLETON_TAB:
  649. return kWindowOpenDispositionSingletonTab;
  650. case WindowOpenDisposition::NEW_FOREGROUND_TAB:
  651. return kWindowOpenDispositionNewForegroundTab;
  652. case WindowOpenDisposition::NEW_BACKGROUND_TAB:
  653. return kWindowOpenDispositionNewBackgroundTab;
  654. case WindowOpenDisposition::NEW_POPUP:
  655. return kWindowOpenDispositionNewPopup;
  656. case WindowOpenDisposition::NEW_WINDOW:
  657. return kWindowOpenDispositionNewWindow;
  658. case WindowOpenDisposition::SAVE_TO_DISK:
  659. return kWindowOpenDispositionSaveToDisk;
  660. case WindowOpenDisposition::SWITCH_TO_TAB:
  661. return kWindowOpenDispositionSwitchToTab;
  662. case WindowOpenDisposition::OFF_THE_RECORD:
  663. return kWindowOpenDispositionOffTheRecord;
  664. case WindowOpenDisposition::IGNORE_ACTION:
  665. return kWindowOpenDispositionIgnoreAction;
  666. case WindowOpenDisposition::NEW_PICTURE_IN_PICTURE:
  667. return kWindowOpenDispositionNewPictureInPicture;
  668. }
  669. }
  670. std::string LaunchContainerToString(apps::LaunchContainer launch_container) {
  671. switch (launch_container) {
  672. case apps::LaunchContainer::kLaunchContainerWindow:
  673. return kLaunchContainerWindow;
  674. case apps::LaunchContainer::kLaunchContainerPanelDeprecated:
  675. return kLaunchContainerPanelDeprecated;
  676. case apps::LaunchContainer::kLaunchContainerTab:
  677. return kLaunchContainerTab;
  678. case apps::LaunchContainer::kLaunchContainerNone:
  679. return kLaunchContainerNone;
  680. }
  681. }
  682. base::Value ConvertURLsToBrowserAppTabValues(const std::vector<GURL>& urls) {
  683. base::Value tab_list = base::Value(base::Value::Type::LIST);
  684. for (const auto& url : urls) {
  685. base::Value browser_tab = base::Value(base::Value::Type::DICTIONARY);
  686. browser_tab.SetKey(kTabUrl, base::Value(url.spec()));
  687. tab_list.Append(std::move(browser_tab));
  688. }
  689. return tab_list;
  690. }
  691. std::string GetAppTypeForJson(apps::AppRegistryCache* apps_cache,
  692. const std::string& app_id) {
  693. const auto app_type = apps_cache->GetAppType(app_id);
  694. // This switch should follow the same structure as DeskSyncBridge#FillApp.
  695. switch (app_type) {
  696. case apps::AppType::kWeb:
  697. case apps::AppType::kSystemWeb:
  698. return kAppTypeChrome;
  699. case apps::AppType::kChromeApp:
  700. if (app_id == app_constants::kChromeAppId) {
  701. return kAppTypeBrowser;
  702. } else {
  703. return kAppTypeChrome;
  704. }
  705. case apps::AppType::kStandaloneBrowser:
  706. if (app_id == app_constants::kLacrosAppId) {
  707. return kAppTypeBrowser;
  708. } else {
  709. return kAppTypeUnsupported;
  710. }
  711. case apps::AppType::kArc:
  712. return kAppTypeArc;
  713. case apps::AppType::kStandaloneBrowserChromeApp:
  714. return kAppTypeChrome;
  715. case apps::AppType::kBuiltIn:
  716. case apps::AppType::kCrostini:
  717. case apps::AppType::kPluginVm:
  718. case apps::AppType::kUnknown:
  719. case apps::AppType::kMacOs:
  720. case apps::AppType::kRemote:
  721. case apps::AppType::kBorealis:
  722. case apps::AppType::kExtension:
  723. case apps::AppType::kStandaloneBrowserExtension:
  724. // Default to unsupported. This app should not be captured.
  725. return kAppTypeUnsupported;
  726. }
  727. }
  728. base::Value ConvertWindowToDeskApp(const std::string& app_id,
  729. const int window_id,
  730. const app_restore::AppRestoreData* app,
  731. apps::AppRegistryCache* apps_cache) {
  732. std::string app_type = GetAppTypeForJson(apps_cache, app_id);
  733. if (kAppTypeUnsupported == app_type) {
  734. return base::Value(base::Value::Type::NONE);
  735. }
  736. base::Value app_data = base::Value(base::Value::Type::DICTIONARY);
  737. if (app->current_bounds.has_value()) {
  738. app_data.SetKey(kWindowBound,
  739. ConvertWindowBoundToValue(app->current_bounds.value()));
  740. }
  741. if (app->bounds_in_root.has_value()) {
  742. app_data.SetKey(kBoundsInRoot,
  743. ConvertWindowBoundToValue(app->bounds_in_root.value()));
  744. }
  745. if (app->minimum_size.has_value()) {
  746. app_data.SetKey(kMinimumSize,
  747. ConvertSizeToValue(app->minimum_size.value()));
  748. }
  749. if (app->maximum_size.has_value()) {
  750. app_data.SetKey(kMaximumSize,
  751. ConvertSizeToValue(app->maximum_size.value()));
  752. }
  753. if (app->title.has_value()) {
  754. app_data.SetKey(kTitle, base::Value(base::UTF16ToUTF8(app->title.value())));
  755. }
  756. chromeos::WindowStateType window_state = chromeos::WindowStateType::kDefault;
  757. if (app->window_state_type.has_value()) {
  758. window_state = app->window_state_type.value();
  759. app_data.SetKey(kWindowState,
  760. base::Value(ChromeOsWindowStateToString(window_state)));
  761. }
  762. // TODO(crbug.com/1311801): Add support for actual event_flag values.
  763. app_data.SetKey(kEventFlag, base::Value(0));
  764. if (app->activation_index.has_value())
  765. app_data.SetKey(kZIndex, base::Value(app->activation_index.value()));
  766. app_data.SetKey(kAppType, base::Value(app_type));
  767. if (app->urls.has_value())
  768. app_data.SetKey(kTabs, ConvertURLsToBrowserAppTabValues(app->urls.value()));
  769. if (app->tab_group_infos.has_value()) {
  770. base::Value tab_groups_value(base::Value::Type::LIST);
  771. for (const auto& tab_group : app->tab_group_infos.value()) {
  772. tab_groups_value.Append(ConvertTabGroupInfoToValue(tab_group));
  773. }
  774. app_data.SetKey(kTabGroups, std::move(tab_groups_value));
  775. }
  776. if (app->active_tab_index.has_value()) {
  777. app_data.SetKey(kActiveTabIndex,
  778. base::Value(app->active_tab_index.value()));
  779. }
  780. if (app->first_non_pinned_tab_index.has_value()) {
  781. app_data.SetKey(kFirstNonPinnedTabIndex,
  782. base::Value(app->first_non_pinned_tab_index.value()));
  783. }
  784. if (app->app_type_browser.has_value()) {
  785. app_data.SetKey(kIsAppTypeBrowser,
  786. base::Value(app->app_type_browser.value()));
  787. }
  788. if (app_type != kAppTypeBrowser)
  789. app_data.SetKey(kAppId, base::Value(app_id));
  790. app_data.SetKey(kWindowId, base::Value(window_id));
  791. if (app->display_id.has_value()) {
  792. app_data.SetKey(kDisplayId,
  793. base::Value(base::NumberToString(app->display_id.value())));
  794. }
  795. if (app->pre_minimized_show_state_type.has_value() &&
  796. window_state == chromeos::WindowStateType::kMinimized) {
  797. app_data.SetKey(kPreMinimizedWindowState,
  798. base::Value(UiWindowStateToString(
  799. app->pre_minimized_show_state_type.value())));
  800. }
  801. if (app->snap_percentage.has_value()) {
  802. app_data.SetKey(
  803. kSnapPercentage,
  804. base::Value(static_cast<int>(app->snap_percentage.value())));
  805. }
  806. if (app->app_name.has_value())
  807. app_data.SetKey(kAppName, base::Value(app->app_name.value()));
  808. if (app->disposition.has_value()) {
  809. WindowOpenDisposition disposition =
  810. static_cast<WindowOpenDisposition>(app->disposition.value());
  811. app_data.SetKey(kWindowOpenDisposition,
  812. base::Value(WindowOpenDispositionToString(disposition)));
  813. }
  814. if (app->container.has_value()) {
  815. apps::LaunchContainer container =
  816. static_cast<apps::LaunchContainer>(app->container.value());
  817. app_data.SetKey(kLaunchContainer,
  818. base::Value(LaunchContainerToString(container)));
  819. }
  820. return app_data;
  821. }
  822. base::Value ConvertRestoreDataToValue(
  823. const app_restore::RestoreData* restore_data,
  824. apps::AppRegistryCache* apps_cache) {
  825. base::Value desk_data = base::Value(base::Value::Type::LIST);
  826. for (const auto& app : restore_data->app_id_to_launch_list()) {
  827. for (const auto& window : app.second) {
  828. auto app_data = ConvertWindowToDeskApp(app.first, window.first,
  829. window.second.get(), apps_cache);
  830. if (app_data.is_none())
  831. continue;
  832. desk_data.Append(std::move(app_data));
  833. }
  834. }
  835. base::Value apps = base::Value(base::Value::Type::DICTIONARY);
  836. apps.SetKey(kApps, std::move(desk_data));
  837. return apps;
  838. }
  839. std::string SerializeDeskTypeAsString(ash::DeskTemplateType desk_type) {
  840. switch (desk_type) {
  841. case ash::DeskTemplateType::kTemplate:
  842. return kDeskTypeTemplate;
  843. case ash::DeskTemplateType::kSaveAndRecall:
  844. return kDeskTypeSaveAndRecall;
  845. case ash::DeskTemplateType::kUnknown:
  846. NOTREACHED();
  847. return kDeskTypeUnknown;
  848. }
  849. }
  850. bool IsValidDeskTemplateType(const std::string& desk_template_type) {
  851. return base::Contains(kValidDeskTypes, desk_template_type);
  852. }
  853. ash::DeskTemplateType GetDeskTypeFromString(const std::string& desk_type) {
  854. DCHECK(IsValidDeskTemplateType(desk_type));
  855. return desk_type == kDeskTypeTemplate ? ash::DeskTemplateType::kTemplate
  856. : ash::DeskTemplateType::kSaveAndRecall;
  857. }
  858. } // namespace
  859. namespace desks_storage {
  860. namespace desk_template_conversion {
  861. // Converts the TabGroupColorId passed into its string equivalent
  862. // as defined in the k constants above.
  863. std::string ConvertTabGroupColorIdToString(GroupColor color) {
  864. switch (color) {
  865. case GroupColor::kGrey:
  866. return app_restore::kTabGroupColorGrey;
  867. case GroupColor::kBlue:
  868. return app_restore::kTabGroupColorBlue;
  869. case GroupColor::kRed:
  870. return app_restore::kTabGroupColorRed;
  871. case GroupColor::kYellow:
  872. return app_restore::kTabGroupColorYellow;
  873. case GroupColor::kGreen:
  874. return app_restore::kTabGroupColorGreen;
  875. case GroupColor::kPink:
  876. return app_restore::kTabGroupColorPink;
  877. case GroupColor::kPurple:
  878. return app_restore::kTabGroupColorPurple;
  879. case GroupColor::kCyan:
  880. return app_restore::kTabGroupColorCyan;
  881. case GroupColor::kOrange:
  882. return app_restore::kTabGroupColorOrange;
  883. }
  884. }
  885. // Converts a time field from sync protobufs to a time object.
  886. base::Time ProtoTimeToTime(int64_t proto_time) {
  887. return base::Time::FromDeltaSinceWindowsEpoch(base::Microseconds(proto_time));
  888. }
  889. // Converts a time object to the format used in sync protobufs
  890. // (Microseconds since the Windows epoch).
  891. int64_t TimeToProtoTime(const base::Time& t) {
  892. return t.ToDeltaSinceWindowsEpoch().InMicroseconds();
  893. }
  894. std::unique_ptr<ash::DeskTemplate> ParseDeskTemplateFromSource(
  895. const base::Value& policy_json,
  896. ash::DeskTemplateSource source) {
  897. if (!policy_json.is_dict())
  898. return nullptr;
  899. int version;
  900. std::string uuid_str;
  901. std::string name;
  902. std::string created_time_usec_str;
  903. std::string updated_time_usec_str;
  904. int64_t created_time_usec;
  905. int64_t updated_time_usec;
  906. const base::Value* desk = policy_json.FindDictKey(kDesk);
  907. if (!desk || !GetInt(policy_json, kVersion, &version) ||
  908. !GetString(policy_json, kUuid, &uuid_str) ||
  909. !GetString(policy_json, kName, &name) ||
  910. !GetString(policy_json, kCreatedTime, &created_time_usec_str) ||
  911. !base::StringToInt64(created_time_usec_str, &created_time_usec) ||
  912. !GetString(policy_json, kUpdatedTime, &updated_time_usec_str) ||
  913. !base::StringToInt64(updated_time_usec_str, &updated_time_usec) ||
  914. name.empty() || created_time_usec_str.empty() ||
  915. updated_time_usec_str.empty())
  916. return nullptr;
  917. base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str);
  918. if (!uuid.is_valid())
  919. return nullptr;
  920. // Set default value for the desk type to template.
  921. std::string desk_type_string;
  922. if (!GetString(policy_json, kDeskType, &desk_type_string)) {
  923. desk_type_string = kDeskTypeTemplate;
  924. } else if (!IsValidDeskTemplateType(desk_type_string)) {
  925. return nullptr;
  926. }
  927. const base::Time created_time = ProtoTimeToTime(created_time_usec);
  928. const base::Time updated_time = ProtoTimeToTime(updated_time_usec);
  929. std::unique_ptr<ash::DeskTemplate> desk_template =
  930. std::make_unique<ash::DeskTemplate>(
  931. std::move(uuid), source, name, created_time,
  932. GetDeskTypeFromString(desk_type_string));
  933. desk_template->set_updated_time(updated_time);
  934. desk_template->set_desk_restore_data(ConvertJsonToRestoreData(desk));
  935. return desk_template;
  936. }
  937. base::Value SerializeDeskTemplateAsPolicy(const ash::DeskTemplate* desk,
  938. apps::AppRegistryCache* app_cache) {
  939. base::Value desk_dict(base::Value::Type::DICTIONARY);
  940. desk_dict.SetKey(kVersion, base::Value(kVersionNum));
  941. desk_dict.SetKey(kUuid, base::Value(desk->uuid().AsLowercaseString()));
  942. desk_dict.SetKey(kName, base::Value(desk->template_name()));
  943. desk_dict.SetKey(kCreatedTime, base::TimeToValue(desk->created_time()));
  944. desk_dict.SetKey(kUpdatedTime, base::TimeToValue(desk->GetLastUpdatedTime()));
  945. desk_dict.SetKey(kDeskType,
  946. base::Value(SerializeDeskTypeAsString(desk->type())));
  947. desk_dict.SetKey(
  948. kDesk, ConvertRestoreDataToValue(desk->desk_restore_data(), app_cache));
  949. return desk_dict;
  950. }
  951. WindowOpenDisposition ToBaseWindowOpenDisposition(
  952. SyncWindowOpenDisposition disposition) {
  953. switch (disposition) {
  954. case sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_UNKNOWN:
  955. return WindowOpenDisposition::UNKNOWN;
  956. case sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_CURRENT_TAB:
  957. return WindowOpenDisposition::CURRENT_TAB;
  958. case sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_SINGLETON_TAB:
  959. return WindowOpenDisposition::SINGLETON_TAB;
  960. case sync_pb::
  961. WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_FOREGROUND_TAB:
  962. return WindowOpenDisposition::NEW_FOREGROUND_TAB;
  963. case sync_pb::
  964. WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_BACKGROUND_TAB:
  965. return WindowOpenDisposition::NEW_BACKGROUND_TAB;
  966. case sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_POPUP:
  967. return WindowOpenDisposition::NEW_POPUP;
  968. case sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_WINDOW:
  969. return WindowOpenDisposition::NEW_WINDOW;
  970. case sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_SAVE_TO_DISK:
  971. return WindowOpenDisposition::SAVE_TO_DISK;
  972. case sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_OFF_THE_RECORD:
  973. return WindowOpenDisposition::OFF_THE_RECORD;
  974. case sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_IGNORE_ACTION:
  975. return WindowOpenDisposition::IGNORE_ACTION;
  976. case sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_SWITCH_TO_TAB:
  977. return WindowOpenDisposition::SWITCH_TO_TAB;
  978. case sync_pb::
  979. WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_PICTURE_IN_PICTURE:
  980. return WindowOpenDisposition::NEW_PICTURE_IN_PICTURE;
  981. }
  982. }
  983. SyncWindowOpenDisposition FromBaseWindowOpenDisposition(
  984. WindowOpenDisposition disposition) {
  985. switch (disposition) {
  986. case WindowOpenDisposition::UNKNOWN:
  987. return sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_UNKNOWN;
  988. case WindowOpenDisposition::CURRENT_TAB:
  989. return sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_CURRENT_TAB;
  990. case WindowOpenDisposition::SINGLETON_TAB:
  991. return sync_pb::
  992. WorkspaceDeskSpecifics_WindowOpenDisposition_SINGLETON_TAB;
  993. case WindowOpenDisposition::NEW_FOREGROUND_TAB:
  994. return sync_pb::
  995. WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_FOREGROUND_TAB;
  996. case WindowOpenDisposition::NEW_BACKGROUND_TAB:
  997. return sync_pb::
  998. WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_BACKGROUND_TAB;
  999. case WindowOpenDisposition::NEW_POPUP:
  1000. return sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_POPUP;
  1001. case WindowOpenDisposition::NEW_WINDOW:
  1002. return sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_WINDOW;
  1003. case WindowOpenDisposition::SAVE_TO_DISK:
  1004. return sync_pb::WorkspaceDeskSpecifics_WindowOpenDisposition_SAVE_TO_DISK;
  1005. case WindowOpenDisposition::OFF_THE_RECORD:
  1006. return sync_pb::
  1007. WorkspaceDeskSpecifics_WindowOpenDisposition_OFF_THE_RECORD;
  1008. case WindowOpenDisposition::IGNORE_ACTION:
  1009. return sync_pb::
  1010. WorkspaceDeskSpecifics_WindowOpenDisposition_IGNORE_ACTION;
  1011. case WindowOpenDisposition::SWITCH_TO_TAB:
  1012. return sync_pb::
  1013. WorkspaceDeskSpecifics_WindowOpenDisposition_SWITCH_TO_TAB;
  1014. case WindowOpenDisposition::NEW_PICTURE_IN_PICTURE:
  1015. return sync_pb::
  1016. WorkspaceDeskSpecifics_WindowOpenDisposition_NEW_PICTURE_IN_PICTURE;
  1017. }
  1018. }
  1019. SyncLaunchContainer FromLaunchContainer(apps::LaunchContainer container) {
  1020. switch (container) {
  1021. case apps::LaunchContainer::kLaunchContainerWindow:
  1022. return sync_pb::
  1023. WorkspaceDeskSpecifics_LaunchContainer_LAUNCH_CONTAINER_WINDOW;
  1024. case apps::LaunchContainer::kLaunchContainerPanelDeprecated:
  1025. return sync_pb::
  1026. WorkspaceDeskSpecifics_LaunchContainer_LAUNCH_CONTAINER_PANEL_DEPRECATED;
  1027. case apps::LaunchContainer::kLaunchContainerTab:
  1028. return sync_pb::
  1029. WorkspaceDeskSpecifics_LaunchContainer_LAUNCH_CONTAINER_TAB;
  1030. case apps::LaunchContainer::kLaunchContainerNone:
  1031. return sync_pb::
  1032. WorkspaceDeskSpecifics_LaunchContainer_LAUNCH_CONTAINER_NONE;
  1033. }
  1034. }
  1035. apps::LaunchContainer ToLaunchContainer(SyncLaunchContainer container) {
  1036. switch (container) {
  1037. case sync_pb::
  1038. WorkspaceDeskSpecifics_LaunchContainer_LAUNCH_CONTAINER_UNSPECIFIED:
  1039. return apps::LaunchContainer::kLaunchContainerWindow;
  1040. case sync_pb::
  1041. WorkspaceDeskSpecifics_LaunchContainer_LAUNCH_CONTAINER_WINDOW:
  1042. return apps::LaunchContainer::kLaunchContainerWindow;
  1043. case sync_pb::
  1044. WorkspaceDeskSpecifics_LaunchContainer_LAUNCH_CONTAINER_PANEL_DEPRECATED:
  1045. return apps::LaunchContainer::kLaunchContainerPanelDeprecated;
  1046. case sync_pb::WorkspaceDeskSpecifics_LaunchContainer_LAUNCH_CONTAINER_TAB:
  1047. return apps::LaunchContainer::kLaunchContainerTab;
  1048. case sync_pb::WorkspaceDeskSpecifics_LaunchContainer_LAUNCH_CONTAINER_NONE:
  1049. return apps::LaunchContainer::kLaunchContainerNone;
  1050. }
  1051. }
  1052. } // namespace desk_template_conversion
  1053. } // namespace desks_storage