OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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/ui/webui/options2/chromeos/bluetooth_options_handler.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/command_line.h" | |
9 #include "base/utf_string_conversions.h" | |
10 #include "base/values.h" | |
11 #include "chrome/browser/chromeos/bluetooth/bluetooth_device.h" | |
12 #include "chrome/browser/chromeos/system/runtime_environment.h" | |
13 #include "chrome/browser/ui/webui/options2/chromeos/system_settings_provider.h" | |
14 #include "chrome/common/chrome_switches.h" | |
15 #include "grit/chromium_strings.h" | |
16 #include "grit/generated_resources.h" | |
17 #include "third_party/cros_system_api/dbus/service_constants.h" | |
18 #include "ui/base/l10n/l10n_util.h" | |
19 | |
20 namespace { | |
21 | |
22 // |UpdateDeviceCallback| takes a variable length list as an argument. The | |
23 // value stored in each list element is indicated by the following constants. | |
24 const int kUpdateDeviceAddressIndex = 0; | |
25 const int kUpdateDeviceCommandIndex = 1; | |
26 const int kUpdateDevicePasskeyIndex = 2; | |
27 | |
28 } // namespace | |
29 | |
30 namespace chromeos { | |
31 | |
32 BluetoothOptionsHandler::BluetoothOptionsHandler() { | |
33 } | |
34 | |
35 BluetoothOptionsHandler::~BluetoothOptionsHandler() { | |
36 if (!CommandLine::ForCurrentProcess() | |
37 ->HasSwitch(switches::kEnableBluetooth)) { | |
38 return; | |
39 } | |
40 | |
41 chromeos::BluetoothManager* bluetooth_manager = | |
42 chromeos::BluetoothManager::GetInstance(); | |
43 DCHECK(bluetooth_manager); | |
44 | |
45 chromeos::BluetoothAdapter* default_adapter = | |
46 bluetooth_manager->DefaultAdapter(); | |
47 | |
48 if (default_adapter != NULL) { | |
49 default_adapter->RemoveObserver(this); | |
50 } | |
51 | |
52 bluetooth_manager->RemoveObserver(this); | |
53 } | |
54 | |
55 void BluetoothOptionsHandler::GetLocalizedValues( | |
56 DictionaryValue* localized_strings) { | |
57 DCHECK(localized_strings); | |
58 | |
59 localized_strings->SetString("bluetooth", | |
60 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH)); | |
61 localized_strings->SetString("disableBluetooth", | |
62 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_DISABLE)); | |
63 localized_strings->SetString("enableBluetooth", | |
64 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_ENABLE)); | |
65 localized_strings->SetString("noBluetoothDevicesFound", | |
66 l10n_util::GetStringUTF16( | |
67 IDS_OPTIONS_SETTINGS_NO_BLUETOOTH_DEVICES_FOUND)); | |
68 localized_strings->SetString("findBluetoothDevices", | |
69 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_FIND_BLUETOOTH_DEVICES)); | |
70 localized_strings->SetString("bluetoothScanning", | |
71 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_SCANNING)); | |
72 localized_strings->SetString("bluetoothDeviceConnected", | |
73 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECTED)); | |
74 localized_strings->SetString("bluetoothDeviceConnecting", | |
75 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECTING)); | |
76 localized_strings->SetString("bluetoothDeviceNotPaired", | |
77 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_NOT_PAIRED)); | |
78 localized_strings->SetString("bluetoothDevicePaired", | |
79 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_PAIRED)); | |
80 localized_strings->SetString("bluetoothDeviceFailedPairing", | |
81 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_FAILED_PAIRING)); | |
82 localized_strings->SetString("bluetoothConnectDevice", | |
83 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT)); | |
84 localized_strings->SetString("bluetoothDisconnectDevice", | |
85 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT)); | |
86 localized_strings->SetString("bluetoothForgetDevice", | |
87 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_FORGET)); | |
88 localized_strings->SetString("bluetoothCancel", | |
89 l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_BLUETOOTH_CANCEL)); | |
90 localized_strings->SetString("bluetoothAcceptPasskey", | |
91 l10n_util::GetStringUTF16( | |
92 IDS_OPTIONS_SETTINGS_BLUETOOTH_ACCEPT_PASSKEY)); | |
93 localized_strings->SetString("bluetoothRejectPasskey", | |
94 l10n_util::GetStringUTF16( | |
95 IDS_OPTIONS_SETTINGS_BLUETOOTH_REJECT_PASSKEY)); | |
96 localized_strings->SetString("bluetoothConfirmPasskey", | |
97 l10n_util::GetStringUTF16( | |
98 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONFIRM_PASSKEY_REQUEST)); | |
99 localized_strings->SetString("bluetoothEnterPasskey", | |
100 l10n_util::GetStringUTF16( | |
101 IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_PASSKEY_REQUEST)); | |
102 localized_strings->SetString("bluetoothRemotePasskey", | |
103 l10n_util::GetStringUTF16( | |
104 IDS_OPTIONS_SETTINGS_BLUETOOTH_REMOTE_PASSKEY_REQUEST)); | |
105 localized_strings->SetString("bluetoothFailedPairingInstructions", | |
106 l10n_util::GetStringUTF16( | |
107 IDS_OPTIONS_SETTINGS_BLUETOOTH_FAILED_PAIRING_INSTRUCTIONS)); | |
108 } | |
109 | |
110 void BluetoothOptionsHandler::Initialize() { | |
111 DCHECK(web_ui_); | |
112 // Bluetooth support is a work in progress. Supress the feature unless | |
113 // explicitly enabled via a command line flag. | |
114 if (!CommandLine::ForCurrentProcess() | |
115 ->HasSwitch(switches::kEnableBluetooth)) { | |
116 return; | |
117 } | |
118 | |
119 web_ui_->CallJavascriptFunction( | |
120 "options.SystemOptions.showBluetoothSettings"); | |
121 | |
122 // TODO(kevers): Determine whether bluetooth adapter is powered. | |
123 bool bluetooth_on = false; | |
124 base::FundamentalValue checked(bluetooth_on); | |
125 web_ui_->CallJavascriptFunction( | |
126 "options.SystemOptions.setBluetoothState", checked); | |
127 | |
128 chromeos::BluetoothManager* bluetooth_manager = | |
129 chromeos::BluetoothManager::GetInstance(); | |
130 DCHECK(bluetooth_manager); | |
131 bluetooth_manager->AddObserver(this); | |
132 | |
133 chromeos::BluetoothAdapter* default_adapter = | |
134 bluetooth_manager->DefaultAdapter(); | |
135 DefaultAdapterChanged(default_adapter); | |
136 } | |
137 | |
138 void BluetoothOptionsHandler::RegisterMessages() { | |
139 DCHECK(web_ui_); | |
140 web_ui_->RegisterMessageCallback("bluetoothEnableChange", | |
141 base::Bind(&BluetoothOptionsHandler::EnableChangeCallback, | |
142 base::Unretained(this))); | |
143 web_ui_->RegisterMessageCallback("findBluetoothDevices", | |
144 base::Bind(&BluetoothOptionsHandler::FindDevicesCallback, | |
145 base::Unretained(this))); | |
146 web_ui_->RegisterMessageCallback("updateBluetoothDevice", | |
147 base::Bind(&BluetoothOptionsHandler::UpdateDeviceCallback, | |
148 base::Unretained(this))); | |
149 } | |
150 | |
151 void BluetoothOptionsHandler::EnableChangeCallback( | |
152 const ListValue* args) { | |
153 bool bluetooth_enabled; | |
154 args->GetBoolean(0, &bluetooth_enabled); | |
155 // TODO(kevers): Call Bluetooth API to enable or disable. | |
156 base::FundamentalValue checked(bluetooth_enabled); | |
157 web_ui_->CallJavascriptFunction( | |
158 "options.SystemOptions.setBluetoothState", checked); | |
159 } | |
160 | |
161 void BluetoothOptionsHandler::FindDevicesCallback( | |
162 const ListValue* args) { | |
163 // We only initiate a scan if we're running on Chrome OS. Otherwise, we | |
164 // generate a fake device list. | |
165 if (!chromeos::system::runtime_environment::IsRunningOnChromeOS()) { | |
166 GenerateFakeDeviceList(); | |
167 return; | |
168 } | |
169 | |
170 chromeos::BluetoothManager* bluetooth_manager = | |
171 chromeos::BluetoothManager::GetInstance(); | |
172 DCHECK(bluetooth_manager); | |
173 | |
174 chromeos::BluetoothAdapter* default_adapter = | |
175 bluetooth_manager->DefaultAdapter(); | |
176 | |
177 ValidateDefaultAdapter(default_adapter); | |
178 | |
179 if (default_adapter == NULL) { | |
180 VLOG(1) << "FindDevicesCallback: no default adapter"; | |
181 return; | |
182 } | |
183 | |
184 default_adapter->StartDiscovery(); | |
185 } | |
186 | |
187 void BluetoothOptionsHandler::UpdateDeviceCallback( | |
188 const ListValue* args) { | |
189 // TODO(kevers): Trigger connect/disconnect. | |
190 int size = args->GetSize(); | |
191 std::string address; | |
192 std::string command; | |
193 args->GetString(kUpdateDeviceAddressIndex, &address); | |
194 args->GetString(kUpdateDeviceCommandIndex, &command); | |
195 if (size > kUpdateDevicePasskeyIndex) { | |
196 // Passkey confirmation as part of the pairing process. | |
197 std::string passkey; | |
198 args->GetString(kUpdateDevicePasskeyIndex, &passkey); | |
199 DVLOG(1) << "UpdateDeviceCallback: " << address << ": " << command | |
200 << " [" << passkey << "]"; | |
201 } else { | |
202 // Initiating a device connection or disconnecting | |
203 DVLOG(1) << "UpdateDeviceCallback: " << address << ": " << command; | |
204 } | |
205 } | |
206 | |
207 void BluetoothOptionsHandler::SendDeviceNotification( | |
208 chromeos::BluetoothDevice* device, | |
209 base::DictionaryValue* params) { | |
210 // Retrieve properties of the bluetooth device. The properties names are | |
211 // in title case. Convert to camel case in accordance with our Javascript | |
212 // naming convention. | |
213 const DictionaryValue& properties = device->AsDictionary(); | |
214 base::DictionaryValue js_properties; | |
215 for (DictionaryValue::key_iterator it = properties.begin_keys(); | |
216 it != properties.end_keys(); ++it) { | |
217 base::Value* child = NULL; | |
218 properties.GetWithoutPathExpansion(*it, &child); | |
219 if (child) { | |
220 std::string js_key = *it; | |
221 js_key[0] = tolower(js_key[0]); | |
222 js_properties.SetWithoutPathExpansion(js_key, child->DeepCopy()); | |
223 } | |
224 } | |
225 if (params) { | |
226 js_properties.MergeDictionary(params); | |
227 } | |
228 web_ui_->CallJavascriptFunction( | |
229 "options.SystemOptions.addBluetoothDevice", | |
230 js_properties); | |
231 } | |
232 | |
233 void BluetoothOptionsHandler::RequestConfirmation( | |
234 chromeos::BluetoothDevice* device, | |
235 int passkey) { | |
236 DictionaryValue params; | |
237 params.SetString("pairing", "bluetoothConfirmPasskey"); | |
238 params.SetInteger("passkey", passkey); | |
239 SendDeviceNotification(device, ¶ms); | |
240 } | |
241 | |
242 void BluetoothOptionsHandler::DisplayPasskey( | |
243 chromeos::BluetoothDevice* device, | |
244 int passkey, | |
245 int entered) { | |
246 DictionaryValue params; | |
247 params.SetString("pairing", "bluetoothRemotePasskey"); | |
248 params.SetInteger("passkey", passkey); | |
249 params.SetInteger("entered", entered); | |
250 SendDeviceNotification(device, ¶ms); | |
251 } | |
252 | |
253 void BluetoothOptionsHandler::RequestPasskey( | |
254 chromeos::BluetoothDevice* device) { | |
255 DictionaryValue params; | |
256 params.SetString("pairing", "bluetoothEnterPasskey"); | |
257 SendDeviceNotification(device, ¶ms); | |
258 } | |
259 | |
260 void BluetoothOptionsHandler::ValidatePasskeyCallback( | |
261 const base::ListValue* args) { | |
262 // TODO(kevers): Implement me. | |
263 } | |
264 | |
265 void BluetoothOptionsHandler::DefaultAdapterChanged( | |
266 chromeos::BluetoothAdapter* adapter) { | |
267 std::string old_default_adapter_id = default_adapter_id_; | |
268 | |
269 if (adapter == NULL) { | |
270 default_adapter_id_.clear(); | |
271 VLOG(2) << "DefaultAdapterChanged: no default bluetooth adapter"; | |
272 } else { | |
273 default_adapter_id_ = adapter->Id(); | |
274 VLOG(2) << "DefaultAdapterChanged: " << default_adapter_id_; | |
275 } | |
276 | |
277 if (default_adapter_id_ == old_default_adapter_id) { | |
278 return; | |
279 } | |
280 | |
281 if (adapter != NULL) { | |
282 adapter->AddObserver(this); | |
283 } | |
284 | |
285 // TODO(vlaviano): Respond to adapter change. | |
286 } | |
287 | |
288 void BluetoothOptionsHandler::DiscoveryStarted(const std::string& adapter_id) { | |
289 VLOG(2) << "Discovery started on " << adapter_id; | |
290 } | |
291 | |
292 void BluetoothOptionsHandler::DiscoveryEnded(const std::string& adapter_id) { | |
293 VLOG(2) << "Discovery ended on " << adapter_id; | |
294 web_ui_->CallJavascriptFunction( | |
295 "options.SystemOptions.notifyBluetoothSearchComplete"); | |
296 | |
297 // Stop the discovery session. | |
298 // TODO(vlaviano): We may want to expose DeviceDisappeared, remove the | |
299 // "Find devices" button, and let the discovery session continue throughout | |
300 // the time that the page is visible rather than just doing a single discovery | |
301 // cycle in response to a button click. | |
302 chromeos::BluetoothManager* bluetooth_manager = | |
303 chromeos::BluetoothManager::GetInstance(); | |
304 DCHECK(bluetooth_manager); | |
305 | |
306 chromeos::BluetoothAdapter* default_adapter = | |
307 bluetooth_manager->DefaultAdapter(); | |
308 | |
309 ValidateDefaultAdapter(default_adapter); | |
310 | |
311 if (default_adapter == NULL) { | |
312 VLOG(1) << "DiscoveryEnded: no default adapter"; | |
313 return; | |
314 } | |
315 | |
316 default_adapter->StopDiscovery(); | |
317 } | |
318 | |
319 void BluetoothOptionsHandler::DeviceFound(const std::string& adapter_id, | |
320 chromeos::BluetoothDevice* device) { | |
321 VLOG(2) << "Device found on " << adapter_id; | |
322 DCHECK(device); | |
323 SendDeviceNotification(device, NULL); | |
324 } | |
325 | |
326 void BluetoothOptionsHandler::ValidateDefaultAdapter( | |
327 chromeos::BluetoothAdapter* adapter) { | |
328 if ((adapter == NULL && !default_adapter_id_.empty()) || | |
329 (adapter != NULL && default_adapter_id_ != adapter->Id())) { | |
330 VLOG(1) << "unexpected default adapter change from \"" | |
331 << default_adapter_id_ << "\" to \"" << adapter->Id() << "\""; | |
332 DefaultAdapterChanged(adapter); | |
333 } | |
334 } | |
335 | |
336 void BluetoothOptionsHandler::GenerateFakeDeviceList() { | |
337 GenerateFakeDevice( | |
338 "Fake Wireless Keyboard", | |
339 "01-02-03-04-05-06", | |
340 "input-keyboard", | |
341 true, | |
342 true, | |
343 ""); | |
344 GenerateFakeDevice( | |
345 "Fake Wireless Mouse", | |
346 "02-03-04-05-06-01", | |
347 "input-mouse", | |
348 true, | |
349 false, | |
350 ""); | |
351 GenerateFakeDevice( | |
352 "Fake Wireless Headset", | |
353 "03-04-05-06-01-02", | |
354 "headset", | |
355 false, | |
356 false, | |
357 ""); | |
358 GenerateFakeDevice( | |
359 "Fake Connecting Keyboard", | |
360 "04-05-06-01-02-03", | |
361 "input-keyboard", | |
362 false, | |
363 false, | |
364 "bluetoothRemotePasskey"); | |
365 GenerateFakeDevice( | |
366 "Fake Connecting Phone", | |
367 "05-06-01-02-03-04", | |
368 "phone", | |
369 false, | |
370 false, | |
371 "bluetoothConfirmPasskey"); | |
372 GenerateFakeDevice( | |
373 "Fake Connecting Headset", | |
374 "06-01-02-03-04-05", | |
375 "headset", | |
376 false, | |
377 false, | |
378 "bluetoothEnterPasskey"); | |
379 web_ui_->CallJavascriptFunction( | |
380 "options.SystemOptions.notifyBluetoothSearchComplete"); | |
381 } | |
382 | |
383 void BluetoothOptionsHandler::GenerateFakeDevice( | |
384 const std::string& name, | |
385 const std::string& address, | |
386 const std::string& icon, | |
387 bool paired, | |
388 bool connected, | |
389 const std::string& pairing) { | |
390 DictionaryValue properties; | |
391 properties.SetString(bluetooth_device::kNameProperty, name); | |
392 properties.SetString(bluetooth_device::kAddressProperty, address); | |
393 properties.SetString(bluetooth_device::kIconProperty, icon); | |
394 properties.SetBoolean(bluetooth_device::kPairedProperty, paired); | |
395 properties.SetBoolean(bluetooth_device::kConnectedProperty, connected); | |
396 properties.SetInteger(bluetooth_device::kClassProperty, 0); | |
397 chromeos::BluetoothDevice* device = | |
398 chromeos::BluetoothDevice::Create(properties); | |
399 DeviceFound("FakeAdapter", device); | |
400 if (pairing.compare("bluetoothRemotePasskey") == 0) { | |
401 DisplayPasskey(device, 12345, 2); | |
402 } else if (pairing.compare("bluetoothConfirmPasskey") == 0) { | |
403 RequestConfirmation(device, 12345); | |
404 } else if (pairing.compare("bluetoothEnterPasskey") == 0) { | |
405 RequestPasskey(device); | |
406 } | |
407 delete device; | |
408 } | |
409 | |
410 } // namespace chromeos | |
411 | |
OLD | NEW |