diff options
Diffstat (limited to 'chrome/browser/extensions/extension_idle_api.cc')
-rw-r--r-- | chrome/browser/extensions/extension_idle_api.cc | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/chrome/browser/extensions/extension_idle_api.cc b/chrome/browser/extensions/extension_idle_api.cc new file mode 100644 index 0000000..0a6a25f --- /dev/null +++ b/chrome/browser/extensions/extension_idle_api.cc @@ -0,0 +1,160 @@ +// Copyright (c) 2010 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. + +// This implementation supposes a single extension thread and synchronized +// method invokation. + +#include "chrome/browser/extensions/extension_idle_api.h" + +#include <string> + +#include "base/json/json_writer.h" +#include "base/message_loop.h" +#include "base/stl_util-inl.h" +#include "base/task.h" +#include "base/time.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/extensions/extension_host.h" +#include "chrome/browser/extensions/extension_idle_api_constants.h" +#include "chrome/browser/extensions/extension_message_service.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/notification_service.h" + +namespace keys = extension_idle_api_constants; + +namespace { + +const int kIdlePollInterval = 15; // Number of seconds between status checks + // when polling for active. +const int kMinThreshold = 15; // In seconds. Set >1 sec for security concerns. +const int kMaxThreshold = 60*60; // One hours, in seconds. Not set arbitrarily + // high for security concerns. + +struct ExtensionIdlePollingData { + IdleState state; + double timestamp; +}; + +// Static variables shared between instances of polling. +static ExtensionIdlePollingData polling_data; + +// Forward declaration of utility methods. +static const wchar_t* IdleStateToDescription(IdleState state); +static StringValue* CreateIdleValue(IdleState idle_state); +static int CheckThresholdBounds(int timeout); +static IdleState CalculateIdleStateAndUpdateTimestamp(int threshold); +static void CreateNewPollTask(Profile* profile); +static IdleState ThrottledCalculateIdleState(int threshold, Profile* profile); + +// Internal object which watches for changes in the system idle state. +class ExtensionIdlePollingTask : public Task { + public: + explicit ExtensionIdlePollingTask(Profile* profile) : profile_(profile) {} + virtual ~ExtensionIdlePollingTask() {} + + // Overridden from Task. + virtual void Run(); + + private: + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionIdlePollingTask); +}; + +const wchar_t* IdleStateToDescription(IdleState state) { + if (IDLE_STATE_ACTIVE == state) + return keys::kStateActive; + if (IDLE_STATE_IDLE == state) + return keys::kStateIdle; + return keys::kStateLocked; +}; + +// Helper function for reporting the idle state. The lifetime of the object +// returned is controlled by the caller. +StringValue* CreateIdleValue(IdleState idle_state) { + StringValue* result = new StringValue(IdleStateToDescription(idle_state)); + return result; +} + +int CheckThresholdBounds(int timeout) { + if (timeout < kMinThreshold) return kMinThreshold; + if (timeout > kMaxThreshold) return kMaxThreshold; + return timeout; +} + +IdleState CalculateIdleStateAndUpdateTimestamp(int threshold) { + polling_data.timestamp = base::Time::Now().ToDoubleT(); + return CalculateIdleState(threshold); +} + +void CreateNewPollTask(Profile* profile) { + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + new ExtensionIdlePollingTask(profile), + kIdlePollInterval * 1000); +} + +IdleState ThrottledCalculateIdleState(int threshold, Profile* profile) { + // If we are not active we should be polling. + if (IDLE_STATE_ACTIVE != polling_data.state) + return polling_data.state; + + // Only allow one check per threshold. + double time_now = base::Time::Now().ToDoubleT(); + double delta = time_now - polling_data.timestamp; + if (delta < threshold) + return polling_data.state; + + // Update the new state with a poll. Note this updates time of last check. + polling_data.state = CalculateIdleStateAndUpdateTimestamp(threshold); + + if (IDLE_STATE_ACTIVE != polling_data.state) + CreateNewPollTask(profile); + + return polling_data.state; +} + +void ExtensionIdlePollingTask::Run() { + IdleState state = CalculateIdleStateAndUpdateTimestamp( + kIdlePollInterval); + if (state != polling_data.state) { + polling_data.state = state; + + // Inform of change if the current state is IDLE_STATE_ACTIVE. + if (IDLE_STATE_ACTIVE == polling_data.state) + ExtensionIdleEventRouter::OnIdleStateChange(profile_, state); + } + + // Create a secondary polling task until an active state is reached. + if (IDLE_STATE_ACTIVE != polling_data.state) + CreateNewPollTask(profile_); +} + +}; // namespace + +bool ExtensionIdleQueryStateFunction::RunImpl() { + int threshold; + EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &threshold)); + threshold = CheckThresholdBounds(threshold); + IdleState state = ThrottledCalculateIdleState(threshold, profile()); + result_.reset(CreateIdleValue(state)); + return true; +} + +void ExtensionIdleEventRouter::OnIdleStateChange(Profile* profile, + IdleState state) { + // Prepare the single argument of the current state. + ListValue args; + args.Append(CreateIdleValue(state)); + std::string json_args; + base::JSONWriter::Write(&args, false, &json_args); + + profile->GetExtensionMessageService()->DispatchEventToRenderers( + keys::kOnStateChanged, + json_args, + profile->IsOffTheRecord(), + GURL()); +} |