display_preferences.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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 5#include "chrome/browser/chromeos/display/display_preferences.h" 6 7#include "ash/display/display_layout_store.h" 8#include "ash/display/display_manager.h" 9#include "ash/display/display_pref_util.h" 10#include "ash/display/resolution_notification_controller.h" 11#include "ash/shell.h" 12#include "base/prefs/pref_registry_simple.h" 13#include "base/prefs/pref_service.h" 14#include "base/strings/string16.h" 15#include "base/strings/string_number_conversions.h" 16#include "base/strings/string_split.h" 17#include "base/strings/string_util.h" 18#include "base/values.h" 19#include "chrome/browser/browser_process.h" 20#include "chrome/browser/chromeos/login/user_manager.h" 21#include "chrome/browser/prefs/scoped_user_pref_update.h" 22#include "chrome/common/pref_names.h" 23#include "chromeos/display/output_configurator.h" 24#include "third_party/cros_system_api/dbus/service_constants.h" 25#include "ui/gfx/display.h" 26#include "ui/gfx/insets.h" 27#include "ui/gfx/screen.h" 28#include "url/url_canon.h" 29#include "url/url_util.h" 30 31namespace chromeos { 32namespace { 33 34const char kInsetsTopKey[] = "insets_top"; 35const char kInsetsLeftKey[] = "insets_left"; 36const char kInsetsBottomKey[] = "insets_bottom"; 37const char kInsetsRightKey[] = "insets_right"; 38 39// This kind of boilerplates should be done by base::JSONValueConverter but it 40// doesn't support classes like gfx::Insets for now. 41// TODO(mukai): fix base::JSONValueConverter and use it here. 42bool ValueToInsets(const base::DictionaryValue& value, gfx::Insets* insets) { 43 DCHECK(insets); 44 int top = 0; 45 int left = 0; 46 int bottom = 0; 47 int right = 0; 48 if (value.GetInteger(kInsetsTopKey, &top) && 49 value.GetInteger(kInsetsLeftKey, &left) && 50 value.GetInteger(kInsetsBottomKey, &bottom) && 51 value.GetInteger(kInsetsRightKey, &right)) { 52 insets->Set(top, left, bottom, right); 53 return true; 54 } 55 return false; 56} 57 58void InsetsToValue(const gfx::Insets& insets, base::DictionaryValue* value) { 59 DCHECK(value); 60 value->SetInteger(kInsetsTopKey, insets.top()); 61 value->SetInteger(kInsetsLeftKey, insets.left()); 62 value->SetInteger(kInsetsBottomKey, insets.bottom()); 63 value->SetInteger(kInsetsRightKey, insets.right()); 64} 65 66ash::internal::DisplayManager* GetDisplayManager() { 67 return ash::Shell::GetInstance()->display_manager(); 68} 69 70// Returns true id the current user can write display preferences to 71// Local State. 72bool UserCanSaveDisplayPreference() { 73 UserManager* user_manager = UserManager::Get(); 74 return user_manager->IsUserLoggedIn() && 75 (user_manager->IsLoggedInAsRegularUser() || 76 user_manager->IsLoggedInAsLocallyManagedUser() || 77 user_manager->IsLoggedInAsKioskApp()); 78} 79 80ash::DisplayController* GetDisplayController() { 81 return ash::Shell::GetInstance()->display_controller(); 82} 83 84void LoadDisplayLayouts() { 85 PrefService* local_state = g_browser_process->local_state(); 86 ash::internal::DisplayLayoutStore* layout_store = 87 GetDisplayManager()->layout_store(); 88 89 const base::DictionaryValue* layouts = local_state->GetDictionary( 90 prefs::kSecondaryDisplays); 91 for (DictionaryValue::Iterator it(*layouts); !it.IsAtEnd(); it.Advance()) { 92 ash::DisplayLayout layout; 93 if (!ash::DisplayLayout::ConvertFromValue(it.value(), &layout)) { 94 LOG(WARNING) << "Invalid preference value for " << it.key(); 95 continue; 96 } 97 98 if (it.key().find(",") != std::string::npos) { 99 std::vector<std::string> ids; 100 base::SplitString(it.key(), ',', &ids); 101 int64 id1 = gfx::Display::kInvalidDisplayID; 102 int64 id2 = gfx::Display::kInvalidDisplayID; 103 if (!base::StringToInt64(ids[0], &id1) || 104 !base::StringToInt64(ids[1], &id2) || 105 id1 == gfx::Display::kInvalidDisplayID || 106 id2 == gfx::Display::kInvalidDisplayID) { 107 continue; 108 } 109 layout_store->RegisterLayoutForDisplayIdPair(id1, id2, layout); 110 } 111 } 112} 113 114void LoadDisplayProperties() { 115 PrefService* local_state = g_browser_process->local_state(); 116 const base::DictionaryValue* properties = local_state->GetDictionary( 117 prefs::kDisplayProperties); 118 for (DictionaryValue::Iterator it(*properties); !it.IsAtEnd(); it.Advance()) { 119 const base::DictionaryValue* dict_value = NULL; 120 if (!it.value().GetAsDictionary(&dict_value) || dict_value == NULL) 121 continue; 122 int64 id = gfx::Display::kInvalidDisplayID; 123 if (!base::StringToInt64(it.key(), &id) || 124 id == gfx::Display::kInvalidDisplayID) { 125 continue; 126 } 127 gfx::Display::Rotation rotation = gfx::Display::ROTATE_0; 128 float ui_scale = 1.0f; 129 const gfx::Insets* insets_to_set = NULL; 130 131 int rotation_value = 0; 132 if (dict_value->GetInteger("rotation", &rotation_value)) { 133 rotation = static_cast<gfx::Display::Rotation>(rotation_value); 134 } 135 int ui_scale_value = 0; 136 if (dict_value->GetInteger("ui-scale", &ui_scale_value)) 137 ui_scale = static_cast<float>(ui_scale_value) / 1000.0f; 138 139 int width = 0, height = 0; 140 dict_value->GetInteger("width", &width); 141 dict_value->GetInteger("height", &height); 142 gfx::Size resolution_in_pixels(width, height); 143 144 gfx::Insets insets; 145 if (ValueToInsets(*dict_value, &insets)) 146 insets_to_set = &insets; 147 GetDisplayManager()->RegisterDisplayProperty(id, 148 rotation, 149 ui_scale, 150 insets_to_set, 151 resolution_in_pixels); 152 } 153} 154 155void StoreDisplayLayoutPref(const ash::DisplayIdPair& pair, 156 const ash::DisplayLayout& display_layout) { 157 std::string name = 158 base::Int64ToString(pair.first) + "," + base::Int64ToString(pair.second); 159 160 PrefService* local_state = g_browser_process->local_state(); 161 DictionaryPrefUpdate update(local_state, prefs::kSecondaryDisplays); 162 base::DictionaryValue* pref_data = update.Get(); 163 scoped_ptr<base::Value> layout_value(new base::DictionaryValue()); 164 if (pref_data->HasKey(name)) { 165 base::Value* value = NULL; 166 if (pref_data->Get(name, &value) && value != NULL) 167 layout_value.reset(value->DeepCopy()); 168 } 169 if (ash::DisplayLayout::ConvertToValue(display_layout, layout_value.get())) 170 pref_data->Set(name, layout_value.release()); 171} 172 173void StoreCurrentDisplayLayoutPrefs() { 174 if (!UserCanSaveDisplayPreference() || 175 GetDisplayManager()->num_connected_displays() < 2) { 176 return; 177 } 178 179 ash::DisplayIdPair pair = GetDisplayManager()->GetCurrentDisplayIdPair(); 180 ash::DisplayLayout display_layout = 181 GetDisplayManager()->layout_store()->GetRegisteredDisplayLayout(pair); 182 StoreDisplayLayoutPref(pair, display_layout); 183} 184 185void StoreCurrentDisplayProperties() { 186 ash::internal::DisplayManager* display_manager = GetDisplayManager(); 187 PrefService* local_state = g_browser_process->local_state(); 188 189 DictionaryPrefUpdate update(local_state, prefs::kDisplayProperties); 190 base::DictionaryValue* pref_data = update.Get(); 191 192 size_t num = display_manager->GetNumDisplays(); 193 for (size_t i = 0; i < num; ++i) { 194 const gfx::Display& display = display_manager->GetDisplayAt(i); 195 int64 id = display.id(); 196 ash::internal::DisplayInfo info = display_manager->GetDisplayInfo(id); 197 198 scoped_ptr<base::DictionaryValue> property_value( 199 new base::DictionaryValue()); 200 property_value->SetInteger("rotation", static_cast<int>(info.rotation())); 201 property_value->SetInteger("ui-scale", 202 static_cast<int>(info.ui_scale() * 1000)); 203 gfx::Size resolution; 204 if (!display.IsInternal() && 205 display_manager->GetSelectedResolutionForDisplayId(id, &resolution)) { 206 property_value->SetInteger("width", resolution.width()); 207 property_value->SetInteger("height", resolution.height()); 208 } 209 210 if (!info.overscan_insets_in_dip().empty()) 211 InsetsToValue(info.overscan_insets_in_dip(), property_value.get()); 212 pref_data->Set(base::Int64ToString(id), property_value.release()); 213 } 214} 215 216typedef std::map<chromeos::DisplayPowerState, std::string> 217 DisplayPowerStateToStringMap; 218 219const DisplayPowerStateToStringMap* GetDisplayPowerStateToStringMap() { 220 static const DisplayPowerStateToStringMap* map = ash::CreateToStringMap( 221 chromeos::DISPLAY_POWER_ALL_ON, "all_on", 222 chromeos::DISPLAY_POWER_ALL_OFF, "all_off", 223 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, 224 "internal_off_external_on", 225 chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF, 226 "internal_on_external_off"); 227 return map; 228} 229 230bool GetDisplayPowerStateFromString(const base::StringPiece& state, 231 chromeos::DisplayPowerState* field) { 232 if (ash::ReverseFind(GetDisplayPowerStateToStringMap(), state, field)) 233 return true; 234 LOG(ERROR) << "Invalid display power state value:" << state; 235 return false; 236} 237 238void StoreDisplayPowerState(DisplayPowerState power_state) { 239 const DisplayPowerStateToStringMap* map = GetDisplayPowerStateToStringMap(); 240 DisplayPowerStateToStringMap::const_iterator iter = map->find(power_state); 241 std::string value = iter != map->end() ? iter->second : std::string(); 242 PrefService* local_state = g_browser_process->local_state(); 243 local_state->SetString(prefs::kDisplayPowerState, value); 244} 245 246void StoreCurrentDisplayPowerState() { 247 StoreDisplayPowerState( 248 ash::Shell::GetInstance()->output_configurator()->power_state()); 249} 250 251} // namespace 252 253void RegisterDisplayLocalStatePrefs(PrefRegistrySimple* registry) { 254 // Per-display preference. 255 registry->RegisterDictionaryPref(prefs::kSecondaryDisplays); 256 registry->RegisterDictionaryPref(prefs::kDisplayProperties); 257 DisplayPowerStateToStringMap::const_iterator iter = 258 GetDisplayPowerStateToStringMap()->find(chromeos::DISPLAY_POWER_ALL_ON); 259 registry->RegisterStringPref(prefs::kDisplayPowerState, iter->second); 260} 261 262void StoreDisplayPrefs() { 263 // Stores the power state regardless of the login status, because the power 264 // state respects to the current status (close/open) of the lid which can be 265 // changed in any situation. See crbug.com/285360 266 StoreCurrentDisplayPowerState(); 267 268 // Do not store prefs when the confirmation dialog is shown. 269 if (!UserCanSaveDisplayPreference() || 270 ash::Shell::GetInstance()->resolution_notification_controller()-> 271 DoesNotificationTimeout()) { 272 return; 273 } 274 StoreCurrentDisplayLayoutPrefs(); 275 StoreCurrentDisplayProperties(); 276} 277 278void SetCurrentDisplayLayout(const ash::DisplayLayout& layout) { 279 GetDisplayManager()->SetLayoutForCurrentDisplays(layout); 280} 281 282void LoadDisplayPreferences(bool first_run_after_boot) { 283 LoadDisplayLayouts(); 284 LoadDisplayProperties(); 285 if (!first_run_after_boot) { 286 PrefService* local_state = g_browser_process->local_state(); 287 // Restore DisplayPowerState: 288 std::string value = local_state->GetString(prefs::kDisplayPowerState); 289 chromeos::DisplayPowerState power_state; 290 if (GetDisplayPowerStateFromString(value, &power_state)) { 291 ash::Shell::GetInstance()->output_configurator()->SetInitialDisplayPower( 292 power_state); 293 } 294 } 295} 296 297// Stores the display layout for given display pairs. 298void StoreDisplayLayoutPrefForTest(int64 id1, 299 int64 id2, 300 const ash::DisplayLayout& layout) { 301 StoreDisplayLayoutPref(std::make_pair(id1, id2), layout); 302} 303 304// Stores the given |power_state|. 305void StoreDisplayPowerStateForTest(DisplayPowerState power_state) { 306 StoreDisplayPowerState(power_state); 307} 308 309} // namespace chromeos 310