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 "ash/wm/user_activity_detector.h"
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/location.h"
     12 #include "base/logging.h"
     13 #include "base/prefs/pref_service.h"
     14 #include "base/time/time.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "chrome/browser/chromeos/profiles/profile_helper.h"
     18 #include "chrome/browser/profiles/profile.h"
     19 #include "chrome/common/pref_names.h"
     20 #include "content/public/browser/notification_details.h"
     21 #include "content/public/browser/notification_service.h"
     22 #include "content/public/browser/notification_source.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(prefs::kLargeCursorEnabled,
     38                              base::Bind(&RecommendationRestorer::Restore,
     39                                         base::Unretained(this), true));
     40   pref_change_registrar_.Add(prefs::kSpokenFeedbackEnabled,
     41                              base::Bind(&RecommendationRestorer::Restore,
     42                                         base::Unretained(this), true));
     43   pref_change_registrar_.Add(prefs::kHighContrastEnabled,
     44                              base::Bind(&RecommendationRestorer::Restore,
     45                                         base::Unretained(this), true));
     46   pref_change_registrar_.Add(prefs::kScreenMagnifierEnabled,
     47                              base::Bind(&RecommendationRestorer::Restore,
     48                                         base::Unretained(this), true));
     49   pref_change_registrar_.Add(prefs::kScreenMagnifierType,
     50                              base::Bind(&RecommendationRestorer::Restore,
     51                                         base::Unretained(this), true));
     52 
     53   notification_registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_CHANGED,
     54                               content::NotificationService::AllSources());
     55 
     56   RestoreAll();
     57 }
     58 
     59 RecommendationRestorer::~RecommendationRestorer() {
     60 }
     61 
     62 void RecommendationRestorer::Shutdown() {
     63   StopTimer();
     64   pref_change_registrar_.RemoveAll();
     65   notification_registrar_.RemoveAll();
     66 }
     67 
     68 void RecommendationRestorer::Observe(
     69     int type,
     70     const content::NotificationSource& source,
     71     const content::NotificationDetails& details) {
     72   if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED) {
     73     logged_in_ = true;
     74     notification_registrar_.RemoveAll();
     75     StopTimer();
     76     RestoreAll();
     77   } else {
     78     NOTREACHED();
     79   }
     80 }
     81 
     82 void RecommendationRestorer::OnUserActivity(const ui::Event* event) {
     83   if (restore_timer_.IsRunning())
     84     restore_timer_.Reset();
     85 }
     86 
     87 void RecommendationRestorer::Restore(bool allow_delay,
     88                                      const std::string& pref_name) {
     89   const PrefService::Preference* pref =
     90       pref_change_registrar_.prefs()->FindPreference(pref_name.c_str());
     91   if (!pref) {
     92     NOTREACHED();
     93     return;
     94   }
     95 
     96   if (!pref->GetRecommendedValue() || !pref->HasUserSetting())
     97     return;
     98 
     99   if (logged_in_) {
    100     allow_delay = false;
    101   } else if (allow_delay && ash::Shell::HasInstance()) {
    102     // Skip the delay if there has been no user input since the browser started.
    103     const ash::UserActivityDetector* user_activity_detector =
    104         ash::Shell::GetInstance()->user_activity_detector();
    105     allow_delay = !user_activity_detector->last_activity_time().is_null();
    106   }
    107 
    108   if (allow_delay)
    109     StartTimer();
    110   else
    111     pref_change_registrar_.prefs()->ClearPref(pref->name().c_str());
    112 }
    113 
    114 void RecommendationRestorer::RestoreAll() {
    115   Restore(false, prefs::kLargeCursorEnabled);
    116   Restore(false, prefs::kSpokenFeedbackEnabled);
    117   Restore(false, prefs::kHighContrastEnabled);
    118   Restore(false, prefs::kScreenMagnifierEnabled);
    119   Restore(false, prefs::kScreenMagnifierType);
    120 }
    121 
    122 void RecommendationRestorer::StartTimer() {
    123   // Listen for user activity so that the timer can be reset while the user is
    124   // active, causing it to fire only when the user remains idle for
    125   // |kRestoreDelayInMs|.
    126   if (ash::Shell::HasInstance()) {
    127     ash::UserActivityDetector* user_activity_detector =
    128         ash::Shell::GetInstance()->user_activity_detector();
    129     if (!user_activity_detector->HasObserver(this))
    130       user_activity_detector->AddObserver(this);
    131   }
    132 
    133   // There should be a separate timer for each pref. However, in the common
    134   // case of the user changing settings, a single timer is sufficient. This is
    135   // because a change initiated by the user implies user activity, so that even
    136   // if there was a separate timer per pref, they would all be reset at that
    137   // point, causing them to fire at exactly the same time. In the much rarer
    138   // case of a recommended value changing, a single timer is a close
    139   // approximation of the behavior that would be obtained by resetting the timer
    140   // for the affected pref only.
    141   restore_timer_.Start(FROM_HERE,
    142                        base::TimeDelta::FromMilliseconds(kRestoreDelayInMs),
    143                        base::Bind(&RecommendationRestorer::RestoreAll,
    144                                   base::Unretained(this)));
    145 }
    146 
    147 void RecommendationRestorer::StopTimer() {
    148   restore_timer_.Stop();
    149   if (ash::Shell::HasInstance())
    150     ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
    151 }
    152 
    153 }  // namespace policy
    154