- add sources.
[platform/framework/web/crosswalk.git] / src / ash / system / tray_update.cc
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/tray_update.h"
6
7 #include "ash/root_window_controller.h"
8 #include "ash/shelf/shelf_layout_manager.h"
9 #include "ash/shelf/shelf_widget.h"
10 #include "ash/shell.h"
11 #include "ash/system/status_area_widget.h"
12 #include "ash/system/tray/fixed_sized_image_view.h"
13 #include "ash/system/tray/system_tray.h"
14 #include "ash/system/tray/system_tray_delegate.h"
15 #include "ash/system/tray/system_tray_notifier.h"
16 #include "ash/system/tray/tray_constants.h"
17 #include "base/time/time.h"
18 #include "base/timer/timer.h"
19 #include "grit/ash_resources.h"
20 #include "grit/ash_strings.h"
21 #include "ui/aura/window.h"
22 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/compositor/layer.h"
24 #include "ui/compositor/layer_animation_observer.h"
25 #include "ui/compositor/layer_animation_sequence.h"
26 #include "ui/gfx/image/image.h"
27 #include "ui/views/controls/image_view.h"
28 #include "ui/views/controls/label.h"
29 #include "ui/views/layout/box_layout.h"
30 #include "ui/views/widget/widget.h"
31
32 namespace {
33
34 // How many seconds should we wait before showing the nag reminder?
35 const int kUpdateNaggingTimeSeconds = 24 * 60 * 60;
36
37 // How long should the nag reminder be displayed?
38 const int kShowUpdateNaggerForSeconds = 15;
39
40 int DecideResource(ash::UpdateObserver::UpdateSeverity severity, bool dark) {
41   switch (severity) {
42     case ash::UpdateObserver::UPDATE_NORMAL:
43       return dark ? IDR_AURA_UBER_TRAY_UPDATE_DARK:
44                     IDR_AURA_UBER_TRAY_UPDATE;
45
46     case ash::UpdateObserver::UPDATE_LOW_GREEN:
47       return dark ? IDR_AURA_UBER_TRAY_UPDATE_DARK_GREEN :
48                     IDR_AURA_UBER_TRAY_UPDATE_GREEN;
49
50     case ash::UpdateObserver::UPDATE_HIGH_ORANGE:
51       return dark ? IDR_AURA_UBER_TRAY_UPDATE_DARK_ORANGE :
52                     IDR_AURA_UBER_TRAY_UPDATE_ORANGE;
53
54     case ash::UpdateObserver::UPDATE_SEVERE_RED:
55       return dark ? IDR_AURA_UBER_TRAY_UPDATE_DARK_RED :
56                     IDR_AURA_UBER_TRAY_UPDATE_RED;
57   }
58
59   NOTREACHED() << "Unknown update severity level.";
60   return 0;
61 }
62
63 class UpdateView : public ash::internal::ActionableView {
64  public:
65   explicit UpdateView(ash::UpdateObserver::UpdateSeverity severity) {
66     SetLayoutManager(new
67         views::BoxLayout(views::BoxLayout::kHorizontal,
68         ash::kTrayPopupPaddingHorizontal, 0,
69         ash::kTrayPopupPaddingBetweenItems));
70
71     ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
72     views::ImageView* image =
73         new ash::internal::FixedSizedImageView(0, ash::kTrayPopupItemHeight);
74     image->SetImage(bundle.GetImageNamed(DecideResource(severity, true)).
75         ToImageSkia());
76
77     AddChildView(image);
78     AddChildView(new views::Label(
79         bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_UPDATE)));
80     SetAccessibleName(bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_UPDATE));
81   }
82
83   virtual ~UpdateView() {}
84
85  private:
86   // Overridden from ActionableView.
87   virtual bool PerformAction(const ui::Event& event) OVERRIDE {
88     ash::Shell::GetInstance()->
89         system_tray_delegate()->RequestRestartForUpdate();
90     return true;
91   }
92
93   DISALLOW_COPY_AND_ASSIGN(UpdateView);
94 };
95
96 }
97
98 namespace ash {
99 namespace internal {
100
101 namespace tray {
102
103 class UpdateNagger : public ui::LayerAnimationObserver {
104  public:
105   explicit UpdateNagger(SystemTrayItem* owner)
106       : owner_(owner) {
107     RestartTimer();
108     owner_->system_tray()->GetWidget()->GetNativeView()->layer()->
109         GetAnimator()->AddObserver(this);
110   }
111
112   virtual ~UpdateNagger() {
113     internal::StatusAreaWidget* status_area =
114         Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget();
115     if (status_area) {
116       status_area->system_tray()->GetWidget()->GetNativeView()->layer()->
117           GetAnimator()->RemoveObserver(this);
118     }
119   }
120
121   void RestartTimer() {
122     timer_.Stop();
123     timer_.Start(FROM_HERE,
124                  base::TimeDelta::FromSeconds(kUpdateNaggingTimeSeconds),
125                  this,
126                  &UpdateNagger::Nag);
127   }
128
129  private:
130   void Nag() {
131     owner_->PopupDetailedView(kShowUpdateNaggerForSeconds, false);
132   }
133
134   // Overridden from ui::LayerAnimationObserver.
135   virtual void OnLayerAnimationEnded(
136       ui::LayerAnimationSequence* sequence) OVERRIDE {
137     // TODO(oshima): Find out if the updator will be shown on non
138     // primary display.
139     if (Shell::GetPrimaryRootWindowController()->shelf()->IsVisible())
140       timer_.Stop();
141     else if (!timer_.IsRunning())
142       RestartTimer();
143   }
144
145   virtual void OnLayerAnimationAborted(
146       ui::LayerAnimationSequence* sequence) OVERRIDE {}
147
148   virtual void OnLayerAnimationScheduled(
149       ui::LayerAnimationSequence* sequence) OVERRIDE {}
150
151   SystemTrayItem* owner_;
152   base::OneShotTimer<UpdateNagger> timer_;
153
154   DISALLOW_COPY_AND_ASSIGN(UpdateNagger);
155 };
156
157 }  // namespace tray
158
159 TrayUpdate::TrayUpdate(SystemTray* system_tray)
160     : TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_UPDATE),
161       severity_(UpdateObserver::UPDATE_NORMAL) {
162   Shell::GetInstance()->system_tray_notifier()->AddUpdateObserver(this);
163 }
164
165 TrayUpdate::~TrayUpdate() {
166   Shell::GetInstance()->system_tray_notifier()->RemoveUpdateObserver(this);
167 }
168
169 bool TrayUpdate::GetInitialVisibility() {
170   return Shell::GetInstance()->system_tray_delegate()->SystemShouldUpgrade();
171 }
172
173 views::View* TrayUpdate::CreateDefaultView(user::LoginStatus status) {
174   if (!Shell::GetInstance()->system_tray_delegate()->SystemShouldUpgrade())
175     return NULL;
176   return new UpdateView(severity_);
177 }
178
179 views::View* TrayUpdate::CreateDetailedView(user::LoginStatus status) {
180   return CreateDefaultView(status);
181 }
182
183 void TrayUpdate::DestroyDetailedView() {
184   if (nagger_) {
185     // The nagger was being displayed. Now that the detailed view is being
186     // closed, that means either the user clicks on it to restart, or the user
187     // didn't click on it to restart. In either case, start the timer to show
188     // the nag reminder again after the specified time.
189     nagger_->RestartTimer();
190   }
191 }
192
193 void TrayUpdate::OnUpdateRecommended(UpdateObserver::UpdateSeverity severity) {
194   severity_ = severity;
195   SetImageFromResourceId(DecideResource(severity_, false));
196   tray_view()->SetVisible(true);
197   if (!Shell::GetPrimaryRootWindowController()->shelf()->IsVisible() &&
198       !nagger_.get()) {
199     // The shelf is not visible, and there is no nagger scheduled.
200     nagger_.reset(new tray::UpdateNagger(this));
201   }
202 }
203
204 }  // namespace internal
205 }  // namespace ash