d24a6e998b42d2b5e5770227770b3364388ed44b
[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::UpdateInfo::UpdateSeverity severity, bool dark) {
41   switch (severity) {
42     case ash::UpdateInfo::UPDATE_NORMAL:
43       return dark ? IDR_AURA_UBER_TRAY_UPDATE_DARK:
44                     IDR_AURA_UBER_TRAY_UPDATE;
45
46     case ash::UpdateInfo::UPDATE_LOW_GREEN:
47       return dark ? IDR_AURA_UBER_TRAY_UPDATE_DARK_GREEN :
48                     IDR_AURA_UBER_TRAY_UPDATE_GREEN;
49
50     case ash::UpdateInfo::UPDATE_HIGH_ORANGE:
51       return dark ? IDR_AURA_UBER_TRAY_UPDATE_DARK_ORANGE :
52                     IDR_AURA_UBER_TRAY_UPDATE_ORANGE;
53
54     case ash::UpdateInfo::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::ActionableView {
64  public:
65   explicit UpdateView(const ash::UpdateInfo& info) {
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::FixedSizedImageView(0, ash::kTrayPopupItemHeight);
74     image->SetImage(bundle.GetImageNamed(DecideResource(info.severity, true))
75                         .ToImageSkia());
76
77     AddChildView(image);
78
79     base::string16 label =
80         info.factory_reset_required
81             ? bundle.GetLocalizedString(
82                   IDS_ASH_STATUS_TRAY_RESTART_AND_POWERWASH_TO_UPDATE)
83             : bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_UPDATE);
84     AddChildView(new views::Label(label));
85     SetAccessibleName(label);
86   }
87
88   ~UpdateView() override {}
89
90  private:
91   // Overridden from ActionableView.
92   bool PerformAction(const ui::Event& event) override {
93     ash::Shell::GetInstance()->
94         system_tray_delegate()->RequestRestartForUpdate();
95     return true;
96   }
97
98   DISALLOW_COPY_AND_ASSIGN(UpdateView);
99 };
100
101 }
102
103 namespace ash {
104 namespace tray {
105
106 class UpdateNagger : public ui::LayerAnimationObserver {
107  public:
108   explicit UpdateNagger(SystemTrayItem* owner)
109       : owner_(owner) {
110     RestartTimer();
111     owner_->system_tray()->GetWidget()->GetNativeView()->layer()->
112         GetAnimator()->AddObserver(this);
113   }
114
115   ~UpdateNagger() override {
116     StatusAreaWidget* status_area =
117         Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget();
118     if (status_area) {
119       status_area->system_tray()->GetWidget()->GetNativeView()->layer()->
120           GetAnimator()->RemoveObserver(this);
121     }
122   }
123
124   void RestartTimer() {
125     timer_.Stop();
126     timer_.Start(FROM_HERE,
127                  base::TimeDelta::FromSeconds(kUpdateNaggingTimeSeconds),
128                  this,
129                  &UpdateNagger::Nag);
130   }
131
132  private:
133   void Nag() {
134     owner_->PopupDetailedView(kShowUpdateNaggerForSeconds, false);
135   }
136
137   // Overridden from ui::LayerAnimationObserver.
138   void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {
139     // TODO(oshima): Find out if the updator will be shown on non
140     // primary display.
141     if (Shell::GetPrimaryRootWindowController()->shelf()->IsVisible())
142       timer_.Stop();
143     else if (!timer_.IsRunning())
144       RestartTimer();
145   }
146
147   void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {}
148
149   void OnLayerAnimationScheduled(
150       ui::LayerAnimationSequence* sequence) override {}
151
152   SystemTrayItem* owner_;
153   base::OneShotTimer<UpdateNagger> timer_;
154
155   DISALLOW_COPY_AND_ASSIGN(UpdateNagger);
156 };
157
158 }  // namespace tray
159
160 TrayUpdate::TrayUpdate(SystemTray* system_tray)
161     : TrayImageItem(system_tray, IDR_AURA_UBER_TRAY_UPDATE) {
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   UpdateInfo info;
171   Shell::GetInstance()->system_tray_delegate()->GetSystemUpdateInfo(&info);
172   return info.update_required;
173 }
174
175 views::View* TrayUpdate::CreateDefaultView(user::LoginStatus status) {
176   UpdateInfo info;
177   Shell::GetInstance()->system_tray_delegate()->GetSystemUpdateInfo(&info);
178   return info.update_required ? new UpdateView(info) : nullptr;
179 }
180
181 views::View* TrayUpdate::CreateDetailedView(user::LoginStatus status) {
182   return CreateDefaultView(status);
183 }
184
185 void TrayUpdate::DestroyDetailedView() {
186   if (nagger_) {
187     // The nagger was being displayed. Now that the detailed view is being
188     // closed, that means either the user clicks on it to restart, or the user
189     // didn't click on it to restart. In either case, start the timer to show
190     // the nag reminder again after the specified time.
191     nagger_->RestartTimer();
192   }
193 }
194
195 void TrayUpdate::OnUpdateRecommended(const UpdateInfo& info) {
196   SetImageFromResourceId(DecideResource(info.severity, false));
197   tray_view()->SetVisible(true);
198   if (!Shell::GetPrimaryRootWindowController()->shelf()->IsVisible() &&
199       !nagger_.get()) {
200     // The shelf is not visible, and there is no nagger scheduled.
201     nagger_.reset(new tray::UpdateNagger(this));
202   }
203 }
204
205 }  // namespace ash