• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
RecommendationRestorer(Profile * profile)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 
~RecommendationRestorer()59 RecommendationRestorer::~RecommendationRestorer() {
60 }
61 
Shutdown()62 void RecommendationRestorer::Shutdown() {
63   StopTimer();
64   pref_change_registrar_.RemoveAll();
65   notification_registrar_.RemoveAll();
66 }
67 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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 
OnUserActivity(const ui::Event * event)82 void RecommendationRestorer::OnUserActivity(const ui::Event* event) {
83   if (restore_timer_.IsRunning())
84     restore_timer_.Reset();
85 }
86 
Restore(bool allow_delay,const std::string & pref_name)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 
RestoreAll()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 
StartTimer()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 
StopTimer()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