display_prefs.cc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. // Copyright (c) 2012 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/display/display_prefs.h"
  5. #include <stddef.h>
  6. #include <string>
  7. #include "ash/constants/ash_pref_names.h"
  8. #include "ash/constants/ash_switches.h"
  9. #include "ash/session/session_controller_impl.h"
  10. #include "ash/shell.h"
  11. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  12. #include "base/command_line.h"
  13. #include "base/containers/contains.h"
  14. #include "base/strings/string_number_conversions.h"
  15. #include "base/strings/string_split.h"
  16. #include "base/strings/string_util.h"
  17. #include "base/system/sys_info.h"
  18. #include "base/values.h"
  19. #include "components/prefs/pref_registry_simple.h"
  20. #include "components/prefs/pref_service.h"
  21. #include "components/prefs/scoped_user_pref_update.h"
  22. #include "third_party/cros_system_api/dbus/service_constants.h"
  23. #include "ui/display/display_features.h"
  24. #include "ui/display/display_switches.h"
  25. #include "ui/display/manager/display_layout_store.h"
  26. #include "ui/display/manager/display_manager.h"
  27. #include "ui/display/manager/display_manager_utilities.h"
  28. #include "ui/display/manager/json_converter.h"
  29. #include "ui/display/types/display_constants.h"
  30. #include "ui/display/util/display_util.h"
  31. #include "ui/gfx/geometry/insets.h"
  32. #include "url/url_canon.h"
  33. #include "url/url_util.h"
  34. using chromeos::DisplayPowerState;
  35. namespace ash {
  36. namespace {
  37. constexpr char kInsetsTopKey[] = "insets_top";
  38. constexpr char kInsetsLeftKey[] = "insets_left";
  39. constexpr char kInsetsBottomKey[] = "insets_bottom";
  40. constexpr char kInsetsRightKey[] = "insets_right";
  41. constexpr char kTouchCalibrationWidth[] = "touch_calibration_width";
  42. constexpr char kTouchCalibrationHeight[] = "touch_calibration_height";
  43. constexpr char kTouchCalibrationPointPairs[] = "touch_calibration_point_pairs";
  44. constexpr char kTouchAssociationTimestamp[] = "touch_association_timestamp";
  45. constexpr char kTouchAssociationCalibrationData[] =
  46. "touch_association_calibration_data";
  47. constexpr char kTouchDeviceIdentifier[] = "touch_device_identifer";
  48. constexpr char kPortAssociationDisplayId[] = "port_association_display_id";
  49. constexpr char kMirroringSourceId[] = "mirroring_source_id";
  50. constexpr char kMirroringDestinationIds[] = "mirroring_destination_ids";
  51. constexpr char kDisplayZoom[] = "display_zoom_factor";
  52. constexpr char kDisplayPowerAllOn[] = "all_on";
  53. constexpr char kDisplayPowerInternalOffExternalOn[] =
  54. "internal_off_external_on";
  55. constexpr char kDisplayPowerInternalOnExternalOff[] =
  56. "internal_on_external_off";
  57. // This kind of boilerplates should be done by base::JSONValueConverter but it
  58. // doesn't support classes like gfx::Insets for now.
  59. // TODO(mukai): fix base::JSONValueConverter and use it here.
  60. bool ValueToInsets(const base::Value::Dict& dict, gfx::Insets* insets) {
  61. DCHECK(insets);
  62. absl::optional<int> top = dict.FindInt(kInsetsTopKey);
  63. absl::optional<int> left = dict.FindInt(kInsetsLeftKey);
  64. absl::optional<int> bottom = dict.FindInt(kInsetsBottomKey);
  65. absl::optional<int> right = dict.FindInt(kInsetsRightKey);
  66. if (top && left && bottom && right) {
  67. *insets = gfx::Insets::TLBR(*top, *left, *bottom, *right);
  68. return true;
  69. }
  70. return false;
  71. }
  72. void InsetsToValue(const gfx::Insets& insets, base::Value::Dict& dict) {
  73. dict.Set(kInsetsTopKey, insets.top());
  74. dict.Set(kInsetsLeftKey, insets.left());
  75. dict.Set(kInsetsBottomKey, insets.bottom());
  76. dict.Set(kInsetsRightKey, insets.right());
  77. }
  78. // Unmarshalls the string containing CalibrationPointPairQuad and populates
  79. // |point_pair_quad| with the unmarshalled data.
  80. bool ParseTouchCalibrationStringValue(
  81. const std::string& str,
  82. display::TouchCalibrationData::CalibrationPointPairQuad* point_pair_quad) {
  83. DCHECK(point_pair_quad);
  84. int x = 0, y = 0;
  85. std::vector<std::string> parts = base::SplitString(
  86. str, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  87. size_t total = point_pair_quad->size();
  88. gfx::Point display_point, touch_point;
  89. for (std::size_t row = 0; row < total; row++) {
  90. if (!base::StringToInt(parts[row * total], &x) ||
  91. !base::StringToInt(parts[row * total + 1], &y)) {
  92. return false;
  93. }
  94. display_point.SetPoint(x, y);
  95. if (!base::StringToInt(parts[row * total + 2], &x) ||
  96. !base::StringToInt(parts[row * total + 3], &y)) {
  97. return false;
  98. }
  99. touch_point.SetPoint(x, y);
  100. (*point_pair_quad)[row] = std::make_pair(display_point, touch_point);
  101. }
  102. return true;
  103. }
  104. // Retrieves touch calibration associated data from the dictionary and stores
  105. // it in an instance of TouchCalibrationData struct.
  106. bool ValueToTouchData(const base::Value::Dict& dict,
  107. display::TouchCalibrationData* touch_calibration_data) {
  108. display::TouchCalibrationData::CalibrationPointPairQuad* point_pair_quad =
  109. &(touch_calibration_data->point_pairs);
  110. const std::string* str = dict.FindString(kTouchCalibrationPointPairs);
  111. if (!str)
  112. return false;
  113. if (!ParseTouchCalibrationStringValue(*str, point_pair_quad))
  114. return false;
  115. absl::optional<int> width = dict.FindInt(kTouchCalibrationWidth);
  116. absl::optional<int> height = dict.FindInt(kTouchCalibrationHeight);
  117. if (!width || !height) {
  118. return false;
  119. }
  120. touch_calibration_data->bounds = gfx::Size(*width, *height);
  121. return true;
  122. }
  123. // Stores the touch calibration data into the dictionary.
  124. void TouchDataToValue(
  125. const display::TouchCalibrationData& touch_calibration_data,
  126. base::Value::Dict& dict) {
  127. std::string str;
  128. for (std::size_t row = 0; row < touch_calibration_data.point_pairs.size();
  129. row++) {
  130. str += base::NumberToString(
  131. touch_calibration_data.point_pairs[row].first.x()) +
  132. " ";
  133. str += base::NumberToString(
  134. touch_calibration_data.point_pairs[row].first.y()) +
  135. " ";
  136. str += base::NumberToString(
  137. touch_calibration_data.point_pairs[row].second.x()) +
  138. " ";
  139. str += base::NumberToString(
  140. touch_calibration_data.point_pairs[row].second.y());
  141. if (row != touch_calibration_data.point_pairs.size() - 1)
  142. str += " ";
  143. }
  144. dict.Set(kTouchCalibrationPointPairs, str);
  145. dict.Set(kTouchCalibrationWidth, touch_calibration_data.bounds.width());
  146. dict.Set(kTouchCalibrationHeight, touch_calibration_data.bounds.height());
  147. }
  148. display::DisplayManager* GetDisplayManager() {
  149. return Shell::Get()->display_manager();
  150. }
  151. // Returns true if the current user can write display preferences to
  152. // Local State.
  153. bool UserCanSaveDisplayPreference() {
  154. SessionControllerImpl* controller = Shell::Get()->session_controller();
  155. auto user_type = controller->GetUserType();
  156. if (!user_type)
  157. return false;
  158. return *user_type == user_manager::USER_TYPE_REGULAR ||
  159. *user_type == user_manager::USER_TYPE_CHILD ||
  160. *user_type == user_manager::USER_TYPE_KIOSK_APP ||
  161. (*user_type == user_manager::USER_TYPE_PUBLIC_ACCOUNT &&
  162. Shell::Get()->local_state()->GetBoolean(
  163. prefs::kAllowMGSToStoreDisplayProperties));
  164. }
  165. void LoadDisplayLayouts(PrefService* local_state) {
  166. display::DisplayLayoutStore* layout_store =
  167. GetDisplayManager()->layout_store();
  168. for (const auto it : local_state->GetValueDict(prefs::kSecondaryDisplays)) {
  169. std::unique_ptr<display::DisplayLayout> layout(new display::DisplayLayout);
  170. if (!display::JsonToDisplayLayout(it.second, layout.get())) {
  171. LOG(WARNING) << "Invalid preference value for " << it.first;
  172. continue;
  173. }
  174. if (it.first.find(",") != std::string::npos) {
  175. std::vector<std::string> ids_str = base::SplitString(
  176. it.first, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
  177. std::vector<int64_t> ids;
  178. for (std::string id_str : ids_str) {
  179. int64_t id;
  180. if (!base::StringToInt64(id_str, &id))
  181. continue;
  182. ids.push_back(id);
  183. }
  184. display::DisplayIdList list =
  185. display::GenerateDisplayIdList(ids.begin(), ids.end());
  186. layout_store->RegisterLayoutForDisplayIdList(list, std::move(layout));
  187. }
  188. }
  189. }
  190. void LoadDisplayProperties(PrefService* local_state) {
  191. for (const auto it : local_state->GetValueDict(prefs::kDisplayProperties)) {
  192. const base::Value::Dict* dict_value = it.second.GetIfDict();
  193. if (!dict_value)
  194. continue;
  195. int64_t id = display::kInvalidDisplayId;
  196. if (!base::StringToInt64(it.first, &id) ||
  197. id == display::kInvalidDisplayId) {
  198. continue;
  199. }
  200. const gfx::Insets* insets_to_set = nullptr;
  201. display::Display::Rotation rotation = display::Display::ROTATE_0;
  202. if (absl::optional<int> rotation_value = dict_value->FindInt("rotation")) {
  203. rotation = static_cast<display::Display::Rotation>(*rotation_value);
  204. }
  205. int width = dict_value->FindInt("width").value_or(0);
  206. int height = dict_value->FindInt("height").value_or(0);
  207. gfx::Size resolution_in_pixels(width, height);
  208. float device_scale_factor = 1.0;
  209. if (absl::optional<int> dsf_value =
  210. dict_value->FindInt("device-scale-factor")) {
  211. device_scale_factor = static_cast<float>(*dsf_value) / 1000.0f;
  212. }
  213. // Default refresh rate is 60 Hz, until
  214. // DisplayManager::OnNativeDisplaysChanged() updates us with the actual
  215. // display info.
  216. double refresh_rate = 60.0;
  217. bool is_interlaced = false;
  218. if (display::features::IsListAllDisplayModesEnabled()) {
  219. refresh_rate =
  220. dict_value->FindDouble("refresh-rate").value_or(refresh_rate);
  221. absl::optional<bool> is_interlaced_opt =
  222. dict_value->FindBool("interlaced");
  223. is_interlaced = is_interlaced_opt.value_or(false);
  224. }
  225. gfx::Insets insets;
  226. if (ValueToInsets(*dict_value, &insets))
  227. insets_to_set = &insets;
  228. double display_zoom = dict_value->FindDouble(kDisplayZoom).value_or(1.0);
  229. GetDisplayManager()->RegisterDisplayProperty(
  230. id, rotation, insets_to_set, resolution_in_pixels, device_scale_factor,
  231. display_zoom, refresh_rate, is_interlaced);
  232. }
  233. }
  234. void LoadDisplayRotationState(PrefService* local_state) {
  235. const base::Value::Dict& properties =
  236. local_state->GetValueDict(prefs::kDisplayRotationLock);
  237. const absl::optional<bool> rotation_lock = properties.FindBool("lock");
  238. if (!rotation_lock)
  239. return;
  240. const absl::optional<int> rotation = properties.FindInt("orientation");
  241. if (!rotation)
  242. return;
  243. GetDisplayManager()->RegisterDisplayRotationProperties(
  244. *rotation_lock, static_cast<display::Display::Rotation>(*rotation));
  245. }
  246. void LoadDisplayTouchAssociations(PrefService* local_state) {
  247. display::TouchDeviceManager::TouchAssociationMap touch_associations;
  248. for (const auto item :
  249. local_state->GetValueDict(prefs::kDisplayTouchAssociations)) {
  250. uint32_t identifier_raw;
  251. if (!base::StringToUint(item.first, &identifier_raw))
  252. continue;
  253. display::TouchDeviceIdentifier identifier(identifier_raw);
  254. touch_associations.emplace(
  255. identifier, display::TouchDeviceManager::AssociationInfoMap());
  256. if (!item.second.is_dict())
  257. continue;
  258. for (const auto association_info_item : item.second.GetDict()) {
  259. display::TouchDeviceManager::TouchAssociationInfo info;
  260. int64_t display_id;
  261. if (!base::StringToInt64(association_info_item.first, &display_id))
  262. continue;
  263. absl::optional<double> value =
  264. association_info_item.second.GetDict().FindDouble(
  265. kTouchAssociationTimestamp);
  266. if (!value)
  267. continue;
  268. info.timestamp = base::Time().FromDoubleT(*value);
  269. const base::Value::Dict* calibration_data_dict =
  270. association_info_item.second.GetDict().FindDict(
  271. kTouchAssociationCalibrationData);
  272. if (!calibration_data_dict)
  273. continue;
  274. ValueToTouchData(*calibration_data_dict, &info.calibration_data);
  275. touch_associations.at(identifier).emplace(display_id, info);
  276. }
  277. }
  278. // Retrieve all the legacy format identifiers. This should be removed after
  279. // a couple of milestones when everything is stable.
  280. const display::TouchDeviceIdentifier& fallback_identifier =
  281. display::TouchDeviceIdentifier::GetFallbackTouchDeviceIdentifier();
  282. for (const auto it : local_state->GetValueDict(prefs::kDisplayProperties)) {
  283. const base::Value::Dict* dict_value = it.second.GetIfDict();
  284. if (!dict_value)
  285. continue;
  286. int64_t id = display::kInvalidDisplayId;
  287. if (!base::StringToInt64(it.first, &id) ||
  288. id == display::kInvalidDisplayId) {
  289. continue;
  290. }
  291. display::TouchCalibrationData calibration_data;
  292. display::TouchCalibrationData* calibration_data_to_set = nullptr;
  293. if (ValueToTouchData(*dict_value, &calibration_data))
  294. calibration_data_to_set = &calibration_data;
  295. if (calibration_data_to_set) {
  296. if (!base::Contains(touch_associations, fallback_identifier)) {
  297. touch_associations.emplace(
  298. fallback_identifier,
  299. display::TouchDeviceManager::AssociationInfoMap());
  300. }
  301. display::TouchDeviceManager::TouchAssociationInfo info;
  302. info.calibration_data = *calibration_data_to_set;
  303. touch_associations.at(fallback_identifier).emplace(id, info);
  304. }
  305. }
  306. // Retrieve port association information.
  307. display::TouchDeviceManager::PortAssociationMap port_associations;
  308. for (const auto item :
  309. local_state->GetValueDict(prefs::kDisplayTouchPortAssociations)) {
  310. // Retrieve the secondary id that identifies the port.
  311. uint32_t secondary_id_raw;
  312. if (!base::StringToUint(item.first, &secondary_id_raw))
  313. continue;
  314. if (!item.second.is_dict())
  315. continue;
  316. // Retrieve the touch device identifier that identifies the touch device.
  317. const std::string* value =
  318. item.second.GetDict().FindString(kTouchDeviceIdentifier);
  319. if (!value)
  320. continue;
  321. uint32_t identifier_raw;
  322. if (!base::StringToUint(*value, &identifier_raw))
  323. continue;
  324. // Retrieve the display that the touch device identified by |identifier_raw|
  325. // was associated with.
  326. value = item.second.GetDict().FindString(kPortAssociationDisplayId);
  327. if (!value)
  328. continue;
  329. int64_t display_id;
  330. if (!base::StringToInt64(*value, &display_id))
  331. continue;
  332. port_associations.emplace(
  333. std::piecewise_construct,
  334. std::forward_as_tuple(identifier_raw, secondary_id_raw),
  335. std::forward_as_tuple(display_id));
  336. }
  337. GetDisplayManager()->touch_device_manager()->RegisterTouchAssociations(
  338. touch_associations, port_associations);
  339. }
  340. // Loads mirror info for each external display, the info will later be used to
  341. // restore mirror mode.
  342. void LoadExternalDisplayMirrorInfo(PrefService* local_state) {
  343. const base::Value::List& pref_data =
  344. local_state->GetValueList(prefs::kExternalDisplayMirrorInfo);
  345. std::set<int64_t> external_display_mirror_info;
  346. for (const auto& it : pref_data) {
  347. const std::string* display_id_str = it.GetIfString();
  348. if (!display_id_str)
  349. continue;
  350. int64_t display_id;
  351. if (!base::StringToInt64(*display_id_str, &display_id))
  352. continue;
  353. external_display_mirror_info.emplace(display_id);
  354. }
  355. GetDisplayManager()->set_external_display_mirror_info(
  356. external_display_mirror_info);
  357. }
  358. // Loads mixed mirror mode parameters which will later be used to restore mixed
  359. // mirror mode. Return false if the parameters fail to be loaded.
  360. void LoadDisplayMixedMirrorModeParams(PrefService* local_state) {
  361. const base::Value::Dict& pref_data =
  362. local_state->GetValueDict(prefs::kDisplayMixedMirrorModeParams);
  363. // This function is called once for system (re)start, so the parameters should
  364. // be empty.
  365. DCHECK(!GetDisplayManager()->mixed_mirror_mode_params());
  366. auto* mirroring_source_id_value = pref_data.Find(kMirroringSourceId);
  367. if (!mirroring_source_id_value)
  368. return;
  369. DCHECK(mirroring_source_id_value->is_string());
  370. int64_t mirroring_source_id;
  371. if (!base::StringToInt64(mirroring_source_id_value->GetString(),
  372. &mirroring_source_id)) {
  373. return;
  374. }
  375. auto* mirroring_destination_ids_value =
  376. pref_data.Find(kMirroringDestinationIds);
  377. if (!mirroring_destination_ids_value)
  378. return;
  379. DCHECK(mirroring_destination_ids_value->is_list());
  380. display::DisplayIdList mirroring_destination_ids;
  381. for (const auto& entry : mirroring_destination_ids_value->GetList()) {
  382. DCHECK(entry.is_string());
  383. int64_t id;
  384. if (!base::StringToInt64(entry.GetString(), &id))
  385. return;
  386. mirroring_destination_ids.emplace_back(id);
  387. }
  388. GetDisplayManager()->set_mixed_mirror_mode_params(
  389. absl::optional<display::MixedMirrorModeParams>(
  390. absl::in_place, mirroring_source_id, mirroring_destination_ids));
  391. }
  392. void StoreDisplayLayoutPref(PrefService* pref_service,
  393. const display::DisplayIdList& list,
  394. const display::DisplayLayout& display_layout) {
  395. DCHECK(display::DisplayLayout::Validate(list, display_layout));
  396. std::string name = display::DisplayIdListToString(list);
  397. DictionaryPrefUpdate update(pref_service, prefs::kSecondaryDisplays);
  398. base::Value::Dict& pref_data = update->GetDict();
  399. base::Value::Dict* layout_dict = pref_data.EnsureDict(name);
  400. // This call modifies `layout_dict` in place.
  401. display::DisplayLayoutToJson(display_layout, *layout_dict);
  402. }
  403. void StoreCurrentDisplayLayoutPrefs(PrefService* pref_service) {
  404. display::DisplayManager* display_manager = GetDisplayManager();
  405. if (!UserCanSaveDisplayPreference() ||
  406. display_manager->num_connected_displays() < 2) {
  407. return;
  408. }
  409. display::DisplayIdList list = display_manager->GetConnectedDisplayIdList();
  410. const display::DisplayLayout& display_layout =
  411. display_manager->layout_store()->GetRegisteredDisplayLayout(list);
  412. if (!display::DisplayLayout::Validate(list, display_layout)) {
  413. // We should never apply an invalid layout, if we do, it persists and the
  414. // user has no way of fixing it except by deleting the local state.
  415. LOG(ERROR) << "Attempting to store an invalid display layout in the local"
  416. << " state. Skipping.";
  417. return;
  418. }
  419. StoreDisplayLayoutPref(pref_service, list, display_layout);
  420. }
  421. void StoreCurrentDisplayProperties(PrefService* pref_service) {
  422. display::DisplayManager* display_manager = GetDisplayManager();
  423. DictionaryPrefUpdate update(pref_service, prefs::kDisplayProperties);
  424. base::Value::Dict& pref_data = update->GetDict();
  425. // Pre-process data related to legacy touch calibration to opitmize lookup.
  426. const display::TouchDeviceIdentifier& fallback_identifier =
  427. display::TouchDeviceIdentifier::GetFallbackTouchDeviceIdentifier();
  428. display::TouchDeviceManager::AssociationInfoMap legacy_data_map;
  429. if (base::Contains(
  430. display_manager->touch_device_manager()->touch_associations(),
  431. fallback_identifier)) {
  432. legacy_data_map =
  433. display_manager->touch_device_manager()->touch_associations().at(
  434. fallback_identifier);
  435. }
  436. size_t num = display_manager->GetNumDisplays();
  437. for (size_t i = 0; i < num; ++i) {
  438. const display::Display& display = display_manager->GetDisplayAt(i);
  439. int64_t id = display.id();
  440. display::ManagedDisplayInfo info = display_manager->GetDisplayInfo(id);
  441. base::Value::Dict property_value;
  442. // Don't save the display preference in unified mode because its
  443. // size and modes can change depending on the combination of displays.
  444. if (display_manager->IsInUnifiedMode())
  445. continue;
  446. // Don't save rotation when in tablet mode, so that if the device is
  447. // rebooted into clamshell mode, it won't have an unexpected rotation.
  448. // https://crbug.com/733092.
  449. // But we should keep any original value so that it can be restored when
  450. // exiting tablet mode.
  451. if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
  452. const base::Value::Dict* original_property =
  453. pref_data.FindDict(base::NumberToString(id));
  454. if (original_property) {
  455. absl::optional<int> original_rotation =
  456. original_property->FindInt("rotation");
  457. if (original_rotation) {
  458. property_value.Set("rotation", *original_rotation);
  459. }
  460. }
  461. } else {
  462. property_value.Set("rotation",
  463. static_cast<int>(info.GetRotation(
  464. display::Display::RotationSource::USER)));
  465. }
  466. display::ManagedDisplayMode mode;
  467. if (!display.IsInternal() &&
  468. display_manager->GetSelectedModeForDisplayId(id, &mode) &&
  469. !mode.native()) {
  470. property_value.Set("width", mode.size().width());
  471. property_value.Set("height", mode.size().height());
  472. property_value.Set("device-scale-factor",
  473. static_cast<int>(mode.device_scale_factor() * 1000));
  474. if (display::features::IsListAllDisplayModesEnabled()) {
  475. property_value.Set("interlaced", mode.is_interlaced());
  476. property_value.Set("refresh-rate", mode.refresh_rate());
  477. }
  478. }
  479. if (!info.overscan_insets_in_dip().IsEmpty())
  480. InsetsToValue(info.overscan_insets_in_dip(), property_value);
  481. // Store the legacy format touch calibration data. This can be removed after
  482. // a couple of milestones when every device has migrated to the new format.
  483. if (legacy_data_map.size() && base::Contains(legacy_data_map, id)) {
  484. TouchDataToValue(legacy_data_map.at(id).calibration_data, property_value);
  485. }
  486. property_value.Set(kDisplayZoom, info.zoom_factor());
  487. pref_data.Set(base::NumberToString(id), std::move(property_value));
  488. }
  489. }
  490. bool GetDisplayPowerStateFromString(const std::string& state_string,
  491. chromeos::DisplayPowerState* power_state) {
  492. if (state_string == kDisplayPowerAllOn) {
  493. *power_state = chromeos::DISPLAY_POWER_ALL_ON;
  494. } else if (state_string == kDisplayPowerInternalOffExternalOn) {
  495. *power_state = chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON;
  496. } else if (state_string == kDisplayPowerInternalOnExternalOff) {
  497. *power_state = chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF;
  498. } else {
  499. // Don't restore ALL_OFF state. http://crbug.com/318456.
  500. return false;
  501. }
  502. return true;
  503. }
  504. void StoreDisplayPowerState(PrefService* pref_service,
  505. DisplayPowerState power_state) {
  506. const char* state_string = nullptr;
  507. switch (power_state) {
  508. case chromeos::DISPLAY_POWER_ALL_ON:
  509. state_string = kDisplayPowerAllOn;
  510. break;
  511. case chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON:
  512. state_string = kDisplayPowerInternalOffExternalOn;
  513. break;
  514. case chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF:
  515. state_string = kDisplayPowerInternalOnExternalOff;
  516. break;
  517. case chromeos::DISPLAY_POWER_ALL_OFF:
  518. // Don't store ALL_OFF state. http://crbug.com/318456.
  519. break;
  520. }
  521. if (state_string)
  522. pref_service->Set(prefs::kDisplayPowerState, base::Value(state_string));
  523. }
  524. void StoreCurrentDisplayPowerState(PrefService* pref_service) {
  525. StoreDisplayPowerState(
  526. pref_service,
  527. Shell::Get()->display_configurator()->GetRequestedPowerState());
  528. }
  529. void StoreDisplayRotationPrefs(PrefService* pref_service,
  530. display::Display::Rotation rotation,
  531. bool rotation_lock) {
  532. DictionaryPrefUpdate update(pref_service, prefs::kDisplayRotationLock);
  533. base::Value::Dict& pref_data = update->GetDict();
  534. pref_data.Set("lock", rotation_lock);
  535. pref_data.Set("orientation", static_cast<int>(rotation));
  536. }
  537. void StoreCurrentDisplayRotationLockPrefs(PrefService* pref_service) {
  538. if (!display::HasInternalDisplay())
  539. return;
  540. display::Display::Rotation rotation =
  541. GetDisplayManager()
  542. ->GetDisplayInfo(display::Display::InternalDisplayId())
  543. .GetRotation(display::Display::RotationSource::ACCELEROMETER);
  544. bool rotation_lock = Shell::Get()
  545. ->display_manager()
  546. ->registered_internal_display_rotation_lock();
  547. StoreDisplayRotationPrefs(pref_service, rotation, rotation_lock);
  548. }
  549. void StoreDisplayTouchAssociations(PrefService* pref_service) {
  550. display::TouchDeviceManager* touch_device_manager =
  551. GetDisplayManager()->touch_device_manager();
  552. DictionaryPrefUpdate update(pref_service, prefs::kDisplayTouchAssociations);
  553. base::Value::Dict& pref_data = update->GetDict();
  554. pref_data.clear();
  555. const display::TouchDeviceManager::TouchAssociationMap& touch_associations =
  556. touch_device_manager->touch_associations();
  557. for (const auto& association : touch_associations) {
  558. base::Value::Dict association_info_map_value;
  559. for (const auto& association_info : association.second) {
  560. // Iteration for each pair of <Display ID, TouchAssociationInfo>.
  561. base::Value::Dict association_info_value;
  562. // Parsing each member of TouchAssociationInfo and storing them in
  563. // |association_info_value|.
  564. // Serialize timestamp.
  565. association_info_value.Set(kTouchAssociationTimestamp,
  566. association_info.second.timestamp.ToDoubleT());
  567. // Serialize TouchCalibrationData.
  568. base::Value::Dict calibration_data_value;
  569. TouchDataToValue(association_info.second.calibration_data,
  570. calibration_data_value);
  571. association_info_value.Set(kTouchAssociationCalibrationData,
  572. std::move(calibration_data_value));
  573. // Move the searialzed TouchAssociationInfo stored in
  574. // |association_info_value| to |association_info_map_value| against the
  575. // display id as key. This is a 1 to 1 mapping of a single entry from
  576. // AssociationInfoMap to its serialized form.
  577. association_info_map_value.Set(
  578. base::NumberToString(association_info.first),
  579. std::move(association_info_value));
  580. }
  581. if (association_info_map_value.empty())
  582. continue;
  583. // Move the already serialized entry of AssociationInfoMap from
  584. // |association_info_map_value| to |pref_data| against the
  585. // TouchDeviceIdentifier as key. This is a 1 to 1 mapping of a single entry
  586. // from TouchAssociationMap to its serialized form.
  587. pref_data.Set(association.first.ToString(),
  588. std::move(association_info_map_value));
  589. }
  590. // Store the port mappings. What display a touch device connected to a
  591. // particular port is associated with.
  592. DictionaryPrefUpdate update_port(pref_service,
  593. prefs::kDisplayTouchPortAssociations);
  594. base::Value::Dict& port_pref_data = update_port->GetDict();
  595. port_pref_data.clear();
  596. const display::TouchDeviceManager::PortAssociationMap& port_associations =
  597. touch_device_manager->port_associations();
  598. // For each port identified by the secondary id of TouchDeviceIdentifier,
  599. // we store the touch device and the display associated with it.
  600. for (const auto& association : port_associations) {
  601. base::Value::Dict association_info_value;
  602. association_info_value.Set(kTouchDeviceIdentifier,
  603. association.first.ToString());
  604. association_info_value.Set(kPortAssociationDisplayId,
  605. base::NumberToString(association.second));
  606. port_pref_data.Set(association.first.SecondaryIdToString(),
  607. std::move(association_info_value));
  608. }
  609. }
  610. // Stores mirror info for each external display.
  611. void StoreExternalDisplayMirrorInfo(PrefService* pref_service) {
  612. ListPrefUpdate update(pref_service, prefs::kExternalDisplayMirrorInfo);
  613. base::Value::List& pref_data = update->GetList();
  614. pref_data.clear();
  615. const std::set<int64_t>& external_display_mirror_info =
  616. GetDisplayManager()->external_display_mirror_info();
  617. for (const auto& id : external_display_mirror_info)
  618. pref_data.Append(base::NumberToString(id));
  619. }
  620. // Stores mixed mirror mode parameters. Clear the preferences if
  621. // |mixed_mirror_mode_params| is null.
  622. void StoreDisplayMixedMirrorModeParams(
  623. PrefService* pref_service,
  624. const absl::optional<display::MixedMirrorModeParams>& mixed_params) {
  625. DictionaryPrefUpdate update(pref_service,
  626. prefs::kDisplayMixedMirrorModeParams);
  627. base::Value::Dict& pref_data = update->GetDict();
  628. pref_data.clear();
  629. if (!mixed_params)
  630. return;
  631. pref_data.Set(kMirroringSourceId,
  632. base::NumberToString(mixed_params->source_id));
  633. base::Value::List mirroring_destination_ids_list;
  634. for (const auto& id : mixed_params->destination_ids) {
  635. mirroring_destination_ids_list.Append(base::NumberToString(id));
  636. }
  637. pref_data.Set(kMirroringDestinationIds,
  638. std::move(mirroring_destination_ids_list));
  639. }
  640. void StoreCurrentDisplayMixedMirrorModeParams(PrefService* pref_service) {
  641. StoreDisplayMixedMirrorModeParams(
  642. pref_service, GetDisplayManager()->mixed_mirror_mode_params());
  643. }
  644. } // namespace
  645. // static
  646. void DisplayPrefs::RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
  647. registry->RegisterDictionaryPref(prefs::kSecondaryDisplays);
  648. registry->RegisterDictionaryPref(prefs::kDisplayProperties);
  649. registry->RegisterStringPref(prefs::kDisplayPowerState, kDisplayPowerAllOn);
  650. registry->RegisterDictionaryPref(prefs::kDisplayRotationLock);
  651. registry->RegisterDictionaryPref(prefs::kDisplayTouchAssociations);
  652. registry->RegisterDictionaryPref(prefs::kDisplayTouchPortAssociations);
  653. registry->RegisterListPref(prefs::kExternalDisplayMirrorInfo);
  654. registry->RegisterDictionaryPref(prefs::kDisplayMixedMirrorModeParams);
  655. registry->RegisterBooleanPref(prefs::kAllowMGSToStoreDisplayProperties,
  656. false);
  657. }
  658. DisplayPrefs::DisplayPrefs(PrefService* local_state)
  659. : local_state_(local_state) {
  660. Shell::Get()->session_controller()->AddObserver(this);
  661. // |local_state_| could be null in tests.
  662. if (local_state_)
  663. LoadDisplayPreferences();
  664. }
  665. DisplayPrefs::~DisplayPrefs() {
  666. Shell::Get()->session_controller()->RemoveObserver(this);
  667. }
  668. void DisplayPrefs::OnFirstSessionStarted() {
  669. if (store_requested_)
  670. MaybeStoreDisplayPrefs();
  671. }
  672. void DisplayPrefs::MaybeStoreDisplayPrefs() {
  673. DCHECK(local_state_);
  674. // Stores the power state regardless of the login status, because the power
  675. // state respects to the current status (close/open) of the lid which can be
  676. // changed in any situation. See http://crbug.com/285360
  677. StoreCurrentDisplayPowerState(local_state_);
  678. StoreCurrentDisplayRotationLockPrefs(local_state_);
  679. // We cannot really decide whether to store display prefs until there is an
  680. // active user session. |OnFirstSessionStarted()| should eventually attempt to
  681. // do a store in this case.
  682. if (!Shell::Get()->session_controller()->GetUserType()) {
  683. store_requested_ = true;
  684. return;
  685. }
  686. // There are multiple scenarios where we don't want to save display prefs.
  687. // Some user types are not allowed, we don't want to change them while a
  688. // display change confirmation dialog is still visible, etc.
  689. if (!UserCanSaveDisplayPreference() ||
  690. !Shell::Get()->ShouldSaveDisplaySettings()) {
  691. return;
  692. }
  693. store_requested_ = false;
  694. // Don't save certain display properties when in tablet mode, so if
  695. // the device is rebooted in clamshell mode, it won't have an unexpected
  696. // mirroring layout. https://crbug.com/733092.
  697. if (!Shell::Get()->tablet_mode_controller()->InTabletMode()) {
  698. StoreCurrentDisplayLayoutPrefs(local_state_);
  699. StoreExternalDisplayMirrorInfo(local_state_);
  700. StoreCurrentDisplayMixedMirrorModeParams(local_state_);
  701. }
  702. StoreCurrentDisplayProperties(local_state_);
  703. StoreDisplayTouchAssociations(local_state_);
  704. // The display prefs need to be committed immediately to guarantee they're not
  705. // lost, and are restored properly on reboot. https://crbug.com/936884.
  706. // This sends a request via mojo to commit the prefs to disk.
  707. local_state_->CommitPendingWrite();
  708. }
  709. void DisplayPrefs::LoadDisplayPreferences() {
  710. LoadDisplayLayouts(local_state_);
  711. LoadDisplayProperties(local_state_);
  712. LoadExternalDisplayMirrorInfo(local_state_);
  713. LoadDisplayMixedMirrorModeParams(local_state_);
  714. LoadDisplayRotationState(local_state_);
  715. LoadDisplayTouchAssociations(local_state_);
  716. // Now that the display prefs have been loaded, request to reconfigure the
  717. // displays, but signal the display manager to restore the mirror state of
  718. // external displays from the loaded prefs (if any).
  719. Shell::Get()
  720. ->display_manager()
  721. ->set_should_restore_mirror_mode_from_display_prefs(true);
  722. Shell::Get()->display_configurator()->OnConfigurationChanged();
  723. // Ensure that we have a reasonable initial display power state if
  724. // powerd fails to send us one over D-Bus. Otherwise, we won't restore
  725. // displays correctly after retaking control when changing virtual terminals.
  726. if (base::CommandLine::ForCurrentProcess()->HasSwitch(
  727. switches::kFirstExecAfterBoot)) {
  728. Shell::Get()->display_configurator()->InitializeDisplayPowerState();
  729. return;
  730. }
  731. // Restore DisplayPowerState:
  732. const std::string value =
  733. local_state_->GetValue(prefs::kDisplayPowerState).GetString();
  734. chromeos::DisplayPowerState power_state;
  735. if (GetDisplayPowerStateFromString(value, &power_state))
  736. Shell::Get()->display_configurator()->SetInitialDisplayPower(power_state);
  737. }
  738. void DisplayPrefs::StoreDisplayRotationPrefsForTest(
  739. display::Display::Rotation rotation,
  740. bool rotation_lock) {
  741. StoreDisplayRotationPrefs(local_state_, rotation, rotation_lock);
  742. }
  743. void DisplayPrefs::StoreDisplayLayoutPrefForTest(
  744. const display::DisplayIdList& list,
  745. const display::DisplayLayout& layout) {
  746. StoreDisplayLayoutPref(local_state_, list, layout);
  747. }
  748. void DisplayPrefs::StoreDisplayPowerStateForTest(
  749. DisplayPowerState power_state) {
  750. StoreDisplayPowerState(local_state_, power_state);
  751. }
  752. void DisplayPrefs::LoadTouchAssociationPreferenceForTest() {
  753. LoadDisplayTouchAssociations(local_state_);
  754. }
  755. void DisplayPrefs::StoreLegacyTouchDataForTest(
  756. int64_t display_id,
  757. const display::TouchCalibrationData& data) {
  758. DictionaryPrefUpdate update(local_state_, prefs::kDisplayProperties);
  759. base::Value::Dict& pref_data = update->GetDict();
  760. base::Value::Dict property_value;
  761. TouchDataToValue(data, property_value);
  762. pref_data.Set(base::NumberToString(display_id), std::move(property_value));
  763. }
  764. bool DisplayPrefs::ParseTouchCalibrationStringForTest(
  765. const std::string& str,
  766. display::TouchCalibrationData::CalibrationPointPairQuad* point_pair_quad) {
  767. return ParseTouchCalibrationStringValue(str, point_pair_quad);
  768. }
  769. void DisplayPrefs::StoreDisplayMixedMirrorModeParamsForTest(
  770. const absl::optional<display::MixedMirrorModeParams>& mixed_params) {
  771. StoreDisplayMixedMirrorModeParams(local_state_, mixed_params);
  772. }
  773. } // namespace ash