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