summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/ash.gyp4
-rw-r--r--ash/ash_strings.grd9
-rw-r--r--ash/shell.cc10
-rw-r--r--ash/system/drive/drive_observer.h23
-rw-r--r--ash/system/drive/tray_drive.cc450
-rw-r--r--ash/system/drive/tray_drive.h62
-rw-r--r--ash/system/tray/system_tray.cc40
-rw-r--r--ash/system/tray/system_tray.h5
-rw-r--r--ash/system/tray/system_tray_delegate.cc45
-rw-r--r--ash/system/tray/system_tray_delegate.h42
-rw-r--r--chrome/browser/chromeos/gdata/gdata_operation_registry.cc4
-rw-r--r--chrome/browser/chromeos/gdata/gdata_operation_registry.h5
-rw-r--r--chrome/browser/chromeos/gdata/gdata_util.cc7
-rw-r--r--chrome/browser/chromeos/system/ash_system_tray_delegate.cc140
-rw-r--r--ui/resources/ui_resources.grd6
15 files changed, 817 insertions, 35 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index f4014ea..d89e543 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -134,6 +134,9 @@
'system/date/date_view.h',
'system/date/tray_date.cc',
'system/date/tray_date.h',
+ 'system/drive/drive_observer.h',
+ 'system/drive/tray_drive.cc',
+ 'system/drive/tray_drive.h',
'system/ime/ime_observer.h',
'system/ime/tray_ime.cc',
'system/ime/tray_ime.h',
@@ -149,6 +152,7 @@
'system/settings/tray_settings.h',
'system/tray/system_tray.cc',
'system/tray/system_tray.h',
+ 'system/tray/system_tray_delegate.cc',
'system/tray/system_tray_delegate.h',
'system/tray/system_tray_item.cc',
'system/tray/system_tray_item.h',
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 2312dca..92538d7 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -282,6 +282,15 @@ This file contains the strings for ash.
<message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_ADD_DEVICE" desc="The label used in the tray popup to add a bluetooth device.">
Add device...
</message>
+ <message name="IDS_ASH_STATUS_TRAY_DRIVE_SYNCING" desc="The label in the tray to indicate onoing file sync operations.">
+ Syncing <ph name="count">$1<ex>3</ex></ph> file(s)
+ </message>
+ <message name="IDS_ASH_STATUS_TRAY_DRIVE" desc="The label used for Google Drive tray details header.">
+ Google Drive
+ </message>
+ <message name="IDS_ASH_STATUS_TRAY_DRIVE_SETTINGS" desc="The label used for Google Drive settings entry.">
+ Google Drive settings...
+ </message>
<message name="IDS_ASH_STATUS_TRAY_IME" desc="The label used as the header in the IME popup.">
Input methods
</message>
diff --git a/ash/shell.cc b/ash/shell.cc
index d025e4d..36391fd 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -309,6 +309,9 @@ class DummySystemTrayDelegate : public SystemTrayDelegate {
virtual void ShowBluetoothSettings() OVERRIDE {
}
+ virtual void ShowDriveSettings() OVERRIDE {
+ }
+
virtual void ShowIMESettings() OVERRIDE {
}
@@ -375,6 +378,13 @@ class DummySystemTrayDelegate : public SystemTrayDelegate {
virtual void ActivateIMEProperty(const std::string& key) OVERRIDE {
}
+ virtual void CancelDriveOperation(const FilePath&) OVERRIDE {
+ }
+
+ virtual void GetDriveOperationStatusList(
+ ash::DriveOperationStatusList*) OVERRIDE {
+ }
+
virtual void GetMostRelevantNetworkIcon(NetworkIconInfo* info,
bool large) OVERRIDE {
}
diff --git a/ash/system/drive/drive_observer.h b/ash/system/drive/drive_observer.h
new file mode 100644
index 0000000..18d12ba
--- /dev/null
+++ b/ash/system/drive/drive_observer.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_DRIVE_DRIVE_OBSERVER_H_
+#define ASH_SYSTEM_DRIVE_DRIVE_OBSERVER_H_
+#pragma once
+
+#include "ash/system/tray/system_tray_delegate.h"
+
+namespace ash {
+
+class DriveObserver {
+ public:
+ virtual void OnDriveRefresh(const DriveOperationStatusList& list) = 0;
+
+ protected:
+ virtual ~DriveObserver() {}
+};
+
+} // namespace ash
+
+#endif // ASH_SYSTEM_DRIVE_DRIVE_OBSERVER_H_
diff --git a/ash/system/drive/tray_drive.cc b/ash/system/drive/tray_drive.cc
new file mode 100644
index 0000000..0f0a46c
--- /dev/null
+++ b/ash/system/drive/tray_drive.cc
@@ -0,0 +1,450 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/drive/tray_drive.h"
+
+#include <vector>
+
+#include "ash/shell.h"
+#include "ash/system/tray/system_tray.h"
+#include "ash/system/tray/system_tray_delegate.h"
+#include "ash/system/tray/tray_constants.h"
+#include "ash/system/tray/tray_item_more.h"
+#include "ash/system/tray/tray_item_view.h"
+#include "ash/system/tray/tray_views.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/stl_util.h"
+#include "grit/ash_strings.h"
+#include "grit/ui_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/image/image.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/progress_bar.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+namespace internal {
+
+namespace {
+
+const int kSidePadding = 8;
+const int kHorizontalPadding = 6;
+const int kVerticalPadding = 6;
+const int kTopPadding = 6;
+const int kBottomPadding = 10;
+const int kProgressBarWidth = 100;
+const int kProgressBarHeight = 8;
+
+string16 GetTrayLabel(const ash::DriveOperationStatusList& list) {
+ return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DRIVE_SYNCING,
+ base::IntToString16(static_cast<int>(list.size())));
+}
+
+ash::DriveOperationStatusList* GetCurrentOperationList() {
+ ash::SystemTrayDelegate* delegate =
+ ash::Shell::GetInstance()->tray_delegate();
+ ash::DriveOperationStatusList* list = new ash::DriveOperationStatusList();
+ delegate->GetDriveOperationStatusList(list);
+ return list;
+}
+
+}
+
+namespace tray {
+
+
+class DriveDefaultView : public TrayItemMore {
+ public:
+ DriveDefaultView(SystemTrayItem* owner,
+ const DriveOperationStatusList* list)
+ : TrayItemMore(owner) {
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+
+ SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DRIVE).ToSkBitmap());
+ Update(list);
+ }
+
+ virtual ~DriveDefaultView() {}
+
+ void Update(const DriveOperationStatusList* list) {
+ DCHECK(list);
+ string16 label = GetTrayLabel(*list);
+ SetLabel(label);
+ SetAccessibleName(label);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DriveDefaultView);
+};
+
+class DriveDetailedView : public views::View,
+ public ViewClickListener {
+ public:
+ DriveDetailedView(SystemTrayItem* owner,
+ const DriveOperationStatusList* list)
+ : header_(NULL),
+ operations_(NULL),
+ settings_(NULL),
+ in_progress_img_(NULL),
+ done_img_(NULL),
+ failed_img_(NULL) {
+ SetLayoutManager(new views::BoxLayout(
+ views::BoxLayout::kVertical, 0, 0, 0));
+ set_background(views::Background::CreateSolidBackground(kBackgroundColor));
+
+ in_progress_img_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_AURA_UBER_TRAY_DRIVE);
+ done_img_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_AURA_UBER_TRAY_DRIVE_DONE);
+ failed_img_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_AURA_UBER_TRAY_DRIVE_FAILED);
+
+ Update(list);
+ }
+
+ virtual ~DriveDetailedView() {
+ STLDeleteValues(&update_map_);
+ }
+
+ void Update(const DriveOperationStatusList* list) {
+ AppendHeaderEntry(list);
+ AppendOperationList(list);
+ AppendSettings();
+ PreferredSizeChanged();
+ SchedulePaint();
+ }
+
+ private:
+
+ class OperationProgressBar : public views::ProgressBar {
+ public:
+ OperationProgressBar() {}
+ private:
+
+ // Overridden from View:
+ virtual gfx::Size GetPreferredSize() OVERRIDE {
+ return gfx::Size(kProgressBarWidth, kProgressBarHeight);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(OperationProgressBar);
+ };
+
+ class RowView : public HoverHighlightView,
+ public views::ButtonListener {
+ public:
+ RowView(DriveDetailedView* parent,
+ ash::DriveOperationStatus::OperationState state,
+ double progress,
+ const FilePath& file_path)
+ : HoverHighlightView(parent),
+ container_(parent),
+ status_img_(NULL),
+ label_container_(NULL),
+ progress_bar_(NULL),
+ cancel_button_(NULL),
+ file_path_(file_path) {
+ // Status image.
+ status_img_ = new views::ImageView();
+ AddChildView(status_img_);
+
+ label_container_ = new views::View();
+ label_container_->SetLayoutManager(new views::BoxLayout(
+ views::BoxLayout::kVertical, 0, 0, kVerticalPadding));
+ views::Label* label = new views::Label(
+ UTF8ToUTF16(file_path.BaseName().value()));
+ label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ label_container_->AddChildView(label);
+ // Add progress bar.
+ progress_bar_ = new OperationProgressBar();
+ label_container_->AddChildView(progress_bar_);
+
+ AddChildView(label_container_);
+
+ cancel_button_ = new views::ImageButton(this);
+ cancel_button_->SetImage(views::ImageButton::BS_NORMAL,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_AURA_UBER_TRAY_DRIVE_CANCEL));
+ cancel_button_->SetImage(views::ImageButton::BS_HOT,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_AURA_UBER_TRAY_DRIVE_CANCEL_HOVER));
+
+ UpdateStatus(state, progress);
+ AddChildView(cancel_button_);
+ }
+
+ void UpdateStatus(ash::DriveOperationStatus::OperationState state,
+ double progress) {
+ status_img_->SetImage(container_->GetImageForState(state));
+ progress_bar_->SetValue(progress);
+ cancel_button_->SetVisible(
+ state == ash::DriveOperationStatus::OPERATION_IN_PROGRESS ||
+ state == ash::DriveOperationStatus::OPERATION_SUSPENDED);
+ }
+
+ private:
+
+ // views::View overrides.
+ virtual gfx::Size GetPreferredSize() OVERRIDE {
+ return gfx::Size(
+ status_img_->GetPreferredSize().width() +
+ label_container_->GetPreferredSize().width() +
+ cancel_button_->GetPreferredSize().width() +
+ 2 * kSidePadding + 2 * kHorizontalPadding,
+ std::max(status_img_->GetPreferredSize().height(),
+ std::max(label_container_->GetPreferredSize().height(),
+ cancel_button_->GetPreferredSize().height())) +
+ kTopPadding + kBottomPadding);
+ }
+
+ virtual void Layout() OVERRIDE {
+ gfx::Rect child_area(GetLocalBounds());
+ if (child_area.IsEmpty())
+ return;
+
+ int pos_x = child_area.x() + kSidePadding;
+ int pos_y = child_area.y() + kTopPadding;
+
+ gfx::Rect bounds_status(
+ gfx::Point(pos_x,
+ pos_y + (child_area.height() - kTopPadding -
+ kBottomPadding -
+ status_img_->GetPreferredSize().height())/2),
+ status_img_->GetPreferredSize());
+ status_img_->SetBoundsRect(bounds_status.Intersect(child_area));
+ pos_x += status_img_->bounds().width() + kHorizontalPadding;
+
+ gfx::Rect bounds_label(pos_x,
+ pos_y,
+ child_area.width() - 2 * kSidePadding -
+ 2 * kHorizontalPadding -
+ status_img_->GetPreferredSize().width() -
+ cancel_button_->GetPreferredSize().width(),
+ label_container_->GetPreferredSize().height());
+ label_container_->SetBoundsRect(bounds_label.Intersect(child_area));
+ pos_x += label_container_->bounds().width() + kHorizontalPadding;
+
+ gfx::Rect bounds_button(
+ gfx::Point(pos_x,
+ pos_y + (child_area.height() - kTopPadding -
+ kBottomPadding -
+ cancel_button_->GetPreferredSize().height())/2),
+ cancel_button_->GetPreferredSize());
+ cancel_button_->SetBoundsRect(bounds_button.Intersect(child_area));
+ }
+
+ // views::ButtonListener overrides.
+ virtual void ButtonPressed(views::Button* sender,
+ const views::Event& event) OVERRIDE {
+ DCHECK(sender == cancel_button_);
+ container_->OnCancelOperation(file_path_);
+ }
+
+ DriveDetailedView* container_;
+ views::ImageView* status_img_;
+ views::View* label_container_;
+ views::ProgressBar* progress_bar_;
+ views::ImageButton* cancel_button_;
+ FilePath file_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(RowView);
+ };
+
+ void AppendHeaderEntry(const DriveOperationStatusList* list) {
+ if (header_)
+ return;
+ header_ = CreateDetailedHeaderEntry(IDS_ASH_STATUS_TRAY_DRIVE, this);
+ AddChildView(header_);
+ }
+
+ SkBitmap* GetImageForState(ash::DriveOperationStatus::OperationState state) {
+ switch (state) {
+ case ash::DriveOperationStatus::OPERATION_NOT_STARTED:
+ case ash::DriveOperationStatus::OPERATION_STARTED:
+ case ash::DriveOperationStatus::OPERATION_IN_PROGRESS:
+ case ash::DriveOperationStatus::OPERATION_SUSPENDED:
+ return in_progress_img_;
+ case ash::DriveOperationStatus::OPERATION_COMPLETED:
+ return done_img_;
+ case ash::DriveOperationStatus::OPERATION_FAILED:
+ return failed_img_;
+ }
+ return failed_img_;
+ }
+
+ virtual void OnCancelOperation(const FilePath& file_path) {
+ SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate();
+ delegate->CancelDriveOperation(file_path);
+ }
+
+ void AppendOperationList(const DriveOperationStatusList* list) {
+ if (!operations_) {
+ operations_ = new views::View;
+ operations_->SetLayoutManager(new views::BoxLayout(
+ views::BoxLayout::kVertical, 0, 0, 1));
+ AddChildView(operations_);
+ }
+
+ // Apply the update.
+ std::set<FilePath> new_set;
+ for (DriveOperationStatusList::const_iterator it = list->begin();
+ it != list->end(); ++it) {
+ const DriveOperationStatus& operation = *it;
+
+ new_set.insert(operation.file_path);
+ std::map<FilePath, RowView*>::iterator existing_item =
+ update_map_.find(operation.file_path);
+
+ if (existing_item != update_map_.end()) {
+ existing_item->second->UpdateStatus(operation.state,
+ operation.progress);
+ } else {
+ RowView* row_view = new RowView(this,
+ operation.state,
+ operation.progress,
+ operation.file_path);
+
+ update_map_[operation.file_path] = row_view;
+ operations_->AddChildView(row_view);
+ }
+ }
+
+ // Remove items from the list that haven't been added or modified with this
+ // update batch.
+ std::set<FilePath> remove_set;
+ for (std::map<FilePath, RowView*>::iterator update_iter =
+ update_map_.begin();
+ update_iter != update_map_.end(); ++update_iter) {
+ if (new_set.find(update_iter->first) == new_set.end()) {
+ remove_set.insert(update_iter->first);
+ }
+ }
+
+ for (std::set<FilePath>::iterator removed_iter = remove_set.begin();
+ removed_iter != remove_set.end(); ++removed_iter) {
+ delete update_map_[*removed_iter];
+ update_map_.erase(*removed_iter);
+ }
+
+ // Close the details if there is really nothing to show there anymore.
+ if (new_set.empty())
+ GetWidget()->Close();
+ }
+
+ void AppendSettings() {
+ if (settings_)
+ return;
+
+ HoverHighlightView* container = new HoverHighlightView(this);
+ container->set_fixed_height(kTrayPopupItemHeight);
+ container->AddLabel(ui::ResourceBundle::GetSharedInstance().
+ GetLocalizedString(IDS_ASH_STATUS_TRAY_DRIVE_SETTINGS),
+ gfx::Font::NORMAL);
+ AddChildView(container);
+ settings_ = container;
+ }
+
+ // Overridden from ViewClickListener.
+ virtual void ClickedOn(views::View* sender) OVERRIDE {
+ SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate();
+ if (sender == header_) {
+ Shell::GetInstance()->tray()->ShowDefaultView();
+ } else if (sender == settings_) {
+ delegate->ShowDriveSettings();
+ }
+ }
+
+ // Maps operation entries to their file paths.
+ std::map<FilePath, RowView*> update_map_;
+ views::View* header_;
+ views::View* operations_;
+ views::View* settings_;
+ SkBitmap* in_progress_img_;
+ SkBitmap* done_img_;
+ SkBitmap* failed_img_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriveDetailedView);
+};
+
+} // namespace tray
+
+TrayDrive::TrayDrive() :
+ TrayImageItem(IDR_AURA_UBER_TRAY_DRIVE_LIGHT),
+ default_(NULL),
+ detailed_(NULL) {
+}
+
+TrayDrive::~TrayDrive() {
+}
+
+bool TrayDrive::GetInitialVisibility() {
+ scoped_ptr<DriveOperationStatusList> list(GetCurrentOperationList());
+ return list->size() > 0;
+}
+
+views::View* TrayDrive::CreateDefaultView(user::LoginStatus status) {
+ DCHECK(!default_);
+
+ if (status != user::LOGGED_IN_USER && status != user::LOGGED_IN_OWNER)
+ return NULL;
+
+ scoped_ptr<DriveOperationStatusList> list(GetCurrentOperationList());
+ if (!list->size())
+ return NULL;
+
+ default_ = new tray::DriveDefaultView(this, list.get());
+ return default_;
+}
+
+views::View* TrayDrive::CreateDetailedView(user::LoginStatus status) {
+ DCHECK(!detailed_);
+
+ if (status != user::LOGGED_IN_USER && status != user::LOGGED_IN_OWNER)
+ return NULL;
+
+ scoped_ptr<DriveOperationStatusList> list(GetCurrentOperationList());
+ if (!list->size())
+ return NULL;
+
+ detailed_ = new tray::DriveDetailedView(this, list.get());
+ return detailed_;
+}
+
+void TrayDrive::DestroyDefaultView() {
+ default_ = NULL;
+}
+
+void TrayDrive::DestroyDetailedView() {
+ detailed_ = NULL;
+}
+
+void TrayDrive::UpdateAfterLoginStatusChange(user::LoginStatus status) {
+ if (status == user::LOGGED_IN_USER || status == user::LOGGED_IN_OWNER)
+ return;
+
+ tray_view()->SetVisible(false);
+ DestroyDefaultView();
+ DestroyDetailedView();
+}
+
+void TrayDrive::OnDriveRefresh(const DriveOperationStatusList& list) {
+ tray_view()->SetVisible(list.size() > 0);
+ tray_view()->SchedulePaint();
+
+ if (default_)
+ default_->Update(&list);
+
+ if (detailed_)
+ detailed_->Update(&list);
+}
+
+} // namespace internal
+} // namespace ash
diff --git a/ash/system/drive/tray_drive.h b/ash/system/drive/tray_drive.h
new file mode 100644
index 0000000..10ceb0b
--- /dev/null
+++ b/ash/system/drive/tray_drive.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_DRIVE_TRAY_DRIVE_H_
+#define ASH_SYSTEM_DRIVE_TRAY_DRIVE_H_
+#pragma once
+
+#include "ash/system/drive/drive_observer.h"
+#include "ash/system/tray/tray_image_item.h"
+#include "base/memory/scoped_ptr.h"
+
+
+namespace views {
+class Label;
+}
+
+namespace ash {
+
+namespace internal {
+
+namespace tray {
+class DriveTrayView;
+class DriveDefaultView;
+class DriveDetailedView;
+}
+
+class TrayDrive : public TrayImageItem,
+ public DriveObserver {
+ public:
+ TrayDrive();
+ virtual ~TrayDrive();
+
+ private:
+ // Overridden from TrayImageItem.
+ virtual bool GetInitialVisibility() OVERRIDE;
+
+ // Overridden from SystemTrayItem.
+ virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE;
+ virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE;
+ virtual void DestroyDefaultView() OVERRIDE;
+ virtual void DestroyDetailedView() OVERRIDE;
+ virtual void UpdateAfterLoginStatusChange(user::LoginStatus status) OVERRIDE;
+
+ // Overridden from DriveObserver.
+ virtual void OnDriveRefresh(const DriveOperationStatusList& list) OVERRIDE;
+
+ // Delayed re-check of the status after encounter operation depleted list.
+ void OnStatusCheck();
+
+ void UpdateTrayIcon(bool show);
+
+ tray::DriveDefaultView* default_;
+ tray::DriveDetailedView* detailed_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrayDrive);
+};
+
+} // namespace internal
+} // namespace ash
+
+#endif // ASH_SYSTEM_DRIVE_TRAY_DRIVE_H_
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 5db8c25..c7f66e9 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -11,6 +11,7 @@
#include "ash/system/bluetooth/tray_bluetooth.h"
#include "ash/system/brightness/tray_brightness.h"
#include "ash/system/date/tray_date.h"
+#include "ash/system/drive/tray_drive.h"
#include "ash/system/ime/tray_ime.h"
#include "ash/system/network/tray_network.h"
#include "ash/system/power/power_status_observer.h"
@@ -136,6 +137,10 @@ class TrayPopupItemContainer : public views::View {
PreferredSizeChanged();
}
+ virtual void ChildPreferredSizeChanged(View* child) OVERRIDE {
+ PreferredSizeChanged();
+ }
+
virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE {
hover_ = true;
SchedulePaint();
@@ -605,37 +610,6 @@ void SystemTrayBubble::OnWidgetVisibilityChanged(views::Widget* widget,
} // namespace internal
-// From system_tray_delegate.h
-
-NetworkIconInfo::NetworkIconInfo()
- : highlight(false),
- tray_icon_visible(true) {
-}
-
-NetworkIconInfo::~NetworkIconInfo() {
-}
-
-BluetoothDeviceInfo::BluetoothDeviceInfo()
- : connected(false) {
-}
-
-BluetoothDeviceInfo::~BluetoothDeviceInfo() {
-}
-
-IMEInfo::IMEInfo()
- : selected(false) {
-}
-
-IMEInfo::~IMEInfo() {
-}
-
-IMEPropertyInfo::IMEPropertyInfo()
- : selected(false) {
-}
-
-IMEPropertyInfo::~IMEPropertyInfo() {
-}
-
// SystemTray
SystemTray::SystemTray()
@@ -646,6 +620,7 @@ SystemTray::SystemTray()
brightness_observer_(NULL),
caps_lock_observer_(NULL),
clock_observer_(NULL),
+ drive_observer_(NULL),
ime_observer_(NULL),
network_observer_(NULL),
power_status_observer_(NULL),
@@ -696,6 +671,7 @@ void SystemTray::CreateItems() {
internal::TrayAccessibility* tray_accessibility =
new internal::TrayAccessibility;
internal::TrayCapsLock* tray_caps_lock = new internal::TrayCapsLock;
+ internal::TrayDrive* tray_drive = new internal::TrayDrive;
internal::TrayIME* tray_ime = new internal::TrayIME;
internal::TrayUpdate* tray_update = new internal::TrayUpdate;
@@ -705,6 +681,7 @@ void SystemTray::CreateItems() {
brightness_observer_ = tray_brightness;
caps_lock_observer_ = tray_caps_lock;
clock_observer_ = tray_date;
+ drive_observer_ = tray_drive;
ime_observer_ = tray_ime;
network_observer_ = tray_network;
power_status_observer_ = tray_power;
@@ -716,6 +693,7 @@ void SystemTray::CreateItems() {
AddTrayItem(tray_power);
AddTrayItem(tray_network);
AddTrayItem(tray_bluetooth);
+ AddTrayItem(tray_drive);
AddTrayItem(tray_ime);
AddTrayItem(tray_volume);
AddTrayItem(tray_brightness);
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h
index 4ea3e63..f608e70 100644
--- a/ash/system/tray/system_tray.h
+++ b/ash/system/tray/system_tray.h
@@ -26,6 +26,7 @@ class BluetoothObserver;
class BrightnessObserver;
class CapsLockObserver;
class ClockObserver;
+class DriveObserver;
class IMEObserver;
class NetworkObserver;
class PowerStatusObserver;
@@ -105,6 +106,9 @@ class ASH_EXPORT SystemTray : NON_EXPORTED_BASE(
ClockObserver* clock_observer() const {
return clock_observer_;
}
+ DriveObserver* drive_observer() const {
+ return drive_observer_;
+ }
IMEObserver* ime_observer() const {
return ime_observer_;
}
@@ -160,6 +164,7 @@ class ASH_EXPORT SystemTray : NON_EXPORTED_BASE(
BrightnessObserver* brightness_observer_;
CapsLockObserver* caps_lock_observer_;
ClockObserver* clock_observer_;
+ DriveObserver* drive_observer_;
IMEObserver* ime_observer_;
NetworkObserver* network_observer_;
PowerStatusObserver* power_status_observer_;
diff --git a/ash/system/tray/system_tray_delegate.cc b/ash/system/tray/system_tray_delegate.cc
new file mode 100644
index 0000000..e3d9798
--- /dev/null
+++ b/ash/system/tray/system_tray_delegate.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/tray/system_tray_delegate.h"
+
+namespace ash {
+
+NetworkIconInfo::NetworkIconInfo()
+ : highlight(false),
+ tray_icon_visible(true) {
+}
+
+NetworkIconInfo::~NetworkIconInfo() {
+}
+
+BluetoothDeviceInfo::BluetoothDeviceInfo()
+ : connected(false) {
+}
+
+BluetoothDeviceInfo::~BluetoothDeviceInfo() {
+}
+
+DriveOperationStatus::DriveOperationStatus()
+ : progress(0.0), type(OPERATION_OTHER), state(OPERATION_NOT_STARTED) {
+}
+
+DriveOperationStatus::~DriveOperationStatus() {
+}
+
+IMEInfo::IMEInfo()
+ : selected(false) {
+}
+
+IMEInfo::~IMEInfo() {
+}
+
+IMEPropertyInfo::IMEPropertyInfo()
+ : selected(false) {
+}
+
+IMEPropertyInfo::~IMEPropertyInfo() {
+}
+
+} // namespace ash
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h
index d75bea8..ee23fdd 100644
--- a/ash/system/tray/system_tray_delegate.h
+++ b/ash/system/tray/system_tray_delegate.h
@@ -12,6 +12,7 @@
#include "ash/ash_export.h"
#include "ash/system/user/login_status.h"
#include "ash/system/power/power_supply_status.h"
+#include "base/file_path.h"
#include "base/i18n/time_formatting.h"
#include "base/string16.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -43,6 +44,37 @@ struct ASH_EXPORT BluetoothDeviceInfo {
typedef std::vector<BluetoothDeviceInfo> BluetoothDeviceList;
+// Structure that packs progress information of each operation.
+struct ASH_EXPORT DriveOperationStatus {
+ enum OperationType {
+ OPERATION_UPLOAD,
+ OPERATION_DOWNLOAD,
+ OPERATION_OTHER,
+ };
+
+ enum OperationState {
+ OPERATION_NOT_STARTED,
+ OPERATION_STARTED,
+ OPERATION_IN_PROGRESS,
+ OPERATION_COMPLETED,
+ OPERATION_FAILED,
+ OPERATION_SUSPENDED,
+ };
+
+ DriveOperationStatus();
+ ~DriveOperationStatus();
+
+ // File path.
+ FilePath file_path;
+ // Current operation completion progress [0.0 - 1.0].
+ double progress;
+ OperationType type;
+ OperationState state;
+};
+
+typedef std::vector<DriveOperationStatus> DriveOperationStatusList;
+
+
struct ASH_EXPORT IMEPropertyInfo {
IMEPropertyInfo();
~IMEPropertyInfo();
@@ -106,6 +138,9 @@ class SystemTrayDelegate {
// Shows the settings related to bluetooth.
virtual void ShowBluetoothSettings() = 0;
+ // Shows settings related to Google Drive.
+ virtual void ShowDriveSettings() = 0;
+
// Shows settings related to input methods.
virtual void ShowIMESettings() = 0;
@@ -166,6 +201,13 @@ class SystemTrayDelegate {
// Activates an IME property.
virtual void ActivateIMEProperty(const std::string& key) = 0;
+ // Cancels ongoing drive operation.
+ virtual void CancelDriveOperation(const FilePath& file_path) = 0;
+
+ // Returns information about the ongoing drive operations.
+ virtual void GetDriveOperationStatusList(
+ DriveOperationStatusList* list) = 0;
+
// Returns information about the most relevant network. Relevance is
// determined by the implementor (e.g. a connecting network may be more
// relevant over a connected network etc.)
diff --git a/chrome/browser/chromeos/gdata/gdata_operation_registry.cc b/chrome/browser/chromeos/gdata/gdata_operation_registry.cc
index 76bef3c..b99a78e 100644
--- a/chrome/browser/chromeos/gdata/gdata_operation_registry.cc
+++ b/chrome/browser/chromeos/gdata/gdata_operation_registry.cc
@@ -272,11 +272,11 @@ bool GDataOperationRegistry::IsFileTransferOperation(
return type == OPERATION_UPLOAD || type == OPERATION_DOWNLOAD;
}
-std::vector<GDataOperationRegistry::ProgressStatus>
+GDataOperationRegistry::ProgressStatusList
GDataOperationRegistry::GetProgressStatusList() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- std::vector<ProgressStatus> status_list;
+ ProgressStatusList status_list;
for (OperationIDMap::const_iterator iter(&in_flight_operations_);
!iter.IsAtEnd();
iter.Advance()) {
diff --git a/chrome/browser/chromeos/gdata/gdata_operation_registry.h b/chrome/browser/chromeos/gdata/gdata_operation_registry.h
index 1499eed..95dc2a3 100644
--- a/chrome/browser/chromeos/gdata/gdata_operation_registry.h
+++ b/chrome/browser/chromeos/gdata/gdata_operation_registry.h
@@ -69,12 +69,13 @@ class GDataOperationRegistry {
// -1 if no expectation is available (yet).
int64 progress_total;
};
+ typedef std::vector<ProgressStatus> ProgressStatusList;
// Observer interface for listening changes in the active set of operations.
class Observer {
public:
// Called when a GData operation started, made some progress, or finished.
- virtual void OnProgressUpdate(const std::vector<ProgressStatus>& list) = 0;
+ virtual void OnProgressUpdate(const ProgressStatusList& list) = 0;
protected:
virtual ~Observer() {}
};
@@ -128,7 +129,7 @@ class GDataOperationRegistry {
bool CancelForFilePath(const FilePath& file_path);
// Obtains the list of currently active operations.
- std::vector<ProgressStatus> GetProgressStatusList();
+ ProgressStatusList GetProgressStatusList();
// Sets the observer.
void AddObserver(Observer* observer);
diff --git a/chrome/browser/chromeos/gdata/gdata_util.cc b/chrome/browser/chromeos/gdata/gdata_util.cc
index dec6c04..ff7916e 100644
--- a/chrome/browser/chromeos/gdata/gdata_util.cc
+++ b/chrome/browser/chromeos/gdata/gdata_util.cc
@@ -24,6 +24,8 @@
#include "chrome/common/url_constants.h"
#include "chrome/browser/chromeos/gdata/gdata_file_system.h"
#include "chrome/browser/chromeos/gdata/gdata_system_service.h"
+#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
@@ -236,6 +238,11 @@ void InsertGDataCachePathsPermissions(
}
bool IsGDataAvailable(Profile* profile) {
+ if (!chromeos::UserManager::Get()->IsUserLoggedIn() ||
+ chromeos::UserManager::Get()->IsLoggedInAsGuest() ||
+ chromeos::UserManager::Get()->IsLoggedInAsDemoUser())
+ return false;
+
// Do not allow GData for incognito windows / guest mode.
if (profile->IsOffTheRecord())
return false;
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index ab6b54b..37fbac6 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -10,6 +10,7 @@
#include "ash/system/bluetooth/bluetooth_observer.h"
#include "ash/system/brightness/brightness_observer.h"
#include "ash/system/date/clock_observer.h"
+#include "ash/system/drive/drive_observer.h"
#include "ash/system/ime/ime_observer.h"
#include "ash/system/network/network_observer.h"
#include "ash/system/power/power_status_observer.h"
@@ -21,6 +22,7 @@
#include "ash/system/user/user_observer.h"
#include "base/chromeos/chromeos_version.h"
#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/audio/audio_handler.h"
@@ -28,6 +30,8 @@
#include "chrome/browser/chromeos/bluetooth/bluetooth_device.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
+#include "chrome/browser/chromeos/gdata/gdata_system_service.h"
+#include "chrome/browser/chromeos/gdata/gdata_util.h"
#include "chrome/browser/chromeos/input_method/input_method_manager.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/chromeos/input_method/input_method_whitelist.h"
@@ -54,16 +58,26 @@
#include "chrome/common/url_constants.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_manager_client.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/user_metrics.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
+using gdata::GDataFileSystem;
+using gdata::GDataOperationRegistry;
+using gdata::GDataSystemService;
+using gdata::GDataSystemServiceFactory;
+
namespace chromeos {
namespace {
+// Time delay for rechecking gdata operation when we suspect that there will
+// be no upcoming activity notifications that need to be pushed to UI.
+const int kGDataOperationRecheckDelayMs = 5000;
+
bool ShouldShowNetworkIconInTray(const Network* network) {
if (!network)
return true;
@@ -90,6 +104,25 @@ void ExtractIMEInfo(const input_method::InputMethodDescriptor& ime,
info->short_name = util.GetInputMethodShortName(ime);
}
+ash::DriveOperationStatusList GetDriveStatusList(
+ const std::vector<GDataOperationRegistry::ProgressStatus>& list) {
+ ash::DriveOperationStatusList results;
+ for (GDataOperationRegistry::ProgressStatusList::const_iterator it =
+ list.begin();
+ it != list.end(); ++it) {
+ ash::DriveOperationStatus status;
+ status.file_path = it->file_path;
+ status.progress = it->progress_total == 0 ? 0.0 :
+ static_cast<double>(it->progress_current) /
+ static_cast<double>(it->progress_total);
+ status.type = static_cast<ash::DriveOperationStatus::OperationType>(
+ it->operation_type);
+ status.state = static_cast<ash::DriveOperationStatus::OperationState>(
+ it->transfer_state);
+ results.push_back(status);
+ }
+ return results;
+}
void BluetoothPowerFailure() {
// TODO(sad): Show an error bubble?
@@ -115,6 +148,7 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
public NetworkLibrary::NetworkManagerObserver,
public NetworkLibrary::NetworkObserver,
public NetworkLibrary::CellularDataPlanObserver,
+ public gdata::GDataOperationRegistry::Observer,
public content::NotificationObserver,
public input_method::InputMethodManager::Observer,
public system::TimezoneSettings::Observer,
@@ -124,6 +158,8 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
public:
explicit SystemTrayDelegate(ash::SystemTray* tray)
: tray_(tray),
+ ui_weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(
+ new base::WeakPtrFactory<SystemTrayDelegate>(this))),
network_icon_(ALLOW_THIS_IN_INITIALIZER_LIST(
new NetworkMenuIcon(this, NetworkMenuIcon::MENU_MODE))),
network_icon_dark_(ALLOW_THIS_IN_INITIALIZER_LIST(
@@ -270,6 +306,10 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
// TODO(sad): Make this work.
}
+ virtual void ShowDriveSettings() OVERRIDE {
+ // TODO(zelidrag): Show settings once we put them in.
+ }
+
virtual void ShowIMESettings() OVERRIDE {
content::RecordAction(
content::UserMetricsAction("OpenLanguageOptionsDialog"));
@@ -404,6 +444,37 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
ActivateInputMethodProperty(key);
}
+ virtual void CancelDriveOperation(const FilePath& file_path) OVERRIDE {
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ if (!gdata::util::IsGDataAvailable(profile))
+ return;
+
+ GDataSystemService* system_service =
+ GDataSystemServiceFactory::FindForProfile(profile);
+ if (!system_service)
+ return;
+
+ system_service->file_system()->GetOperationRegistry()->CancelForFilePath(
+ file_path);
+ }
+
+ virtual void GetDriveOperationStatusList(
+ ash::DriveOperationStatusList* list) OVERRIDE {
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ if (!gdata::util::IsGDataAvailable(profile))
+ return;
+
+ GDataSystemService* system_service =
+ GDataSystemServiceFactory::FindForProfile(profile);
+ if (!system_service)
+ return;
+
+ *list = GetDriveStatusList(
+ system_service->file_system()->GetOperationRegistry()->
+ GetProgressStatusList());
+ }
+
+
virtual void GetMostRelevantNetworkIcon(ash::NetworkIconInfo* info,
bool dark) OVERRIDE {
NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary();
@@ -655,6 +726,13 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
UpdateClockType(profile->GetPrefs());
search_key_mapped_to_ =
profile->GetPrefs()->GetInteger(prefs::kLanguageXkbRemapSearchKeyTo);
+
+ if (gdata::util::IsGDataAvailable(profile)) {
+ GDataSystemService* system_service =
+ GDataSystemServiceFactory::FindForProfile(profile);
+ system_service->file_system()->GetOperationRegistry()->
+ AddObserver(this);
+ }
}
void UpdateClockType(PrefService* service) {
@@ -695,6 +773,12 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
observer->OnIMERefresh();
}
+ void NotifyRefreshDrive(ash::DriveOperationStatusList& list) {
+ ash::DriveObserver* observer = tray_->drive_observer();
+ if (observer)
+ observer->OnDriveRefresh(list);
+ }
+
void RefreshNetworkObserver(NetworkLibrary* crosnet) {
const Network* network = crosnet->active_network();
std::string new_path = network ? network->service_path() : std::string();
@@ -872,6 +956,61 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
NotifyRefreshIME();
}
+ // gdata::GDataOperationRegistry::Observer overrides.
+ virtual void OnProgressUpdate(
+ const GDataOperationRegistry::ProgressStatusList& list) {
+ std::vector<ash::DriveOperationStatus> ui_list = GetDriveStatusList(list);
+ NotifyRefreshDrive(ui_list);
+
+ // If we have something to report right now (i.e. completion status only),
+ // we need to delayed re-check the status in few seconds to ensure we
+ // raise events that will let us properly clear the uber tray state.
+ if (list.size() > 0) {
+ bool has_in_progress_items = false;
+ for (GDataOperationRegistry::ProgressStatusList::const_iterator it =
+ list.begin();
+ it != list.end(); ++it) {
+ if (it->transfer_state ==
+ GDataOperationRegistry::OPERATION_STARTED ||
+ it->transfer_state ==
+ GDataOperationRegistry::OPERATION_IN_PROGRESS ||
+ it->transfer_state ==
+ GDataOperationRegistry::OPERATION_SUSPENDED) {
+ has_in_progress_items = true;
+ break;
+ }
+ }
+
+ if (!has_in_progress_items) {
+ content::BrowserThread::PostDelayedTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&SystemTrayDelegate::RecheckGDataOperations,
+ ui_weak_ptr_factory_->GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kGDataOperationRecheckDelayMs));
+ }
+ }
+
+ }
+
+ // Pulls the list of ongoing drive operations and initiates status update.
+ // This method is needed to ensure delayed cleanup of the latest reported
+ // status in UI in cases when there are no new changes coming (i.e. when the
+ // last set of transfer operations completed).
+ void RecheckGDataOperations() {
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ if (!gdata::util::IsGDataAvailable(profile))
+ return;
+
+ GDataSystemService* system_service =
+ GDataSystemServiceFactory::FindForProfile(profile);
+ if (!system_service)
+ return;
+
+ OnProgressUpdate(system_service->file_system()->GetOperationRegistry()->
+ GetProgressStatusList());
+ }
+
// Overridden from system::TimezoneSettings::Observer.
virtual void TimezoneChanged(const icu::TimeZone& timezone) OVERRIDE {
NotifyRefreshClock();
@@ -957,6 +1096,7 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
}
ash::SystemTray* tray_;
+ scoped_ptr<base::WeakPtrFactory<SystemTrayDelegate> > ui_weak_ptr_factory_;
scoped_ptr<NetworkMenuIcon> network_icon_;
scoped_ptr<NetworkMenuIcon> network_icon_dark_;
scoped_ptr<NetworkMenu> network_menu_;
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index 7a20703..d5871228 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -293,6 +293,12 @@
<include name="IDR_AURA_UBER_TRAY_CAPS_LOCK" file="aura/status_capslock.png" type="BINDATA" />
<include name="IDR_AURA_UBER_TRAY_CAPS_LOCK_DARK" file="aura/status_capslock_dark.png" type="BINDATA" />
<include name="IDR_AURA_UBER_TRAY_BLUETOOTH" file="aura/status_bluetooth.png" type="BINDATA" />
+ <include name="IDR_AURA_UBER_TRAY_DRIVE" file="aura/status_drive.png" type="BINDATA" />
+ <include name="IDR_AURA_UBER_TRAY_DRIVE_FAILED" file="aura/status_drive_item_failed.png" type="BINDATA" />
+ <include name="IDR_AURA_UBER_TRAY_DRIVE_DONE" file="aura/status_drive_item_done.png" type="BINDATA" />
+ <include name="IDR_AURA_UBER_TRAY_DRIVE_CANCEL" file="aura/status_drive_item_cancel.png" type="BINDATA" />
+ <include name="IDR_AURA_UBER_TRAY_DRIVE_CANCEL_HOVER" file="aura/status_drive_item_cancel_hover.png" type="BINDATA" />
+ <include name="IDR_AURA_UBER_TRAY_DRIVE_LIGHT" file="aura/status_drive_light.png" type="BINDATA" />
<include name="IDR_AURA_UBER_TRAY_IME" file="aura/status_ime.png" type="BINDATA" />
<include name="IDR_AURA_UBER_TRAY_UPDATE" file="aura/status_update.png" type="BINDATA" />
<include name="IDR_AURA_UBER_TRAY_UPDATE_DARK" file="aura/status_update_dark.png" type="BINDATA" />