| // 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 "chrome/browser/extensions/api/alarms/alarms_api.h" |
| |
| #include "base/strings/string_number_conversions.h" |
| #include "base/time/clock.h" |
| #include "base/time/default_clock.h" |
| #include "base/values.h" |
| #include "chrome/browser/extensions/api/alarms/alarm_manager.h" |
| #include "chrome/common/extensions/api/alarms.h" |
| #include "extensions/common/error_utils.h" |
| |
| namespace alarms = extensions::api::alarms; |
| |
| namespace extensions { |
| |
| namespace { |
| |
| const char kDefaultAlarmName[] = ""; |
| const char kAlarmNotFound[] = "No alarm named '*' exists."; |
| const char kBothRelativeAndAbsoluteTime[] = |
| "Cannot set both when and delayInMinutes."; |
| const char kNoScheduledTime[] = |
| "Must set at least one of when, delayInMinutes, or periodInMinutes."; |
| const int kReleaseDelayMinimum = 1; |
| const int kDevDelayMinimum = 0; |
| |
| bool ValidateAlarmCreateInfo(const std::string& alarm_name, |
| const alarms::AlarmCreateInfo& create_info, |
| const Extension* extension, |
| std::string* error, |
| std::vector<std::string>* warnings) { |
| if (create_info.delay_in_minutes.get() && |
| create_info.when.get()) { |
| *error = kBothRelativeAndAbsoluteTime; |
| return false; |
| } |
| if (create_info.delay_in_minutes == NULL && |
| create_info.when == NULL && |
| create_info.period_in_minutes == NULL) { |
| *error = kNoScheduledTime; |
| return false; |
| } |
| |
| // Users can always use an absolute timeout to request an arbitrarily-short or |
| // negative delay. We won't honor the short timeout, but we can't check it |
| // and warn the user because it would introduce race conditions (say they |
| // compute a long-enough timeout, but then the call into the alarms interface |
| // gets delayed past the boundary). However, it's still worth warning about |
| // relative delays that are shorter than we'll honor. |
| if (create_info.delay_in_minutes.get()) { |
| if (*create_info.delay_in_minutes < kReleaseDelayMinimum) { |
| COMPILE_ASSERT(kReleaseDelayMinimum == 1, update_warning_message_below); |
| if (Manifest::IsUnpackedLocation(extension->location())) |
| warnings->push_back(ErrorUtils::FormatErrorMessage( |
| "Alarm delay is less than minimum of 1 minutes." |
| " In released .crx, alarm \"*\" will fire in approximately" |
| " 1 minutes.", |
| alarm_name)); |
| else |
| warnings->push_back(ErrorUtils::FormatErrorMessage( |
| "Alarm delay is less than minimum of 1 minutes." |
| " Alarm \"*\" will fire in approximately 1 minutes.", |
| alarm_name)); |
| } |
| } |
| if (create_info.period_in_minutes.get()) { |
| if (*create_info.period_in_minutes < kReleaseDelayMinimum) { |
| COMPILE_ASSERT(kReleaseDelayMinimum == 1, update_warning_message_below); |
| if (Manifest::IsUnpackedLocation(extension->location())) |
| warnings->push_back(ErrorUtils::FormatErrorMessage( |
| "Alarm period is less than minimum of 1 minutes." |
| " In released .crx, alarm \"*\" will fire approximately" |
| " every 1 minutes.", |
| alarm_name)); |
| else |
| warnings->push_back(ErrorUtils::FormatErrorMessage( |
| "Alarm period is less than minimum of 1 minutes." |
| " Alarm \"*\" will fire approximately every 1 minutes.", |
| alarm_name)); |
| } |
| } |
| |
| return true; |
| } |
| |
| } // namespace |
| |
| AlarmsCreateFunction::AlarmsCreateFunction() |
| : clock_(new base::DefaultClock()), owns_clock_(true) {} |
| |
| AlarmsCreateFunction::AlarmsCreateFunction(base::Clock* clock) |
| : clock_(clock), owns_clock_(false) {} |
| |
| AlarmsCreateFunction::~AlarmsCreateFunction() { |
| if (owns_clock_) |
| delete clock_; |
| } |
| |
| bool AlarmsCreateFunction::RunImpl() { |
| scoped_ptr<alarms::Create::Params> params( |
| alarms::Create::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| const std::string& alarm_name = |
| params->name.get() ? *params->name : kDefaultAlarmName; |
| std::vector<std::string> warnings; |
| if (!ValidateAlarmCreateInfo( |
| alarm_name, params->alarm_info, GetExtension(), &error_, &warnings)) { |
| return false; |
| } |
| for (std::vector<std::string>::const_iterator it = warnings.begin(); |
| it != warnings.end(); ++it) |
| WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING, *it); |
| |
| Alarm alarm(alarm_name, |
| params->alarm_info, |
| base::TimeDelta::FromMinutes( |
| Manifest::IsUnpackedLocation(GetExtension()->location()) ? |
| kDevDelayMinimum : kReleaseDelayMinimum), |
| clock_->Now()); |
| AlarmManager::Get(GetProfile())->AddAlarm( |
| extension_id(), alarm, base::Bind(&AlarmsCreateFunction::Callback, this)); |
| |
| return true; |
| } |
| |
| void AlarmsCreateFunction::Callback() { |
| SendResponse(true); |
| } |
| |
| bool AlarmsGetFunction::RunImpl() { |
| scoped_ptr<alarms::Get::Params> params(alarms::Get::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| |
| std::string name = params->name.get() ? *params->name : kDefaultAlarmName; |
| AlarmManager::Get(GetProfile()) |
| ->GetAlarm(extension_id(), |
| name, |
| base::Bind(&AlarmsGetFunction::Callback, this, name)); |
| |
| return true; |
| } |
| |
| void AlarmsGetFunction::Callback( |
| const std::string& name, extensions::Alarm* alarm) { |
| if (alarm) { |
| results_ = alarms::Get::Results::Create(*alarm->js_alarm); |
| SendResponse(true); |
| } else { |
| error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name); |
| SendResponse(false); |
| } |
| } |
| |
| bool AlarmsGetAllFunction::RunImpl() { |
| AlarmManager::Get(GetProfile())->GetAllAlarms( |
| extension_id(), base::Bind(&AlarmsGetAllFunction::Callback, this)); |
| return true; |
| } |
| |
| void AlarmsGetAllFunction::Callback(const AlarmList* alarms) { |
| if (alarms) { |
| std::vector<linked_ptr<extensions::api::alarms::Alarm> > create_arg; |
| create_arg.reserve(alarms->size()); |
| for (size_t i = 0, size = alarms->size(); i < size; ++i) { |
| create_arg.push_back((*alarms)[i].js_alarm); |
| } |
| results_ = alarms::GetAll::Results::Create(create_arg); |
| } else { |
| SetResult(new base::ListValue()); |
| } |
| SendResponse(true); |
| } |
| |
| bool AlarmsClearFunction::RunImpl() { |
| scoped_ptr<alarms::Clear::Params> params( |
| alarms::Clear::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| |
| std::string name = params->name.get() ? *params->name : kDefaultAlarmName; |
| AlarmManager::Get(GetProfile()) |
| ->RemoveAlarm(extension_id(), |
| name, |
| base::Bind(&AlarmsClearFunction::Callback, this, name)); |
| |
| return true; |
| } |
| |
| void AlarmsClearFunction::Callback(const std::string& name, bool success) { |
| if (!success) |
| error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name); |
| |
| SendResponse(success); |
| } |
| |
| bool AlarmsClearAllFunction::RunImpl() { |
| AlarmManager::Get(GetProfile())->RemoveAllAlarms( |
| extension_id(), base::Bind(&AlarmsClearAllFunction::Callback, this)); |
| return true; |
| } |
| |
| void AlarmsClearAllFunction::Callback() { |
| SendResponse(true); |
| } |
| |
| } // namespace extensions |