Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(264)

Side by Side Diff: ash/system/chromeos/screen_layout_observer.cc

Issue 2644593003: Fix bugs in the display notification (Closed)
Patch Set: Oshima's comments Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ash/system/chromeos/screen_layout_observer.h" 5 #include "ash/system/chromeos/screen_layout_observer.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 // Callback to handle a user selecting the notification view. 94 // Callback to handle a user selecting the notification view.
95 void OpenSettingsFromNotification() { 95 void OpenSettingsFromNotification() {
96 WmShell::Get()->RecordUserMetricsAction( 96 WmShell::Get()->RecordUserMetricsAction(
97 UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SELECTED); 97 UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SELECTED);
98 if (OpenSettings()) { 98 if (OpenSettings()) {
99 WmShell::Get()->RecordUserMetricsAction( 99 WmShell::Get()->RecordUserMetricsAction(
100 UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SHOW_SETTINGS); 100 UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SHOW_SETTINGS);
101 } 101 }
102 } 102 }
103 103
104 // Returns the name of the currently connected external display. This should not 104 // Returns the name of the currently connected external display whose ID is
105 // be used when the external display is used for mirroring. 105 // |external_display_id|. This should not be used when the external display is
106 base::string16 GetExternalDisplayName() { 106 // used for mirroring.
107 base::string16 GetExternalDisplayName(int64_t external_display_id) {
108 DCHECK(!display::Display::IsInternalDisplayId(external_display_id));
109
107 display::DisplayManager* display_manager = GetDisplayManager(); 110 display::DisplayManager* display_manager = GetDisplayManager();
108 DCHECK(!display_manager->IsInMirrorMode()); 111 DCHECK(!display_manager->IsInMirrorMode());
109 112
110 int64_t external_id = display::kInvalidDisplayId; 113 if (external_display_id == display::kInvalidDisplayId)
111 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
112 int64_t id = display_manager->GetDisplayAt(i).id();
113 if (!display::Display::IsInternalDisplayId(id)) {
114 external_id = id;
115 break;
116 }
117 }
118
119 if (external_id == display::kInvalidDisplayId)
120 return l10n_util::GetStringUTF16(IDS_DISPLAY_NAME_UNKNOWN); 114 return l10n_util::GetStringUTF16(IDS_DISPLAY_NAME_UNKNOWN);
121 115
122 // The external display name may have an annotation of "(width x height)" in 116 // The external display name may have an annotation of "(width x height)" in
123 // case that the display is rotated or its resolution is changed. 117 // case that the display is rotated or its resolution is changed.
124 base::string16 name = GetDisplayName(external_id); 118 base::string16 name = GetDisplayName(external_display_id);
125 const display::ManagedDisplayInfo& display_info = 119 const display::ManagedDisplayInfo& display_info =
126 display_manager->GetDisplayInfo(external_id); 120 display_manager->GetDisplayInfo(external_display_id);
127 if (display_info.GetActiveRotation() != display::Display::ROTATE_0 || 121 if (display_info.GetActiveRotation() != display::Display::ROTATE_0 ||
128 display_info.configured_ui_scale() != 1.0f || 122 display_info.configured_ui_scale() != 1.0f ||
129 !display_info.overscan_insets_in_dip().IsEmpty()) { 123 !display_info.overscan_insets_in_dip().IsEmpty()) {
130 name = 124 name =
131 l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, 125 l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME,
132 name, GetDisplaySize(external_id)); 126 name, GetDisplaySize(external_display_id));
133 } else if (display_info.overscan_insets_in_dip().IsEmpty() && 127 } else if (display_info.overscan_insets_in_dip().IsEmpty() &&
134 display_info.has_overscan()) { 128 display_info.has_overscan()) {
135 name = l10n_util::GetStringFUTF16( 129 name = l10n_util::GetStringFUTF16(
136 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, name, 130 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, name,
137 l10n_util::GetStringUTF16( 131 l10n_util::GetStringUTF16(
138 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION_OVERSCAN)); 132 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION_OVERSCAN));
139 } 133 }
140 134
141 return name; 135 return name;
142 } 136 }
143 137
144 base::string16 GetDisplayMessage(base::string16* additional_message_out) { 138 // Returns true if docked mode is currently enabled.
139 bool IsDockedModeEnabled() {
145 display::DisplayManager* display_manager = GetDisplayManager(); 140 display::DisplayManager* display_manager = GetDisplayManager();
146 if (display_manager->GetNumDisplays() > 1) { 141 if (display::Display::HasInternalDisplay()) {
147 if (display::Display::HasInternalDisplay()) { 142 // We have an internal display but it's not one of the active displays.
148 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, 143 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
149 GetExternalDisplayName()); 144 if (display::Display::IsInternalDisplayId(
145 display_manager->GetDisplayAt(i).id())) {
146 return false;
147 }
148
149 return true;
150 } 150 }
151 }
152
153 return false;
154 }
155
156 // Returns the notification message that should be shown to the user when the
157 // docked mode is entered.
158 base::string16 GetDockedModeEnabledMessage(
159 base::string16* out_additional_message) {
160 DCHECK(IsDockedModeEnabled());
161 DCHECK(out_additional_message);
162
163 *out_additional_message = ash::SubstituteChromeOSDeviceType(
164 IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED_DESCRIPTION);
165 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED);
166 }
167
168 // Returns the notification message that should be shown when mirror display
169 // mode is entered.
170 base::string16 GetEnterMirrorModeMessage() {
171 if (display::Display::HasInternalDisplay()) {
172 return l10n_util::GetStringFUTF16(
173 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING,
174 GetDisplayName(GetDisplayManager()->mirroring_display_id()));
175 }
176
177 return l10n_util::GetStringUTF16(
178 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL);
179 }
180
181 // Returns the notification message that should be shown when mirror display
182 // mode is exited.
183 bool GetExitMirrorModeMessage(base::string16* out_message,
184 base::string16* out_additional_message) {
185 display::DisplayManager* display_manager = GetDisplayManager();
186 if (display_manager->GetNumDisplays() == 1 &&
187 !display_manager->IsInUnifiedMode()) {
oshima 2017/01/25 22:22:26 can you pass old state instead of testing the cond
afakhry 2017/01/26 19:51:09 Done. Here we need to know if the new state is no
oshima 2017/01/28 06:14:29 yes, sorry I meant new state.
188 // Make sure we're not in unified mode as this is also considered as
189 // a single display.
190 if (IsDockedModeEnabled()) {
191 // Handle disabling mirror mode as a result of going to docked mode when
192 // we only have a single display (this means we actually have two physical
193 // displays, one of which is the internal display, but they were in mirror
194 // mode, and hence considered as one. Closing the internal display
195 // disables mirror mode and we still have a single active display).
196 *out_message = GetDockedModeEnabledMessage(out_additional_message);
197 return true;
198 }
199
200 // We're exiting mirror mode because we removed one of the two displays.
201 *out_message =
202 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRROR_EXIT);
203 return true;
204 }
205
206 if (display_manager->GetNumDisplays() > 2) {
207 // Mirror mode was turned off due to having more than two displays. Show
208 // a message that mirror mode for 3+ displays is not supported.
209 *out_message =
210 l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_MIRRORING_NOT_SUPPORTED);
211 return true;
212 }
213
214 // Mirror mode was turned off; other messages should be shown e.g. extended
215 // mode is on, ... etc.
216 return false;
217 }
218
219 // Returns the notification message that should be shown when unified desktop
220 // mode is entered.
221 base::string16 GetEnterUnifiedModeMessage() {
222 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED);
223 }
224
225 // Returns the notification message that should be shown when unified desktop
226 // mode is exited.
227 base::string16 GetExitUnifiedModeMessage() {
228 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED_EXITING);
229 }
230
231 base::string16 GetDisplayRemovedMessage(
232 const display::ManagedDisplayInfo& removed_display_info,
233 base::string16* out_additional_message) {
234 // Removing the internal display means entering docked mode.
235 if (display::Display::IsInternalDisplayId(removed_display_info.id()))
oshima 2017/01/25 22:22:26 you can also use the old state. (or DCHECK one of
afakhry 2017/01/26 19:51:09 I'm sorry, I don't understand what you mean here.
236 return GetDockedModeEnabledMessage(out_additional_message);
237
238 return l10n_util::GetStringFUTF16(
239 IDS_ASH_STATUS_TRAY_DISPLAY_REMOVED,
240 base::UTF8ToUTF16(removed_display_info.name()));
241 }
242
243 base::string16 GetDisplayAddedMessage(int64_t added_display_id,
244 base::string16* additional_message_out) {
245 if (!display::Display::HasInternalDisplay()) {
151 return l10n_util::GetStringUTF16( 246 return l10n_util::GetStringUTF16(
152 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL); 247 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL);
153 } 248 }
154 249
155 if (display_manager->IsInMirrorMode()) { 250 if (display::Display::IsInternalDisplayId(added_display_id)) {
156 if (display::Display::HasInternalDisplay()) { 251 // Adding the internal display means exiting docked mode (IFF we are not
157 return l10n_util::GetStringFUTF16( 252 // exiting unified mode. This case should have already been handled by the
158 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, 253 // time this function is called).
159 GetDisplayName(display_manager->mirroring_display_id()));
160 }
161 return l10n_util::GetStringUTF16( 254 return l10n_util::GetStringUTF16(
162 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL); 255 IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED_EXITING);
163 } 256 }
164 257
165 if (display_manager->IsInUnifiedMode()) 258 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED,
166 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED); 259 GetExternalDisplayName(added_display_id));
167
168 int64_t primary_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
169 if (display::Display::HasInternalDisplay() &&
170 !(display::Display::IsInternalDisplayId(primary_id))) {
171 if (additional_message_out) {
172 *additional_message_out = ash::SubstituteChromeOSDeviceType(
173 IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED_DESCRIPTION);
174 }
175 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED);
176 }
177
178 return base::string16();
179 } 260 }
180 261
181 } // namespace 262 } // namespace
182 263
183 const char ScreenLayoutObserver::kNotificationId[] = 264 const char ScreenLayoutObserver::kNotificationId[] =
184 "chrome://settings/display"; 265 "chrome://settings/display";
185 266
186 ScreenLayoutObserver::ScreenLayoutObserver() { 267 ScreenLayoutObserver::ScreenLayoutObserver() {
187 WmShell::Get()->AddDisplayObserver(this); 268 WmShell::Get()->AddDisplayObserver(this);
188 UpdateDisplayInfo(NULL); 269 UpdateDisplayInfo(NULL);
(...skipping 11 matching lines...) Expand all
200 281
201 display::DisplayManager* display_manager = GetDisplayManager(); 282 display::DisplayManager* display_manager = GetDisplayManager();
202 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { 283 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
203 int64_t id = display_manager->GetDisplayAt(i).id(); 284 int64_t id = display_manager->GetDisplayAt(i).id();
204 display_info_[id] = display_manager->GetDisplayInfo(id); 285 display_info_[id] = display_manager->GetDisplayInfo(id);
205 } 286 }
206 } 287 }
207 288
208 bool ScreenLayoutObserver::GetDisplayMessageForNotification( 289 bool ScreenLayoutObserver::GetDisplayMessageForNotification(
209 const ScreenLayoutObserver::DisplayInfoMap& old_info, 290 const ScreenLayoutObserver::DisplayInfoMap& old_info,
210 base::string16* message_out, 291 base::string16* out_message,
211 base::string16* additional_message_out) { 292 base::string16* out_additional_message) {
212 // Display is added or removed. Use the same message as the one in 293 if (old_display_mode_ != current_display_mode_) {
213 // the system tray. 294 // Detect changes in the mirror mode status.
214 if (display_info_.size() != old_info.size()) { 295 if (current_display_mode_ == DisplayMode::MIRRORING) {
215 *message_out = GetDisplayMessage(additional_message_out); 296 *out_message = GetEnterMirrorModeMessage();
216 return true; 297 return true;
217 } 298 }
218 299 if (old_display_mode_ == DisplayMode::MIRRORING &&
219 for (DisplayInfoMap::const_iterator iter = display_info_.begin(); 300 GetExitMirrorModeMessage(out_message, out_additional_message)) {
220 iter != display_info_.end(); ++iter) {
221 DisplayInfoMap::const_iterator old_iter = old_info.find(iter->first);
222 // The display's number is same but different displays. This happens
223 // for the transition between docked mode and mirrored display. Falls back
224 // to GetDisplayMessage().
225 if (old_iter == old_info.end()) {
226 *message_out = GetDisplayMessage(additional_message_out);
227 return true; 301 return true;
228 } 302 }
229 303
230 if (iter->second.configured_ui_scale() != 304 // Detect changes in the unified mode status.
231 old_iter->second.configured_ui_scale()) { 305 if (current_display_mode_ == DisplayMode::UNIFIED) {
232 *additional_message_out = l10n_util::GetStringFUTF16( 306 *out_message = GetEnterUnifiedModeMessage();
233 IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
234 GetDisplayName(iter->first), GetDisplaySize(iter->first));
235 return true; 307 return true;
236 } 308 }
237 if (iter->second.GetActiveRotation() != 309 if (old_display_mode_ == DisplayMode::UNIFIED) {
310 *out_message = GetExitUnifiedModeMessage();
311 return true;
312 }
313 }
314
315 // Displays are added or removed.
316 if (display_info_.size() < old_info.size()) {
317 // A display has been removed.
318 for (const auto& iter : old_info) {
319 if (display_info_.count(iter.first))
320 continue;
321
322 *out_message =
323 GetDisplayRemovedMessage(iter.second, out_additional_message);
324 return true;
325 }
326 } else if (display_info_.size() > old_info.size()) {
327 // A display has been added.
328 for (const auto& iter : display_info_) {
329 if (old_info.count(iter.first))
330 continue;
331
332 *out_message = GetDisplayAddedMessage(iter.first, out_additional_message);
333 return true;
334 }
335 }
336
337 for (const auto& iter : display_info_) {
338 DisplayInfoMap::const_iterator old_iter = old_info.find(iter.first);
339 if (old_iter == old_info.end()) {
340 // The display's number is same but different displays. This happens
341 // for the transition between docked mode and mirrored display.
342 // This condition can never be reached here, since it is handled above.
343 NOTREACHED();
344 return false;
345 }
346
347 if (iter.second.configured_ui_scale() !=
348 old_iter->second.configured_ui_scale()) {
349 *out_additional_message = l10n_util::GetStringFUTF16(
350 IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
351 GetDisplayName(iter.first), GetDisplaySize(iter.first));
352 return true;
353 }
354 if (iter.second.GetActiveRotation() !=
238 old_iter->second.GetActiveRotation()) { 355 old_iter->second.GetActiveRotation()) {
239 int rotation_text_id = 0; 356 int rotation_text_id = 0;
240 switch (iter->second.GetActiveRotation()) { 357 switch (iter.second.GetActiveRotation()) {
241 case display::Display::ROTATE_0: 358 case display::Display::ROTATE_0:
242 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION; 359 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION;
243 break; 360 break;
244 case display::Display::ROTATE_90: 361 case display::Display::ROTATE_90:
245 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90; 362 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90;
246 break; 363 break;
247 case display::Display::ROTATE_180: 364 case display::Display::ROTATE_180:
248 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180; 365 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180;
249 break; 366 break;
250 case display::Display::ROTATE_270: 367 case display::Display::ROTATE_270:
251 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270; 368 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270;
252 break; 369 break;
253 } 370 }
254 *additional_message_out = l10n_util::GetStringFUTF16( 371 *out_additional_message = l10n_util::GetStringFUTF16(
255 IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetDisplayName(iter->first), 372 IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetDisplayName(iter.first),
256 l10n_util::GetStringUTF16(rotation_text_id)); 373 l10n_util::GetStringUTF16(rotation_text_id));
257 return true; 374 return true;
258 } 375 }
259 } 376 }
260 377
261 // Found nothing special 378 // Found nothing special
262 return false; 379 return false;
263 } 380 }
264 381
265 void ScreenLayoutObserver::CreateOrUpdateNotification( 382 void ScreenLayoutObserver::CreateOrUpdateNotification(
(...skipping 30 matching lines...) Expand all
296 WmShell::Get()->RecordUserMetricsAction( 413 WmShell::Get()->RecordUserMetricsAction(
297 UMA_STATUS_AREA_DISPLAY_NOTIFICATION_CREATED); 414 UMA_STATUS_AREA_DISPLAY_NOTIFICATION_CREATED);
298 message_center::MessageCenter::Get()->AddNotification( 415 message_center::MessageCenter::Get()->AddNotification(
299 std::move(notification)); 416 std::move(notification));
300 } 417 }
301 418
302 void ScreenLayoutObserver::OnDisplayConfigurationChanged() { 419 void ScreenLayoutObserver::OnDisplayConfigurationChanged() {
303 DisplayInfoMap old_info; 420 DisplayInfoMap old_info;
304 UpdateDisplayInfo(&old_info); 421 UpdateDisplayInfo(&old_info);
305 422
423 old_display_mode_ = current_display_mode_;
424 if (GetDisplayManager()->IsInMirrorMode())
425 current_display_mode_ = DisplayMode::MIRRORING;
426 else if (GetDisplayManager()->IsInUnifiedMode())
427 current_display_mode_ = DisplayMode::UNIFIED;
428 else if (GetDisplayManager()->GetNumDisplays() > 1)
429 current_display_mode_ = DisplayMode::EXTENDED;
430 else
431 current_display_mode_ = DisplayMode::SINGLE;
432
306 if (!show_notifications_for_testing) 433 if (!show_notifications_for_testing)
307 return; 434 return;
308 435
309 base::string16 message; 436 base::string16 message;
310 base::string16 additional_message; 437 base::string16 additional_message;
311 if (GetDisplayMessageForNotification(old_info, &message, &additional_message)) 438 if (GetDisplayMessageForNotification(old_info, &message, &additional_message))
312 CreateOrUpdateNotification(message, additional_message); 439 CreateOrUpdateNotification(message, additional_message);
313 } 440 }
314 441
315 } // namespace ash 442 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/chromeos/screen_layout_observer.h ('k') | ash/system/chromeos/screen_layout_observer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698