1 // Copyright 2014 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.
5 #include "chrome/browser/signin/easy_unlock_service.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/component_loader.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h"
17 #include "chrome/browser/signin/easy_unlock_service_factory.h"
18 #include "chrome/browser/signin/easy_unlock_service_observer.h"
19 #include "chrome/browser/signin/screenlock_bridge.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/extensions/extension_constants.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/pref_registry/pref_registry_syncable.h"
24 #include "device/bluetooth/bluetooth_adapter.h"
25 #include "device/bluetooth/bluetooth_adapter_factory.h"
26 #include "extensions/browser/extension_registry.h"
27 #include "extensions/browser/extension_system.h"
28 #include "extensions/common/one_shot_event.h"
29 #include "grit/browser_resources.h"
31 #if defined(OS_CHROMEOS)
32 #include "chromeos/dbus/dbus_thread_manager.h"
33 #include "chromeos/dbus/power_manager_client.h"
38 extensions::ComponentLoader
* GetComponentLoader(
39 content::BrowserContext
* context
) {
40 extensions::ExtensionSystem
* extension_system
=
41 extensions::ExtensionSystem::Get(context
);
42 ExtensionService
* extension_service
= extension_system
->extension_service();
43 return extension_service
->component_loader();
49 EasyUnlockService
* EasyUnlockService::Get(Profile
* profile
) {
50 return EasyUnlockServiceFactory::GetForProfile(profile
);
53 class EasyUnlockService::BluetoothDetector
54 : public device::BluetoothAdapter::Observer
{
56 explicit BluetoothDetector(EasyUnlockService
* service
)
58 weak_ptr_factory_(this) {
61 virtual ~BluetoothDetector() {
63 adapter_
->RemoveObserver(this);
67 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
70 device::BluetoothAdapterFactory::GetAdapter(
71 base::Bind(&BluetoothDetector::OnAdapterInitialized
,
72 weak_ptr_factory_
.GetWeakPtr()));
75 bool IsPresent() const { return adapter_
.get() && adapter_
->IsPresent(); }
77 // device::BluetoothAdapter::Observer:
78 virtual void AdapterPresentChanged(device::BluetoothAdapter
* adapter
,
79 bool present
) OVERRIDE
{
80 service_
->OnBluetoothAdapterPresentChanged();
84 void OnAdapterInitialized(scoped_refptr
<device::BluetoothAdapter
> adapter
) {
86 adapter_
->AddObserver(this);
87 service_
->OnBluetoothAdapterPresentChanged();
90 // Owner of this class and should out-live this class.
91 EasyUnlockService
* service_
;
92 scoped_refptr
<device::BluetoothAdapter
> adapter_
;
93 base::WeakPtrFactory
<BluetoothDetector
> weak_ptr_factory_
;
95 DISALLOW_COPY_AND_ASSIGN(BluetoothDetector
);
98 #if defined(OS_CHROMEOS)
99 class EasyUnlockService::PowerMonitor
:
100 public chromeos::PowerManagerClient::Observer
{
102 explicit PowerMonitor(EasyUnlockService
* service
) : service_(service
) {
103 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
107 virtual ~PowerMonitor() {
108 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
109 RemoveObserver(this);
113 // chromeos::PowerManagerClient::Observer:
114 virtual void SuspendImminent() OVERRIDE
{
115 service_
->DisableAppIfLoaded();
118 virtual void SuspendDone(const base::TimeDelta
& sleep_duration
) OVERRIDE
{
122 EasyUnlockService
* service_
;
124 DISALLOW_COPY_AND_ASSIGN(PowerMonitor
);
128 EasyUnlockService::EasyUnlockService(Profile
* profile
)
130 bluetooth_detector_(new BluetoothDetector(this)),
131 weak_ptr_factory_(this) {
132 extensions::ExtensionSystem::Get(profile_
)->ready().Post(
134 base::Bind(&EasyUnlockService::Initialize
,
135 weak_ptr_factory_
.GetWeakPtr()));
138 EasyUnlockService::~EasyUnlockService() {
142 void EasyUnlockService::RegisterProfilePrefs(
143 user_prefs::PrefRegistrySyncable
* registry
) {
144 registry
->RegisterBooleanPref(
145 prefs::kEasyUnlockEnabled
,
147 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
148 registry
->RegisterBooleanPref(
149 prefs::kEasyUnlockShowTutorial
,
151 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
152 registry
->RegisterDictionaryPref(
153 prefs::kEasyUnlockPairing
,
154 new base::DictionaryValue(),
155 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
156 registry
->RegisterBooleanPref(
157 prefs::kEasyUnlockAllowed
,
159 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
162 bool EasyUnlockService::IsAllowed() {
163 if (!IsAllowedInternal())
166 #if defined(OS_CHROMEOS)
167 if (!profile_
->GetPrefs()->GetBoolean(prefs::kEasyUnlockAllowed
))
170 // Respect existing policy and skip finch test.
171 if (!profile_
->GetPrefs()->IsManagedPreference(prefs::kEasyUnlockAllowed
)) {
172 // It is disabled when the trial exists and is in "Disable" group.
173 if (base::FieldTrialList::FindFullName("EasyUnlock") == "Disable")
177 if (!bluetooth_detector_
->IsPresent())
182 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
187 EasyUnlockScreenlockStateHandler
*
188 EasyUnlockService::GetScreenlockStateHandler() {
191 if (!screenlock_state_handler_
) {
192 screenlock_state_handler_
.reset(new EasyUnlockScreenlockStateHandler(
194 GetType() == TYPE_REGULAR
? profile_
->GetPrefs() : NULL
,
195 ScreenlockBridge::Get()));
197 return screenlock_state_handler_
.get();
200 void EasyUnlockService::AddObserver(EasyUnlockServiceObserver
* observer
) {
201 observers_
.AddObserver(observer
);
204 void EasyUnlockService::RemoveObserver(EasyUnlockServiceObserver
* observer
) {
205 observers_
.RemoveObserver(observer
);
208 void EasyUnlockService::LoadApp() {
211 #if defined(GOOGLE_CHROME_BUILD)
212 base::FilePath easy_unlock_path
;
213 #if defined(OS_CHROMEOS)
214 easy_unlock_path
= base::FilePath("/usr/share/chromeos-assets/easy_unlock");
215 #endif // defined(OS_CHROMEOS)
218 // Only allow app path override switch for debug build.
219 const CommandLine
* command_line
= CommandLine::ForCurrentProcess();
220 if (command_line
->HasSwitch(switches::kEasyUnlockAppPath
)) {
222 command_line
->GetSwitchValuePath(switches::kEasyUnlockAppPath
);
224 #endif // !defined(NDEBUG)
226 if (!easy_unlock_path
.empty()) {
227 extensions::ComponentLoader
* loader
= GetComponentLoader(profile_
);
228 if (!loader
->Exists(extension_misc::kEasyUnlockAppId
))
229 loader
->Add(IDR_EASY_UNLOCK_MANIFEST
, easy_unlock_path
);
231 ExtensionService
* extension_service
=
232 extensions::ExtensionSystem::Get(profile_
)->extension_service();
233 extension_service
->EnableExtension(extension_misc::kEasyUnlockAppId
);
235 #endif // defined(GOOGLE_CHROME_BUILD)
238 void EasyUnlockService::DisableAppIfLoaded() {
239 // Make sure lock screen state set by the extension gets reset.
240 screenlock_state_handler_
.reset();
242 extensions::ComponentLoader
* loader
= GetComponentLoader(profile_
);
243 if (!loader
->Exists(extension_misc::kEasyUnlockAppId
))
246 ExtensionService
* extension_service
=
247 extensions::ExtensionSystem::Get(profile_
)->extension_service();
248 extension_service
->DisableExtension(extension_misc::kEasyUnlockAppId
,
249 extensions::Extension::DISABLE_RELOAD
);
252 void EasyUnlockService::ReloadApp() {
253 // Make sure lock screen state set by the extension gets reset.
254 screenlock_state_handler_
.reset();
256 if (GetComponentLoader(profile_
)->Exists(extension_misc::kEasyUnlockAppId
)) {
257 extensions::ExtensionSystem
* extension_system
=
258 extensions::ExtensionSystem::Get(profile_
);
259 extension_system
->extension_service()->ReloadExtension(
260 extension_misc::kEasyUnlockAppId
);
264 void EasyUnlockService::UpdateAppState() {
268 #if defined(OS_CHROMEOS)
270 power_monitor_
.reset(new PowerMonitor(this));
273 DisableAppIfLoaded();
274 #if defined(OS_CHROMEOS)
275 power_monitor_
.reset();
280 void EasyUnlockService::NotifyTurnOffOperationStatusChanged() {
282 EasyUnlockServiceObserver
, observers_
, OnTurnOffOperationStatusChanged());
285 void EasyUnlockService::Initialize() {
286 InitializeInternal();
288 #if defined(OS_CHROMEOS)
289 // Only start Bluetooth detection for ChromeOS since the feature is
290 // only offered on ChromeOS. Enabling this on non-ChromeOS platforms
291 // previously introduced a performance regression: http://crbug.com/404482
292 // Make sure not to reintroduce a performance regression if re-enabling on
293 // additional platforms.
294 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
295 bluetooth_detector_
->Initialize();
296 #endif // defined(OS_CHROMEOS)
299 void EasyUnlockService::OnBluetoothAdapterPresentChanged() {