diff options
-rw-r--r-- | ash/ash.gyp | 4 | ||||
-rw-r--r-- | ash/ash_strings.grd | 9 | ||||
-rw-r--r-- | ash/shell.cc | 10 | ||||
-rw-r--r-- | ash/system/drive/drive_observer.h | 23 | ||||
-rw-r--r-- | ash/system/drive/tray_drive.cc | 450 | ||||
-rw-r--r-- | ash/system/drive/tray_drive.h | 62 | ||||
-rw-r--r-- | ash/system/tray/system_tray.cc | 40 | ||||
-rw-r--r-- | ash/system/tray/system_tray.h | 5 | ||||
-rw-r--r-- | ash/system/tray/system_tray_delegate.cc | 45 | ||||
-rw-r--r-- | ash/system/tray/system_tray_delegate.h | 42 | ||||
-rw-r--r-- | chrome/browser/chromeos/gdata/gdata_operation_registry.cc | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/gdata/gdata_operation_registry.h | 5 | ||||
-rw-r--r-- | chrome/browser/chromeos/gdata/gdata_util.cc | 7 | ||||
-rw-r--r-- | chrome/browser/chromeos/system/ash_system_tray_delegate.cc | 140 | ||||
-rw-r--r-- | ui/resources/ui_resources.grd | 6 |
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" /> |