Commit 630d8080 authored by jianli@chromium.org's avatar jianli@chromium.org

Support creating progress bar notification for Windows

This is the 1st patch to add progress bar notification support. It contains:
1) A new progress type is added and a new optional progress value is added.
2) NotificationView creates and adds a NotificationProgressbar child view.

BUG=170924
TEST=manual test by creating a progress bar notification

Review URL: https://chromiumcodereview.appspot.com/18662006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@213287 0039d316-1c4b-4281-b951-d872f2087c98
parent 76b74015
......@@ -34,6 +34,10 @@ namespace extensions {
namespace {
const char kResultKey[] = "result";
const char kUnexpectedProgressValueForNonProgressType[] =
"The progress value should not be specified for non-progress notification";
const char kInvalidProgressValue[] =
"The progress value should range from 0 to 100";
// Converts an object with width, height, and data in RGBA format into an
// gfx::Image (in ARGB format).
......@@ -276,6 +280,20 @@ bool NotificationsApiFunction::CreateNotification(
if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE))
return false;
if (options->progress.get() != NULL) {
// We should have progress if and only if the type is a progress type.
if (type != message_center::NOTIFICATION_TYPE_PROGRESS) {
SetError(kUnexpectedProgressValueForNonProgressType);
return false;
}
optional_fields.progress = *options->progress;
// Progress value should range from 0 to 100.
if (optional_fields.progress < 0 || optional_fields.progress > 100) {
SetError(kInvalidProgressValue);
return false;
}
}
if (has_list_items) {
using api::notifications::NotificationItem;
std::vector<linked_ptr<NotificationItem> >::iterator i;
......@@ -333,6 +351,8 @@ NotificationsApiFunction::MapApiTemplateTypeToType(
return message_center::NOTIFICATION_TYPE_IMAGE;
case api::notifications::TEMPLATE_TYPE_LIST:
return message_center::NOTIFICATION_TYPE_MULTIPLE;
case api::notifications::TEMPLATE_TYPE_PROGRESS:
return message_center::NOTIFICATION_TYPE_PROGRESS;
default:
// Gracefully handle newer application code that is running on an older
// runtime that doesn't recognize the requested template.
......
......@@ -388,3 +388,117 @@ IN_PROC_BROWSER_TEST_F(NotificationsApiTest, MAYBE_TestByUser) {
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
}
#if defined(OS_LINUX)
#define MAYBE_TestProgressNotification DISABLED_TestProgressNotification
#else
#define MAYBE_TestProgressNotification TestProgressNotification
#endif
IN_PROC_BROWSER_TEST_F(NotificationsApiTest, MAYBE_TestProgressNotification) {
scoped_refptr<Extension> empty_extension(utils::CreateEmptyExtension());
{
scoped_refptr<extensions::NotificationsCreateFunction>
notification_create_function(
new extensions::NotificationsCreateFunction());
notification_create_function->set_extension(empty_extension.get());
notification_create_function->set_has_callback(true);
scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
notification_create_function.get(),
"[\"\", "
"{"
"\"type\": \"progress\","
"\"iconUrl\": \"an/image/that/does/not/exist.png\","
"\"title\": \"Test!\","
"\"message\": \"This is a progress notification.\","
"\"priority\": 1,"
"\"eventTime\": 1234567890.12345678,"
"\"progress\": 30"
"}]",
browser(),
utils::NONE));
std::string notification_id;
EXPECT_EQ(base::Value::TYPE_STRING, result->GetType());
EXPECT_TRUE(result->GetAsString(&notification_id));
EXPECT_TRUE(notification_id.length() > 0);
}
// Error case: progress value provided for non-progress type.
{
scoped_refptr<extensions::NotificationsCreateFunction>
notification_create_function(
new extensions::NotificationsCreateFunction());
notification_create_function->set_extension(empty_extension.get());
notification_create_function->set_has_callback(true);
utils::RunFunction(
notification_create_function.get(),
"[\"\", "
"{"
"\"type\": \"basic\","
"\"iconUrl\": \"an/image/that/does/not/exist.png\","
"\"title\": \"Test!\","
"\"message\": \"This is a progress notification.\","
"\"priority\": 1,"
"\"eventTime\": 1234567890.12345678,"
"\"progress\": 10"
"}]",
browser(),
utils::NONE);
EXPECT_FALSE(notification_create_function->GetError().empty());
}
// Error case: progress value less than lower bound.
{
scoped_refptr<extensions::NotificationsCreateFunction>
notification_create_function(
new extensions::NotificationsCreateFunction());
notification_create_function->set_extension(empty_extension.get());
notification_create_function->set_has_callback(true);
utils::RunFunction(
notification_create_function.get(),
"[\"\", "
"{"
"\"type\": \"progress\","
"\"iconUrl\": \"an/image/that/does/not/exist.png\","
"\"title\": \"Test!\","
"\"message\": \"This is a progress notification.\","
"\"priority\": 1,"
"\"eventTime\": 1234567890.12345678,"
"\"progress\": -10"
"}]",
browser(),
utils::NONE);
EXPECT_FALSE(notification_create_function->GetError().empty());
}
// Error case: progress value greater than upper bound.
{
scoped_refptr<extensions::NotificationsCreateFunction>
notification_create_function(
new extensions::NotificationsCreateFunction());
notification_create_function->set_extension(empty_extension.get());
notification_create_function->set_has_callback(true);
utils::RunFunction(
notification_create_function.get(),
"[\"\", "
"{"
"\"type\": \"progress\","
"\"iconUrl\": \"an/image/that/does/not/exist.png\","
"\"title\": \"Test!\","
"\"message\": \"This is a progress notification.\","
"\"priority\": 1,"
"\"eventTime\": 1234567890.12345678,"
"\"progress\": 101"
"}]",
browser(),
utils::NONE);
EXPECT_FALSE(notification_create_function->GetError().empty());
}
}
......@@ -13,7 +13,10 @@ namespace notifications {
image,
// icon, title, message, items, up to two buttons
list
list,
// icon, title, message, progress, up to two buttons
progress
};
dictionary NotificationItem {
......@@ -70,6 +73,9 @@ namespace notifications {
// Items for multi-item notifications.
NotificationItem[]? items;
// Current progress ranges from 0 to 100.
long? progress;
};
callback CreateCallback = void (DOMString notificationId);
......
......@@ -26,7 +26,8 @@ ButtonInfo::ButtonInfo(const string16& title)
RichNotificationData::RichNotificationData()
: priority(DEFAULT_PRIORITY),
never_timeout(false),
timestamp(base::Time::Now()) {}
timestamp(base::Time::Now()),
progress(0) {}
RichNotificationData::RichNotificationData(const RichNotificationData& other)
: priority(other.priority),
......@@ -35,6 +36,7 @@ RichNotificationData::RichNotificationData(const RichNotificationData& other)
expanded_message(other.expanded_message),
image(other.image),
items(other.items),
progress(other.progress),
buttons(other.buttons) {}
RichNotificationData::~RichNotificationData() {}
......
......@@ -44,6 +44,7 @@ class MESSAGE_CENTER_EXPORT RichNotificationData {
string16 expanded_message;
gfx::Image image;
std::vector<NotificationItem> items;
int progress;
std::vector<ButtonInfo> buttons;
};
......@@ -88,6 +89,7 @@ class MESSAGE_CENTER_EXPORT Notification {
const std::vector<NotificationItem>& items() const {
return optional_fields_.items;
}
int progress() const { return optional_fields_.progress; }
// End unpacked values.
// Images fetched asynchronously.
......
......@@ -33,6 +33,7 @@ enum NotificationType {
NOTIFICATION_TYPE_BASE_FORMAT,
NOTIFICATION_TYPE_IMAGE,
NOTIFICATION_TYPE_MULTIPLE,
NOTIFICATION_TYPE_PROGRESS
};
enum NotificationPriority {
......
......@@ -24,6 +24,7 @@
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.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/fill_layout.h"
#include "ui/views/widget/widget.h"
......@@ -38,6 +39,11 @@ const int kTextLeftPadding = kIconSize + message_center::kIconToTextPadding;
const int kTextBottomPadding = 12;
const int kTextRightPadding = 23;
const int kItemTitleToMessagePadding = 3;
const int kProgressBarWidth = message_center::kNotificationWidth -
kTextLeftPadding - kTextRightPadding;
const int kProgressBarHeight = 8;
const int kProgressBarTopPadding = 12;
const int kProgressBarBottomPadding = 2;
const int kButtonVecticalPadding = 0;
const int kButtonTitleTopPadding = 0;
......@@ -74,6 +80,11 @@ views::Border* MakeTextBorder(int padding, int top, int bottom) {
(padding + 1) / 2 + bottom, kTextRightPadding);
}
// static
views::Border* MakeProgressBarBorder(int top, int bottom) {
return MakeEmptyBorder(top, kTextLeftPadding, bottom, kTextRightPadding);
}
// static
views::Border* MakeSeparatorBorder(int top, int left, SkColor color) {
return views::Border::CreateSolidSidedBorder(top, left, 0, 0, color);
......@@ -223,6 +234,33 @@ gfx::Size ProportionalImageView::GetImageSizeForWidth(int width) {
return message_center::GetImageSizeForWidth(width, size);
}
// NotificationProgressBar /////////////////////////////////////////////////////
class NotificationProgressBar : public views::ProgressBar {
public:
NotificationProgressBar();
virtual ~NotificationProgressBar();
private:
// Overriden from View
virtual gfx::Size GetPreferredSize() OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(NotificationProgressBar);
};
NotificationProgressBar::NotificationProgressBar() {
}
NotificationProgressBar::~NotificationProgressBar() {
}
gfx::Size NotificationProgressBar::GetPreferredSize() {
gfx::Size pref_size(kProgressBarWidth, kProgressBarHeight);
gfx::Insets insets = GetInsets();
pref_size.Enlarge(insets.width(), insets.height());
return pref_size;
}
// NotificationButton //////////////////////////////////////////////////////////
// NotificationButtons render the action buttons of notifications.
......@@ -345,6 +383,7 @@ MessageView* NotificationView::Create(const Notification& notification,
case NOTIFICATION_TYPE_IMAGE:
case NOTIFICATION_TYPE_MULTIPLE:
case NOTIFICATION_TYPE_SIMPLE:
case NOTIFICATION_TYPE_PROGRESS:
break;
default:
// If the caller asks for an unrecognized kind of view (entirely possible
......@@ -422,6 +461,16 @@ NotificationView::NotificationView(const Notification& notification,
accessible_lines.push_back(notification.message());
}
// Create the progress bar view.
progress_bar_view_ = NULL;
if (notification.type() == NOTIFICATION_TYPE_PROGRESS) {
progress_bar_view_ = new NotificationProgressBar();
progress_bar_view_->set_border(MakeProgressBarBorder(
kProgressBarTopPadding, kProgressBarBottomPadding));
progress_bar_view_->SetValue(notification.progress() / 100.0);
top_view_->AddChildView(progress_bar_view_);
}
// Create the list item views (up to a maximum).
int padding = kMessageLineHeight - views::Label().font().GetHeight();
std::vector<NotificationItem> items = notification.items();
......
......@@ -10,6 +10,10 @@
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/views/message_view.h"
namespace views {
class ProgressBar;
}
namespace message_center {
class BoundedLabel;
......@@ -71,6 +75,7 @@ class MESSAGE_CENTER_EXPORT NotificationView : public MessageView {
views::View* icon_view_;
views::View* bottom_view_;
views::View* image_view_;
views::ProgressBar* progress_bar_view_;
std::vector<views::View*> action_buttons_;
DISALLOW_COPY_AND_ASSIGN(NotificationView);
......
......@@ -183,7 +183,10 @@ void ProgressBar::GetAccessibleState(ui::AccessibleViewState* state) {
}
gfx::Size ProgressBar::GetPreferredSize() {
return gfx::Size(100, 11);
gfx::Size pref_size(100, 11);
gfx::Insets insets = GetInsets();
pref_size.Enlarge(insets.width(), insets.height());
return pref_size;
}
const char* ProgressBar::GetClassName() const {
......@@ -191,18 +194,24 @@ const char* ProgressBar::GetClassName() const {
}
void ProgressBar::OnPaint(gfx::Canvas* canvas) {
gfx::Rect content_bounds = GetContentsBounds();
int bar_left = content_bounds.x();
int bar_top = content_bounds.y();
int bar_width = content_bounds.width();
int bar_height = content_bounds.height();
const int progress_width =
static_cast<int>(width() * GetNormalizedValue() + 0.5);
static_cast<int>(bar_width * GetNormalizedValue() + 0.5);
// Draw background.
FillRoundRect(canvas,
0, 0, width(), height(),
bar_left, bar_top, bar_width, bar_height,
kCornerRadius,
kBackgroundColor, kBackgroundColor,
false);
StrokeRoundRect(canvas,
0, 0,
width(), height(),
bar_left, bar_top,
bar_width, bar_height,
kCornerRadius,
kBackgroundBorderColor,
kBorderWidth);
......@@ -214,7 +223,7 @@ void ProgressBar::OnPaint(gfx::Canvas* canvas) {
SkPath inner_path;
AddRoundRectPathWithPadding(
0, 0, progress_width, height(),
bar_left, bar_top, progress_width, bar_height,
kCornerRadius,
0,
&inner_path);
......@@ -228,7 +237,7 @@ void ProgressBar::OnPaint(gfx::Canvas* canvas) {
kBarColorEnd,
};
// We want a thin 1-pixel line for kBarTopColor.
SkScalar scalar_height = SkIntToScalar(height());
SkScalar scalar_height = SkIntToScalar(bar_height);
SkScalar highlight_width = SkScalarDiv(SK_Scalar1, scalar_height);
SkScalar border_width = SkScalarDiv(SkIntToScalar(kBorderWidth),
scalar_height);
......@@ -257,8 +266,8 @@ void ProgressBar::OnPaint(gfx::Canvas* canvas) {
// Do not start from (kBorderWidth, kBorderWidth) because it makes gaps
// between the inner and the border.
FillRoundRect(canvas,
0, 0,
progress_width, height(),
bar_left, bar_top,
progress_width, bar_height,
kCornerRadius,
enabled() ? bar_colors : disabled_bar_colors,
enabled() ? bar_points : disabled_bar_points,
......@@ -294,7 +303,7 @@ void ProgressBar::OnPaint(gfx::Canvas* canvas) {
paint.setShader(s.get());
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
canvas->DrawRect(gfx::Rect(highlight_left, 0,
kHighlightWidth + kBorderWidth, height()),
kHighlightWidth + kBorderWidth, bar_height),
paint);
}
......@@ -303,7 +312,7 @@ void ProgressBar::OnPaint(gfx::Canvas* canvas) {
// Draw bar stroke
StrokeRoundRect(canvas,
0, 0, progress_width, height(),
bar_left, bar_top, progress_width, bar_height,
kCornerRadius,
enabled() ? kBarBorderColor : kDisabledBarBorderColor,
kBorderWidth);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment