blob: 7c0621498b44ee8703b638f26dd7560dbb00e2d1 [file] [log] [blame]
// 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