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

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

Issue 2732813002: chromeos: Move files in //ash/common to //ash, part 1 (Closed)
Patch Set: rebase Created 3 years, 9 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
(Empty)
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 "ash/system/chromeos/screen_layout_observer.h"
6
7 #include <memory>
8 #include <utility>
9 #include <vector>
10
11 #include "ash/common/metrics/user_metrics_action.h"
12 #include "ash/common/system/chromeos/devicetype_utils.h"
13 #include "ash/common/system/system_notifier.h"
14 #include "ash/common/system/tray/fixed_sized_image_view.h"
15 #include "ash/common/system/tray/system_tray_controller.h"
16 #include "ash/common/system/tray/system_tray_delegate.h"
17 #include "ash/common/system/tray/tray_constants.h"
18 #include "ash/common/wm_shell.h"
19 #include "ash/display/screen_orientation_controller_chromeos.h"
20 #include "ash/resources/grit/ash_resources.h"
21 #include "ash/shell.h"
22 #include "ash/strings/grit/ash_strings.h"
23 #include "base/bind.h"
24 #include "base/strings/string_util.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/resource/resource_bundle.h"
28 #include "ui/display/display.h"
29 #include "ui/display/manager/display_manager.h"
30 #include "ui/display/types/display_constants.h"
31 #include "ui/message_center/message_center.h"
32 #include "ui/message_center/notification.h"
33 #include "ui/message_center/notification_delegate.h"
34 #include "ui/strings/grit/ui_strings.h"
35
36 using message_center::Notification;
37
38 namespace ash {
39 namespace {
40
41 display::DisplayManager* GetDisplayManager() {
42 return Shell::GetInstance()->display_manager();
43 }
44
45 base::string16 GetDisplayName(int64_t display_id) {
46 return base::UTF8ToUTF16(
47 GetDisplayManager()->GetDisplayNameForId(display_id));
48 }
49
50 base::string16 GetDisplaySize(int64_t display_id) {
51 display::DisplayManager* display_manager = GetDisplayManager();
52
53 const display::Display* display =
54 &display_manager->GetDisplayForId(display_id);
55
56 // We don't show display size for mirrored display. Fallback
57 // to empty string if this happens on release build.
58 bool mirroring = display_manager->mirroring_display_id() == display_id;
59 DCHECK(!mirroring);
60 if (mirroring)
61 return base::string16();
62
63 DCHECK(display->is_valid());
64 return base::UTF8ToUTF16(display->size().ToString());
65 }
66
67 // Attempts to open the display settings, returns true if successful.
68 bool OpenSettings() {
69 // switch is intentionally introduced without default, to cause an error when
70 // a new type of login status is introduced.
71 switch (WmShell::Get()->system_tray_delegate()->GetUserLoginStatus()) {
72 case LoginStatus::NOT_LOGGED_IN:
73 case LoginStatus::LOCKED:
74 return false;
75
76 case LoginStatus::USER:
77 case LoginStatus::OWNER:
78 case LoginStatus::GUEST:
79 case LoginStatus::PUBLIC:
80 case LoginStatus::SUPERVISED:
81 case LoginStatus::KIOSK_APP:
82 case LoginStatus::ARC_KIOSK_APP:
83 SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate();
84 if (delegate->ShouldShowSettings()) {
85 WmShell::Get()->system_tray_controller()->ShowDisplaySettings();
86 return true;
87 }
88 break;
89 }
90
91 return false;
92 }
93
94 // Callback to handle a user selecting the notification view.
95 void OpenSettingsFromNotification() {
96 WmShell::Get()->RecordUserMetricsAction(
97 UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SELECTED);
98 if (OpenSettings()) {
99 WmShell::Get()->RecordUserMetricsAction(
100 UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SHOW_SETTINGS);
101 }
102 }
103
104 // Returns the name of the currently connected external display whose ID is
105 // |external_display_id|. This should not be used when the external display is
106 // used for mirroring.
107 base::string16 GetExternalDisplayName(int64_t external_display_id) {
108 DCHECK(!display::Display::IsInternalDisplayId(external_display_id));
109
110 display::DisplayManager* display_manager = GetDisplayManager();
111 DCHECK(!display_manager->IsInMirrorMode());
112
113 if (external_display_id == display::kInvalidDisplayId)
114 return l10n_util::GetStringUTF16(IDS_DISPLAY_NAME_UNKNOWN);
115
116 // The external display name may have an annotation of "(width x height)" in
117 // case that the display is rotated or its resolution is changed.
118 base::string16 name = GetDisplayName(external_display_id);
119 const display::ManagedDisplayInfo& display_info =
120 display_manager->GetDisplayInfo(external_display_id);
121 if (display_info.GetActiveRotation() != display::Display::ROTATE_0 ||
122 display_info.configured_ui_scale() != 1.0f ||
123 !display_info.overscan_insets_in_dip().IsEmpty()) {
124 name =
125 l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME,
126 name, GetDisplaySize(external_display_id));
127 } else if (display_info.overscan_insets_in_dip().IsEmpty() &&
128 display_info.has_overscan()) {
129 name = l10n_util::GetStringFUTF16(
130 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, name,
131 l10n_util::GetStringUTF16(
132 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION_OVERSCAN));
133 }
134
135 return name;
136 }
137
138 // Returns true if docked mode is currently enabled.
139 bool IsDockedModeEnabled() {
140 display::DisplayManager* display_manager = GetDisplayManager();
141 if (!display::Display::HasInternalDisplay())
142 return false;
143
144 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
145 if (display::Display::IsInternalDisplayId(
146 display_manager->GetDisplayAt(i).id())) {
147 return false;
148 }
149 }
150
151 // We have an internal display but it's not one of the active displays.
152 return true;
153 }
154
155 // Returns the notification message that should be shown when mirror display
156 // mode is entered.
157 base::string16 GetEnterMirrorModeMessage() {
158 if (display::Display::HasInternalDisplay()) {
159 return l10n_util::GetStringFUTF16(
160 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING,
161 GetDisplayName(GetDisplayManager()->mirroring_display_id()));
162 }
163
164 return l10n_util::GetStringUTF16(
165 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL);
166 }
167
168 // Returns the notification message that should be shown when unified desktop
169 // mode is entered.
170 base::string16 GetEnterUnifiedModeMessage() {
171 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED);
172 }
173
174 // Returns the notification message that should be shown when unified desktop
175 // mode is exited.
176 base::string16 GetExitUnifiedModeMessage() {
177 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED_EXITING);
178 }
179
180 base::string16 GetDisplayRemovedMessage(
181 const display::ManagedDisplayInfo& removed_display_info,
182 base::string16* out_additional_message) {
183 return l10n_util::GetStringFUTF16(
184 IDS_ASH_STATUS_TRAY_DISPLAY_REMOVED,
185 base::UTF8ToUTF16(removed_display_info.name()));
186 }
187
188 base::string16 GetDisplayAddedMessage(int64_t added_display_id,
189 base::string16* additional_message_out) {
190 if (!display::Display::HasInternalDisplay()) {
191 return l10n_util::GetStringUTF16(
192 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL);
193 }
194
195 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED,
196 GetExternalDisplayName(added_display_id));
197 }
198
199 } // namespace
200
201 const char ScreenLayoutObserver::kNotificationId[] =
202 "chrome://settings/display";
203
204 ScreenLayoutObserver::ScreenLayoutObserver() {
205 WmShell::Get()->AddDisplayObserver(this);
206 UpdateDisplayInfo(NULL);
207 }
208
209 ScreenLayoutObserver::~ScreenLayoutObserver() {
210 WmShell::Get()->RemoveDisplayObserver(this);
211 }
212
213 void ScreenLayoutObserver::UpdateDisplayInfo(
214 ScreenLayoutObserver::DisplayInfoMap* old_info) {
215 if (old_info)
216 old_info->swap(display_info_);
217 display_info_.clear();
218
219 display::DisplayManager* display_manager = GetDisplayManager();
220 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
221 int64_t id = display_manager->GetDisplayAt(i).id();
222 display_info_[id] = display_manager->GetDisplayInfo(id);
223 }
224 }
225
226 bool ScreenLayoutObserver::GetDisplayMessageForNotification(
227 const ScreenLayoutObserver::DisplayInfoMap& old_info,
228 base::string16* out_message,
229 base::string16* out_additional_message) {
230 if (old_display_mode_ != current_display_mode_) {
231 // Detect changes in the mirror mode status.
232 if (current_display_mode_ == DisplayMode::MIRRORING) {
233 *out_message = GetEnterMirrorModeMessage();
234 return true;
235 }
236 if (old_display_mode_ == DisplayMode::MIRRORING &&
237 GetExitMirrorModeMessage(out_message, out_additional_message)) {
238 return true;
239 }
240
241 // Detect changes in the unified mode status.
242 if (current_display_mode_ == DisplayMode::UNIFIED) {
243 *out_message = GetEnterUnifiedModeMessage();
244 return true;
245 }
246 if (old_display_mode_ == DisplayMode::UNIFIED) {
247 *out_message = GetExitUnifiedModeMessage();
248 return true;
249 }
250
251 if (current_display_mode_ == DisplayMode::DOCKED ||
252 old_display_mode_ == DisplayMode::DOCKED) {
253 // We no longer show any notification for docked mode events.
254 // crbug.com/674719.
255 return false;
256 }
257 }
258
259 // Displays are added or removed.
260 if (display_info_.size() < old_info.size()) {
261 // A display has been removed.
262 for (const auto& iter : old_info) {
263 if (display_info_.count(iter.first))
264 continue;
265
266 *out_message =
267 GetDisplayRemovedMessage(iter.second, out_additional_message);
268 return true;
269 }
270 } else if (display_info_.size() > old_info.size()) {
271 // A display has been added.
272 for (const auto& iter : display_info_) {
273 if (old_info.count(iter.first))
274 continue;
275
276 *out_message = GetDisplayAddedMessage(iter.first, out_additional_message);
277 return true;
278 }
279 }
280
281 for (const auto& iter : display_info_) {
282 DisplayInfoMap::const_iterator old_iter = old_info.find(iter.first);
283 if (old_iter == old_info.end()) {
284 // The display's number is same but different displays. This happens
285 // for the transition between docked mode and mirrored display.
286 // This condition can never be reached here, since it is handled above.
287 NOTREACHED() << "A display mode transition that should have been handled"
288 "earlier.";
289 return false;
290 }
291
292 if (iter.second.configured_ui_scale() !=
293 old_iter->second.configured_ui_scale()) {
294 *out_additional_message = l10n_util::GetStringFUTF16(
295 IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
296 GetDisplayName(iter.first), GetDisplaySize(iter.first));
297 return true;
298 }
299 if (iter.second.GetActiveRotation() !=
300 old_iter->second.GetActiveRotation()) {
301 int rotation_text_id = 0;
302 switch (iter.second.GetActiveRotation()) {
303 case display::Display::ROTATE_0:
304 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION;
305 break;
306 case display::Display::ROTATE_90:
307 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90;
308 break;
309 case display::Display::ROTATE_180:
310 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180;
311 break;
312 case display::Display::ROTATE_270:
313 rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270;
314 break;
315 }
316 *out_additional_message = l10n_util::GetStringFUTF16(
317 IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetDisplayName(iter.first),
318 l10n_util::GetStringUTF16(rotation_text_id));
319 return true;
320 }
321 }
322
323 // Found nothing special
324 return false;
325 }
326
327 void ScreenLayoutObserver::CreateOrUpdateNotification(
328 const base::string16& message,
329 const base::string16& additional_message) {
330 // Always remove the notification to make sure the notification appears
331 // as a popup in any situation.
332 message_center::MessageCenter::Get()->RemoveNotification(kNotificationId,
333 false /* by_user */);
334
335 if (message.empty() && additional_message.empty())
336 return;
337
338 // Don't display notifications for accelerometer triggered screen rotations.
339 // See http://crbug.com/364949
340 if (Shell::GetInstance()
341 ->screen_orientation_controller()
342 ->ignore_display_configuration_updates()) {
343 return;
344 }
345
346 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
347 std::unique_ptr<Notification> notification(new Notification(
348 message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, message,
349 additional_message, bundle.GetImageNamed(IDR_AURA_NOTIFICATION_DISPLAY),
350 base::string16(), // display_source
351 GURL(),
352 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
353 system_notifier::kNotifierDisplay),
354 message_center::RichNotificationData(),
355 new message_center::HandleNotificationClickedDelegate(
356 base::Bind(&OpenSettingsFromNotification))));
357
358 WmShell::Get()->RecordUserMetricsAction(
359 UMA_STATUS_AREA_DISPLAY_NOTIFICATION_CREATED);
360 message_center::MessageCenter::Get()->AddNotification(
361 std::move(notification));
362 }
363
364 void ScreenLayoutObserver::OnDisplayConfigurationChanged() {
365 DisplayInfoMap old_info;
366 UpdateDisplayInfo(&old_info);
367
368 old_display_mode_ = current_display_mode_;
369 if (GetDisplayManager()->IsInMirrorMode())
370 current_display_mode_ = DisplayMode::MIRRORING;
371 else if (GetDisplayManager()->IsInUnifiedMode())
372 current_display_mode_ = DisplayMode::UNIFIED;
373 else if (IsDockedModeEnabled())
374 current_display_mode_ = DisplayMode::DOCKED;
375 else if (GetDisplayManager()->GetNumDisplays() > 2)
376 current_display_mode_ = DisplayMode::EXTENDED_3_PLUS;
377 else if (GetDisplayManager()->GetNumDisplays() == 2)
378 current_display_mode_ = DisplayMode::EXTENDED_2;
379 else
380 current_display_mode_ = DisplayMode::SINGLE;
381
382 if (!show_notifications_for_testing)
383 return;
384
385 base::string16 message;
386 base::string16 additional_message;
387 if (GetDisplayMessageForNotification(old_info, &message, &additional_message))
388 CreateOrUpdateNotification(message, additional_message);
389 }
390
391 bool ScreenLayoutObserver::GetExitMirrorModeMessage(
392 base::string16* out_message,
393 base::string16* out_additional_message) {
394 switch (current_display_mode_) {
395 case DisplayMode::EXTENDED_3_PLUS:
396 // Mirror mode was turned off due to having more than two displays.
397 // Show a message that mirror mode for 3+ displays is not supported.
398 *out_message =
399 l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_MIRRORING_NOT_SUPPORTED);
400 return true;
401
402 case DisplayMode::DOCKED:
403 // Handle disabling mirror mode as a result of going to docked mode
404 // when we only have a single display (this means we actually have two
405 // physical displays, one of which is the internal display, but they
406 // were in mirror mode, and hence considered as one. Closing the
407 // internal display disables mirror mode and we still have a single
408 // active display).
409 // Falls through.
410 case DisplayMode::SINGLE:
411 // We're exiting mirror mode because we removed one of the two
412 // displays.
413 *out_message =
414 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRROR_EXIT);
415 return true;
416
417 default:
418 // Mirror mode was turned off; other messages should be shown e.g.
419 // extended mode is on, ... etc.
420 return false;
421 }
422 }
423
424 } // 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