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