diff options
-rw-r--r-- | chrome/browser/extensions/extension_idle_api.cc | 168 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_idle_api.h | 5 | ||||
-rw-r--r-- | chrome/browser/idle.cc | 25 | ||||
-rw-r--r-- | chrome/browser/idle.h | 13 | ||||
-rw-r--r-- | chrome/browser/idle_linux.cc | 13 | ||||
-rw-r--r-- | chrome/browser/idle_mac.mm | 14 | ||||
-rw-r--r-- | chrome/browser/idle_win.cc | 13 | ||||
-rw-r--r-- | chrome/browser/notifications/notification_ui_manager.cc | 2 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 1 |
9 files changed, 166 insertions, 88 deletions
diff --git a/chrome/browser/extensions/extension_idle_api.cc b/chrome/browser/extensions/extension_idle_api.cc index bf22ecc..f52f4b7 100644 --- a/chrome/browser/extensions/extension_idle_api.cc +++ b/chrome/browser/extensions/extension_idle_api.cc @@ -2,13 +2,12 @@ // 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/bind.h" +#include "base/callback.h" #include "base/json/json_writer.h" #include "base/message_loop.h" #include "base/stl_util.h" @@ -25,9 +24,11 @@ namespace keys = extension_idle_api_constants; namespace { - -const int kIdlePollInterval = 15; // Number of seconds between status checks - // when polling for active. +const int kIdlePollInterval = 1; // Number of seconds between status checks + // when polling for active. +const int kThrottleInterval = 1; // Number of seconds to throttle idle checks + // for. Return the previously checked idle + // state if the next check is faster than this 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. @@ -37,32 +38,74 @@ struct ExtensionIdlePollingData { double timestamp; }; -// Static variables shared between instances of polling. -static ExtensionIdlePollingData polling_data; - -// Forward declaration of utility methods. -static const char* 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); +// Used to throttle excessive calls to query for idle state +ExtensionIdlePollingData polling_data = {IDLE_STATE_UNKNOWN, 0}; -// Internal object which watches for changes in the system idle state. -class ExtensionIdlePollingTask : public Task { +// Internal class which is used to poll for changes in the system idle state. +class ExtensionIdlePollingTask { public: - explicit ExtensionIdlePollingTask(Profile* profile) : profile_(profile) {} - virtual ~ExtensionIdlePollingTask() {} + explicit ExtensionIdlePollingTask(int threshold, IdleState last_state, + Profile* profile) : threshold_(threshold), last_state_(last_state), + profile_(profile) {} - // Overridden from Task. - virtual void Run(); + // Check if we're active; then restart the polling task. Do this till we are + // are in active state. + void CheckIdleState(); + void IdleStateCallback(IdleState state); + + // Create a poll task to check for Idle state + static void CreateNewPollTask(int threshold, IdleState state, + Profile* profile); private: + int threshold_; + IdleState last_state_; Profile* profile_; + static bool poll_task_running_; + DISALLOW_COPY_AND_ASSIGN(ExtensionIdlePollingTask); }; +// Implementation of ExtensionIdlePollingTask. +bool ExtensionIdlePollingTask::poll_task_running_ = false; + +void ExtensionIdlePollingTask::IdleStateCallback(IdleState current_state) { + // If we just came into an active state, notify the extension. + if (IDLE_STATE_ACTIVE == current_state && last_state_ != current_state) + ExtensionIdleEventRouter::OnIdleStateChange(profile_, current_state); + + ExtensionIdlePollingTask::poll_task_running_ = false; + + // Startup another polling task as we exit. + if (current_state != IDLE_STATE_ACTIVE) + ExtensionIdlePollingTask::CreateNewPollTask(threshold_, current_state, + profile_); + + // This instance won't be needed anymore. + delete this; +} + +void ExtensionIdlePollingTask::CheckIdleState() { + CalculateIdleState(threshold_, + base::Bind(&ExtensionIdlePollingTask::IdleStateCallback, + base::Unretained(this))); +} + +// static +void ExtensionIdlePollingTask::CreateNewPollTask(int threshold, IdleState state, + Profile* profile) { + if (ExtensionIdlePollingTask::poll_task_running_) return; + + ExtensionIdlePollingTask::poll_task_running_ = true; + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&ExtensionIdlePollingTask::CheckIdleState, base::Unretained( + new ExtensionIdlePollingTask(threshold, state, profile))), + kIdlePollInterval * 1000); +} + + const char* IdleStateToDescription(IdleState state) { if (IDLE_STATE_ACTIVE == state) return keys::kStateActive; @@ -84,62 +127,51 @@ int CheckThresholdBounds(int timeout) { return timeout; } -IdleState CalculateIdleStateAndUpdateTimestamp(int threshold) { - polling_data.timestamp = base::Time::Now().ToDoubleT(); - return CalculateIdleState(threshold); +bool ShouldThrottle() { + double now = base::Time::Now().ToDoubleT(); + double delta = now - polling_data.timestamp; + polling_data.timestamp = now; + if (delta < kThrottleInterval) + return false; + else + return true; } +}; // namespace -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); +void ExtensionIdleQueryStateFunction::IdleStateCallback(int threshold, + IdleState state) { + // If our state is not active, make sure we're running a polling task to check + // for active state and report it when it changes to active. + if (state != IDLE_STATE_ACTIVE) { + ExtensionIdlePollingTask::CreateNewPollTask(threshold, state, profile_); } - // Create a secondary polling task until an active state is reached. - if (IDLE_STATE_ACTIVE != polling_data.state) - CreateNewPollTask(profile_); + result_.reset(CreateIdleValue(state)); + polling_data.state = state; + SendResponse(true); } -}; // 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)); + + if (ShouldThrottle()) { + if (polling_data.state != IDLE_STATE_UNKNOWN) { + result_.reset(CreateIdleValue(polling_data.state)); + SendResponse(true); + return true; + } + // We cannot get the idle state right now, we're already checking for idle + // from a previous call, so continue with normal idle check instead. + } + + polling_data.state = IDLE_STATE_UNKNOWN; + CalculateIdleState(threshold, + base::Bind(&ExtensionIdleQueryStateFunction::IdleStateCallback, + base::Unretained(this), threshold)); + + // Don't send the response, it'll be sent by our callback return true; } diff --git a/chrome/browser/extensions/extension_idle_api.h b/chrome/browser/extensions/extension_idle_api.h index 9f40481..927c68c 100644 --- a/chrome/browser/extensions/extension_idle_api.h +++ b/chrome/browser/extensions/extension_idle_api.h @@ -21,10 +21,13 @@ class ExtensionIdleEventRouter { }; // Implementation of the chrome.idle.queryState API. -class ExtensionIdleQueryStateFunction : public SyncExtensionFunction { +class ExtensionIdleQueryStateFunction : public AsyncExtensionFunction { public: virtual bool RunImpl(); DECLARE_EXTENSION_FUNCTION_NAME("idle.queryState") + + private: + void IdleStateCallback(int threshold, IdleState state); }; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_IDLE_API_H_ diff --git a/chrome/browser/idle.cc b/chrome/browser/idle.cc new file mode 100644 index 0000000..73b5613 --- /dev/null +++ b/chrome/browser/idle.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2011 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/idle.h" + +#include "base/bind.h" +#include "base/synchronization/waitable_event.h" + + + +void IdleStateCallback(IdleState* return_state, base::WaitableEvent* done, + IdleState state) { + *return_state = state; + done->Signal(); +} + +IdleState CalculateIdleStateSync(unsigned int idle_threshold) { + IdleState return_state; + base::WaitableEvent done(true, false); + CalculateIdleState(idle_threshold, base::Bind(&IdleStateCallback, + &return_state, &done)); + done.Wait(); + return return_state; +} diff --git a/chrome/browser/idle.h b/chrome/browser/idle.h index 4f99bef..05b5066 100644 --- a/chrome/browser/idle.h +++ b/chrome/browser/idle.h @@ -6,10 +6,14 @@ #define CHROME_BROWSER_IDLE_H_ #pragma once +#include "base/callback.h" + enum IdleState { IDLE_STATE_ACTIVE = 0, IDLE_STATE_IDLE = 1, // No activity within threshold. - IDLE_STATE_LOCKED = 2 // Only available on supported systems. + IDLE_STATE_LOCKED = 2, // Only available on supported systems. + IDLE_STATE_UNKNOWN = 3 // Used when waiting for the Idle state or in error + // conditions }; // For MacOSX, InitIdleMonitor needs to be called first to setup the monitor. @@ -19,6 +23,11 @@ void InitIdleMonitor(); void StopIdleMonitor(); #endif -IdleState CalculateIdleState(unsigned int idle_threshold); +typedef base::Callback<void(IdleState)> IdleCallback; + +// Calculate the Idle state and notify the callback. +void CalculateIdleState(unsigned int idle_threshold, IdleCallback notify); +// Calculate the Idle state synchronously and return the state. +IdleState CalculateIdleStateSync(unsigned int idle_threshold); #endif // CHROME_BROWSER_IDLE_H_ diff --git a/chrome/browser/idle_linux.cc b/chrome/browser/idle_linux.cc index 2689808..eba7958 100644 --- a/chrome/browser/idle_linux.cc +++ b/chrome/browser/idle_linux.cc @@ -63,18 +63,21 @@ bool ScreensaverWindowExists() { } -IdleState CalculateIdleState(unsigned int idle_threshold) { +void CalculateIdleState(unsigned int idle_threshold, IdleCallback notify) { // Usually the screensaver is used to lock the screen, so we do not need to // check if the workstation is locked. gdk_error_trap_push(); bool result = ScreensaverWindowExists(); bool got_error = gdk_error_trap_pop(); - if (result && !got_error) - return IDLE_STATE_LOCKED; + if (result && !got_error) { + notify.Run(IDLE_STATE_LOCKED); + return; + } browser::IdleQueryLinux idle_query; unsigned int idle_time = idle_query.IdleTime(); if (idle_time >= idle_threshold) - return IDLE_STATE_IDLE; - return IDLE_STATE_ACTIVE; + notify.Run(IDLE_STATE_IDLE); + else + notify.Run(IDLE_STATE_ACTIVE); } diff --git a/chrome/browser/idle_mac.mm b/chrome/browser/idle_mac.mm index 4032408..e1ab476 100644 --- a/chrome/browser/idle_mac.mm +++ b/chrome/browser/idle_mac.mm @@ -84,16 +84,18 @@ void StopIdleMonitor() { g_screenMonitor = nil; } -IdleState CalculateIdleState(unsigned int idle_threshold) { +void CalculateIdleState(unsigned int idle_threshold, IdleCallback notify) { if ([g_screenMonitor isScreensaverRunning] || - [g_screenMonitor isScreenLocked]) - return IDLE_STATE_LOCKED; + [g_screenMonitor isScreenLocked]) { + notify.Run(IDLE_STATE_LOCKED); + return; + } CFTimeInterval idle_time = CGEventSourceSecondsSinceLastEventType( kCGEventSourceStateCombinedSessionState, kCGAnyInputEventType); if (idle_time >= idle_threshold) - return IDLE_STATE_IDLE; - - return IDLE_STATE_ACTIVE; + notify.Run(IDLE_STATE_IDLE); + else + notify.Run(IDLE_STATE_ACTIVE); } diff --git a/chrome/browser/idle_win.cc b/chrome/browser/idle_win.cc index ed45da2..c745ca9 100644 --- a/chrome/browser/idle_win.cc +++ b/chrome/browser/idle_win.cc @@ -10,9 +10,11 @@ static bool IsScreensaverRunning(); static bool IsWorkstationLocked(); -IdleState CalculateIdleState(unsigned int idle_threshold) { - if (IsScreensaverRunning() || IsWorkstationLocked()) - return IDLE_STATE_LOCKED; +void CalculateIdleState(unsigned int idle_threshold, IdleCallback notify) { + if (IsScreensaverRunning() || IsWorkstationLocked()) { + notify.Run(IDLE_STATE_LOCKED); + return; + } LASTINPUTINFO last_input_info = {0}; last_input_info.cbSize = sizeof(LASTINPUTINFO); @@ -36,8 +38,9 @@ IdleState CalculateIdleState(unsigned int idle_threshold) { } if (current_idle_time >= idle_threshold) - return IDLE_STATE_IDLE; - return IDLE_STATE_ACTIVE; + notify.Run(IDLE_STATE_IDLE); + else + notify.Run(IDLE_STATE_ACTIVE); } bool IsScreensaverRunning() { diff --git a/chrome/browser/notifications/notification_ui_manager.cc b/chrome/browser/notifications/notification_ui_manager.cc index 2d66214..a2fdf24 100644 --- a/chrome/browser/notifications/notification_ui_manager.cc +++ b/chrome/browser/notifications/notification_ui_manager.cc @@ -152,7 +152,7 @@ void NotificationUIManager::CheckAndShowNotifications() { void NotificationUIManager::CheckUserState() { bool is_user_active_previously = is_user_active_; - is_user_active_ = CalculateIdleState(0) != IDLE_STATE_LOCKED && + is_user_active_ = CalculateIdleStateSync(0) != IDLE_STATE_LOCKED && !IsFullScreenMode(); if (is_user_active_ == is_user_active_previously) return; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index b4c1ad8..248d41a 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1300,6 +1300,7 @@ 'browser/icon_manager_linux.cc', 'browser/icon_manager_mac.mm', 'browser/icon_manager_win.cc', + 'browser/idle.cc', 'browser/idle_linux.cc', 'browser/idle_mac.mm', 'browser/idle_query_linux.cc', |