- add sources.
[platform/framework/web/crosswalk.git] / src / ash / display / resolution_notification_controller.cc
1 // Copyright 2013 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/display/resolution_notification_controller.h"
6
7 #include "ash/display/display_controller.h"
8 #include "ash/display/display_manager.h"
9 #include "ash/shell.h"
10 #include "ash/system/system_notifier.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "grit/ash_resources.h"
13 #include "grit/ash_strings.h"
14 #include "ui/base/l10n/l10n_util.h"
15 #include "ui/base/l10n/time_format.h"
16 #include "ui/base/resource/resource_bundle.h"
17 #include "ui/gfx/display.h"
18 #include "ui/gfx/screen.h"
19 #include "ui/message_center/message_center.h"
20 #include "ui/message_center/notification.h"
21 #include "ui/message_center/notification_delegate.h"
22
23 using message_center::Notification;
24
25 namespace ash {
26 namespace internal {
27 namespace {
28
29 bool g_use_timer = true;
30
31 class ResolutionChangeNotificationDelegate
32     : public message_center::NotificationDelegate {
33  public:
34   ResolutionChangeNotificationDelegate(
35       ResolutionNotificationController* controller,
36       bool has_timeout);
37
38  protected:
39   virtual ~ResolutionChangeNotificationDelegate();
40
41  private:
42   // message_center::NotificationDelegate overrides:
43   virtual void Display() OVERRIDE;
44   virtual void Error() OVERRIDE;
45   virtual void Close(bool by_user) OVERRIDE;
46   virtual void Click() OVERRIDE;
47   virtual bool HasClickedListener() OVERRIDE;
48   virtual void ButtonClick(int button_index) OVERRIDE;
49
50   ResolutionNotificationController* controller_;
51   bool has_timeout_;
52
53   DISALLOW_COPY_AND_ASSIGN(ResolutionChangeNotificationDelegate);
54 };
55
56 ResolutionChangeNotificationDelegate::ResolutionChangeNotificationDelegate(
57     ResolutionNotificationController* controller,
58     bool has_timeout)
59     : controller_(controller),
60       has_timeout_(has_timeout) {
61   DCHECK(controller_);
62 }
63
64 ResolutionChangeNotificationDelegate::~ResolutionChangeNotificationDelegate() {
65 }
66
67 void ResolutionChangeNotificationDelegate::Display() {
68 }
69
70 void ResolutionChangeNotificationDelegate::Error() {
71 }
72
73 void ResolutionChangeNotificationDelegate::Close(bool by_user) {
74   if (by_user)
75     controller_->AcceptResolutionChange(false);
76 }
77
78 void ResolutionChangeNotificationDelegate::Click() {
79   controller_->AcceptResolutionChange(true);
80 }
81
82 bool ResolutionChangeNotificationDelegate::HasClickedListener() {
83   return true;
84 }
85
86 void ResolutionChangeNotificationDelegate::ButtonClick(int button_index) {
87   // If there's the timeout, the first button is "Accept". Otherwise the
88   // button click should be "Revert".
89   if (has_timeout_ && button_index == 0)
90     controller_->AcceptResolutionChange(true);
91   else
92     controller_->RevertResolutionChange();
93 }
94
95 }  // namespace
96
97 // static
98 const int ResolutionNotificationController::kTimeoutInSec = 15;
99
100 // static
101 const char ResolutionNotificationController::kNotificationId[] =
102     "chrome://settings/display/resolution";
103
104 struct ResolutionNotificationController::ResolutionChangeInfo {
105   ResolutionChangeInfo(int64 display_id,
106                        const gfx::Size& old_resolution,
107                        const gfx::Size& new_resolution,
108                        const base::Closure& accept_callback);
109   ~ResolutionChangeInfo();
110
111   // The id of the display where the resolution change happens.
112   int64 display_id;
113
114   // The resolution before the change.
115   gfx::Size old_resolution;
116
117   // The new resolution after the change.
118   gfx::Size new_resolution;
119
120   // The callback when accept is chosen.
121   base::Closure accept_callback;
122
123   // The remaining timeout in seconds. 0 if the change does not time out.
124   uint8 timeout_count;
125
126   // The timer to invoke OnTimerTick() every second. This cannot be
127   // OneShotTimer since the message contains text "automatically closed in xx
128   // seconds..." which has to be updated every second.
129   base::RepeatingTimer<ResolutionNotificationController> timer;
130
131  private:
132   DISALLOW_COPY_AND_ASSIGN(ResolutionChangeInfo);
133 };
134
135 ResolutionNotificationController::ResolutionChangeInfo::ResolutionChangeInfo(
136     int64 display_id,
137     const gfx::Size& old_resolution,
138     const gfx::Size& new_resolution,
139     const base::Closure& accept_callback)
140     : display_id(display_id),
141       old_resolution(old_resolution),
142       new_resolution(new_resolution),
143       accept_callback(accept_callback),
144       timeout_count(0) {
145   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
146   if (!display_manager->HasInternalDisplay() &&
147       display_manager->num_connected_displays() == 1u) {
148     timeout_count = kTimeoutInSec;
149   }
150 }
151
152 ResolutionNotificationController::ResolutionChangeInfo::
153     ~ResolutionChangeInfo() {
154 }
155
156 ResolutionNotificationController::ResolutionNotificationController() {
157   Shell::GetInstance()->display_controller()->AddObserver(this);
158   Shell::GetScreen()->AddObserver(this);
159 }
160
161 ResolutionNotificationController::~ResolutionNotificationController() {
162   Shell::GetInstance()->display_controller()->RemoveObserver(this);
163   Shell::GetScreen()->RemoveObserver(this);
164 }
165
166 void ResolutionNotificationController::SetDisplayResolutionAndNotify(
167     int64 display_id,
168     const gfx::Size& old_resolution,
169     const gfx::Size& new_resolution,
170     const base::Closure& accept_callback) {
171   // If multiple resolution changes are invoked for the same display,
172   // the original resolution for the first resolution change has to be used
173   // instead of the specified |old_resolution|.
174   gfx::Size original_resolution;
175   if (change_info_ && change_info_->display_id == display_id) {
176     DCHECK(change_info_->new_resolution == old_resolution);
177     original_resolution = change_info_->old_resolution;
178   }
179
180   change_info_.reset(new ResolutionChangeInfo(
181       display_id, old_resolution, new_resolution, accept_callback));
182   if (!original_resolution.IsEmpty())
183     change_info_->old_resolution = original_resolution;
184
185   // SetDisplayResolution() causes OnConfigurationChanged() and the notification
186   // will be shown at that point.
187   Shell::GetInstance()->display_manager()->SetDisplayResolution(
188       display_id, new_resolution);
189 }
190
191 bool ResolutionNotificationController::DoesNotificationTimeout() {
192   return change_info_ && change_info_->timeout_count > 0;
193 }
194
195 void ResolutionNotificationController::CreateOrUpdateNotification(
196     bool enable_spoken_feedback) {
197   message_center::MessageCenter* message_center =
198       message_center::MessageCenter::Get();
199   if (!change_info_) {
200     message_center->RemoveNotification(kNotificationId, false /* by_user */);
201     return;
202   }
203
204   base::string16 timeout_message;
205   message_center::RichNotificationData data;
206   if (change_info_->timeout_count > 0) {
207     data.buttons.push_back(message_center::ButtonInfo(
208         l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_RESOLUTION_CHANGE_ACCEPT)));
209     timeout_message = l10n_util::GetStringFUTF16(
210         IDS_ASH_DISPLAY_RESOLUTION_TIMEOUT,
211         ui::TimeFormat::TimeDurationLong(
212             base::TimeDelta::FromSeconds(change_info_->timeout_count)));
213   }
214   data.buttons.push_back(message_center::ButtonInfo(
215         l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_RESOLUTION_CHANGE_REVERT)));
216
217   data.should_make_spoken_feedback_for_popup_updates = enable_spoken_feedback;
218
219   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
220   scoped_ptr<Notification> notification(new Notification(
221       message_center::NOTIFICATION_TYPE_SIMPLE,
222       kNotificationId,
223       l10n_util::GetStringFUTF16(
224           IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
225           UTF8ToUTF16(Shell::GetInstance()->display_manager()->
226               GetDisplayNameForId(change_info_->display_id)),
227           UTF8ToUTF16(change_info_->new_resolution.ToString())),
228       timeout_message,
229       bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY),
230       base::string16() /* display_source */,
231       message_center::NotifierId(
232           system_notifier::NOTIFIER_DISPLAY_RESOLUTION_CHANGE),
233       data,
234       new ResolutionChangeNotificationDelegate(
235           this, change_info_->timeout_count > 0)));
236   notification->SetSystemPriority();
237   message_center->AddNotification(notification.Pass());
238 }
239
240 void ResolutionNotificationController::OnTimerTick() {
241   if (!change_info_)
242     return;
243
244   --change_info_->timeout_count;
245   if (change_info_->timeout_count == 0)
246     RevertResolutionChange();
247   else
248     CreateOrUpdateNotification(false);
249 }
250
251 void ResolutionNotificationController::AcceptResolutionChange(
252     bool close_notification) {
253   if (close_notification) {
254     message_center::MessageCenter::Get()->RemoveNotification(
255         kNotificationId, false /* by_user */);
256   }
257   base::Closure callback = change_info_->accept_callback;
258   change_info_.reset();
259   callback.Run();
260 }
261
262 void ResolutionNotificationController::RevertResolutionChange() {
263   message_center::MessageCenter::Get()->RemoveNotification(
264       kNotificationId, false /* by_user */);
265   int64 display_id = change_info_->display_id;
266   gfx::Size old_resolution = change_info_->old_resolution;
267   change_info_.reset();
268   Shell::GetInstance()->display_manager()->SetDisplayResolution(
269       display_id, old_resolution);
270 }
271
272 void ResolutionNotificationController::OnDisplayBoundsChanged(
273     const gfx::Display& display) {
274 }
275
276 void ResolutionNotificationController::OnDisplayAdded(
277     const gfx::Display& new_display) {
278 }
279
280 void ResolutionNotificationController::OnDisplayRemoved(
281     const gfx::Display& old_display) {
282   if (change_info_ && change_info_->display_id == old_display.id())
283     RevertResolutionChange();
284 }
285
286 void ResolutionNotificationController::OnDisplayConfigurationChanged() {
287   if (!change_info_)
288     return;
289
290   CreateOrUpdateNotification(true);
291   if (g_use_timer && change_info_->timeout_count > 0) {
292     change_info_->timer.Start(FROM_HERE,
293                               base::TimeDelta::FromSeconds(1),
294                               this,
295                               &ResolutionNotificationController::OnTimerTick);
296   }
297 }
298
299 void ResolutionNotificationController::SuppressTimerForTest() {
300   g_use_timer = false;
301 }
302
303 }  // namespace internal
304 }  // namespace ash