Home | History | Annotate | Download | only in policy
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/policy/recommendation_restorer.h"
      6 
      7 #include "ash/shell.h"
      8 #include "base/bind.h"
      9 #include "base/bind_helpers.h"
     10 #include "base/location.h"
     11 #include "base/logging.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "base/time/time.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/chrome_notification_types.h"
     16 #include "chrome/browser/chromeos/profiles/profile_helper.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/common/pref_names.h"
     19 #include "content/public/browser/notification_details.h"
     20 #include "content/public/browser/notification_service.h"
     21 #include "content/public/browser/notification_source.h"
     22 #include "ui/wm/core/user_activity_detector.h"
     23 
     24 namespace policy {
     25 
     26 namespace {
     27 // The amount of idle time after which recommended values are restored.
     28 const int kRestoreDelayInMs = 60 * 1000;  // 1 minute.
     29 }  // namespace
     30 
     31 RecommendationRestorer::RecommendationRestorer(Profile* profile)
     32     : logged_in_(false) {
     33   if (!chromeos::ProfileHelper::IsSigninProfile(profile))
     34     return;
     35 
     36   pref_change_registrar_.Init(profile->GetPrefs());
     37   pref_change_registrar_.Add(
     38       prefs::kAccessibilityLargeCursorEnabled,
     39       base::Bind(
     40           &RecommendationRestorer::Restore, base::Unretained(this), true));
     41   pref_change_registrar_.Add(
     42       prefs::kAccessibilitySpokenFeedbackEnabled,
     43       base::Bind(
     44           &RecommendationRestorer::Restore, base::Unretained(this), true));
     45   pref_change_registrar_.Add(
     46       prefs::kAccessibilityHighContrastEnabled,
     47       base::Bind(
     48           &RecommendationRestorer::Restore, base::Unretained(this), true));
     49   pref_change_registrar_.Add(
     50       prefs::kAccessibilityScreenMagnifierEnabled,
     51       base::Bind(
     52           &RecommendationRestorer::Restore, base::Unretained(this), true));
     53   pref_change_registrar_.Add(
     54       prefs::kAccessibilityScreenMagnifierType,
     55       base::Bind(
     56           &RecommendationRestorer::Restore, base::Unretained(this), true));
     57   pref_change_registrar_.Add(
     58       prefs::kAccessibilityVirtualKeyboardEnabled,
     59       base::Bind(
     60           &RecommendationRestorer::Restore, base::Unretained(this), true));
     61 
     62   notification_registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_CHANGED,
     63                               content::NotificationService::AllSources());
     64 
     65   RestoreAll();
     66 }
     67 
     68 RecommendationRestorer::~RecommendationRestorer() {
     69 }
     70 
     71 void RecommendationRestorer::Shutdown() {
     72   StopTimer();
     73   pref_change_registrar_.RemoveAll();
     74   notification_registrar_.RemoveAll();
     75 }
     76 
     77 void RecommendationRestorer::Observe(
     78     int type,
     79     const content::NotificationSource& source,
     80     const content::NotificationDetails& details) {
     81   if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED) {
     82     logged_in_ = true;
     83     notification_registrar_.RemoveAll();
     84     StopTimer();
     85     RestoreAll();
     86   } else {
     87     NOTREACHED();
     88   }
     89 }
     90 
     91 void RecommendationRestorer::OnUserActivity(const ui::Event* event) {
     92   if (restore_timer_.IsRunning())
     93     restore_timer_.Reset();
     94 }
     95 
     96 void RecommendationRestorer::Restore(bool allow_delay,
     97                                      const std::string& pref_name) {
     98   const PrefService::Preference* pref =
     99       pref_change_registrar_.prefs()->FindPreference(pref_name.c_str());
    100   if (!pref) {
    101     NOTREACHED();
    102     return;
    103   }
    104 
    105   if (!pref->GetRecommendedValue() || !pref->HasUserSetting())
    106     return;
    107 
    108   if (logged_in_) {
    109     allow_delay = false;
    110   } else if (allow_delay && ash::Shell::HasInstance()) {
    111     // Skip the delay if there has been no user input since the browser started.
    112     const wm::UserActivityDetector* user_activity_detector =
    113         ash::Shell::GetInstance()->user_activity_detector();
    114     allow_delay = !user_activity_detector->last_activity_time().is_null();
    115   }
    116 
    117   if (allow_delay)
    118     StartTimer();
    119   else
    120     pref_change_registrar_.prefs()->ClearPref(pref->name().c_str());
    121 }
    122 
    123 void RecommendationRestorer::RestoreAll() {
    124   Restore(false, prefs::kAccessibilityLargeCursorEnabled);
    125   Restore(false, prefs::kAccessibilitySpokenFeedbackEnabled);
    126   Restore(false, prefs::kAccessibilityHighContrastEnabled);
    127   Restore(false, prefs::kAccessibilityScreenMagnifierEnabled);
    128   Restore(false, prefs::kAccessibilityScreenMagnifierType);
    129   Restore(false, prefs::kAccessibilityVirtualKeyboardEnabled);
    130 }
    131 
    132 void RecommendationRestorer::StartTimer() {
    133   // Listen for user activity so that the timer can be reset while the user is
    134   // active, causing it to fire only when the user remains idle for
    135   // |kRestoreDelayInMs|.
    136   if (ash::Shell::HasInstance()) {
    137     wm::UserActivityDetector* user_activity_detector =
    138         ash::Shell::GetInstance()->user_activity_detector();
    139     if (!user_activity_detector->HasObserver(this))
    140       user_activity_detector->AddObserver(this);
    141   }
    142 
    143   // There should be a separate timer for each pref. However, in the common
    144   // case of the user changing settings, a single timer is sufficient. This is
    145   // because a change initiated by the user implies user activity, so that even
    146   // if there was a separate timer per pref, they would all be reset at that
    147   // point, causing them to fire at exactly the same time. In the much rarer
    148   // case of a recommended value changing, a single timer is a close
    149   // approximation of the behavior that would be obtained by resetting the timer
    150   // for the affected pref only.
    151   restore_timer_.Start(FROM_HERE,
    152                        base::TimeDelta::FromMilliseconds(kRestoreDelayInMs),
    153                        base::Bind(&RecommendationRestorer::RestoreAll,
    154                                   base::Unretained(this)));
    155 }
    156 
    157 void RecommendationRestorer::StopTimer() {
    158   restore_timer_.Stop();
    159   if (ash::Shell::HasInstance())
    160     ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
    161 }
    162 
    163 }  // namespace policy
    164