OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // NETWORK_ERROR Note: | 5 // NETWORK_ERROR Note: |
6 // When a device can't be found in the BluetoothAdapter, that generally | 6 // When a device can't be found in the BluetoothAdapter, that generally |
7 // indicates that it's gone out of range. We reject with a NetworkError in that | 7 // indicates that it's gone out of range. We reject with a NetworkError in that |
8 // case. | 8 // case. |
9 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothdevice-conne
ctgatt | 9 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothdevice-conne
ctgatt |
10 | 10 |
| 11 // ID Not In Map Note: |
| 12 // A service, characteristic, or descriptor ID not in the corresponding |
| 13 // BluetoothDispatcherHost map [service_to_device_, characteristic_to_service_, |
| 14 // descriptor_to_characteristic_] implies a hostile renderer because a renderer |
| 15 // obtains the corresponding ID from this class and it will be added to the map |
| 16 // at that time. |
| 17 |
11 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h" | 18 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h" |
12 | 19 |
13 #include "base/bind.h" | 20 #include "base/bind.h" |
14 #include "base/single_thread_task_runner.h" | 21 #include "base/single_thread_task_runner.h" |
15 #include "base/strings/utf_string_conversions.h" | 22 #include "base/strings/utf_string_conversions.h" |
16 #include "base/thread_task_runner_handle.h" | 23 #include "base/thread_task_runner_handle.h" |
17 #include "content/browser/bad_message.h" | 24 #include "content/browser/bad_message.h" |
18 #include "content/browser/bluetooth/bluetooth_metrics.h" | 25 #include "content/browser/bluetooth/bluetooth_metrics.h" |
19 #include "content/browser/bluetooth/first_device_bluetooth_chooser.h" | 26 #include "content/browser/bluetooth/first_device_bluetooth_chooser.h" |
20 #include "content/browser/frame_host/render_frame_host_impl.h" | 27 #include "content/browser/frame_host/render_frame_host_impl.h" |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 bool BluetoothDispatcherHost::OnMessageReceived(const IPC::Message& message) { | 199 bool BluetoothDispatcherHost::OnMessageReceived(const IPC::Message& message) { |
193 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 200 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
194 bool handled = true; | 201 bool handled = true; |
195 IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcherHost, message) | 202 IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcherHost, message) |
196 IPC_MESSAGE_HANDLER(BluetoothHostMsg_RequestDevice, OnRequestDevice) | 203 IPC_MESSAGE_HANDLER(BluetoothHostMsg_RequestDevice, OnRequestDevice) |
197 IPC_MESSAGE_HANDLER(BluetoothHostMsg_ConnectGATT, OnConnectGATT) | 204 IPC_MESSAGE_HANDLER(BluetoothHostMsg_ConnectGATT, OnConnectGATT) |
198 IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetPrimaryService, OnGetPrimaryService) | 205 IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetPrimaryService, OnGetPrimaryService) |
199 IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetCharacteristic, OnGetCharacteristic) | 206 IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetCharacteristic, OnGetCharacteristic) |
200 IPC_MESSAGE_HANDLER(BluetoothHostMsg_ReadValue, OnReadValue) | 207 IPC_MESSAGE_HANDLER(BluetoothHostMsg_ReadValue, OnReadValue) |
201 IPC_MESSAGE_HANDLER(BluetoothHostMsg_WriteValue, OnWriteValue) | 208 IPC_MESSAGE_HANDLER(BluetoothHostMsg_WriteValue, OnWriteValue) |
| 209 IPC_MESSAGE_HANDLER(BluetoothHostMsg_StartNotifications, OnStartNotifications) |
| 210 IPC_MESSAGE_HANDLER(BluetoothHostMsg_StopNotifications, OnStopNotifications) |
202 IPC_MESSAGE_UNHANDLED(handled = false) | 211 IPC_MESSAGE_UNHANDLED(handled = false) |
203 IPC_END_MESSAGE_MAP() | 212 IPC_END_MESSAGE_MAP() |
204 return handled; | 213 return handled; |
205 } | 214 } |
206 | 215 |
207 void BluetoothDispatcherHost::SetBluetoothAdapterForTesting( | 216 void BluetoothDispatcherHost::SetBluetoothAdapterForTesting( |
208 scoped_refptr<device::BluetoothAdapter> mock_adapter) { | 217 scoped_refptr<device::BluetoothAdapter> mock_adapter) { |
209 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 218 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
210 current_delay_time_ = kTestingDelayTime; | 219 current_delay_time_ = kTestingDelayTime; |
211 // Reset the discovery session timer to use the new delay time. | 220 // Reset the discovery session timer to use the new delay time. |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 for (IDMap<RequestDeviceSession, IDMapOwnPointer>::iterator iter( | 349 for (IDMap<RequestDeviceSession, IDMapOwnPointer>::iterator iter( |
341 &request_device_sessions_); | 350 &request_device_sessions_); |
342 !iter.IsAtEnd(); iter.Advance()) { | 351 !iter.IsAtEnd(); iter.Advance()) { |
343 RequestDeviceSession* session = iter.GetCurrentValue(); | 352 RequestDeviceSession* session = iter.GetCurrentValue(); |
344 if (session->chooser) { | 353 if (session->chooser) { |
345 session->chooser->RemoveDevice(device->GetAddress()); | 354 session->chooser->RemoveDevice(device->GetAddress()); |
346 } | 355 } |
347 } | 356 } |
348 } | 357 } |
349 | 358 |
| 359 void BluetoothDispatcherHost::GattCharacteristicValueChanged( |
| 360 device::BluetoothAdapter* adapter, |
| 361 device::BluetoothGattCharacteristic* characteristic, |
| 362 const std::vector<uint8>& value) { |
| 363 // TODO(ortuno): Notify renderer the characteristic changed. |
| 364 // http://crbug.com/529560 |
| 365 VLOG(1) << "Characteristic updated."; |
| 366 } |
| 367 |
350 void BluetoothDispatcherHost::OnRequestDevice( | 368 void BluetoothDispatcherHost::OnRequestDevice( |
351 int thread_id, | 369 int thread_id, |
352 int request_id, | 370 int request_id, |
353 int frame_routing_id, | 371 int frame_routing_id, |
354 const std::vector<BluetoothScanFilter>& filters, | 372 const std::vector<BluetoothScanFilter>& filters, |
355 const std::vector<BluetoothUUID>& optional_services) { | 373 const std::vector<BluetoothUUID>& optional_services) { |
356 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 374 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
357 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::REQUEST_DEVICE); | 375 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::REQUEST_DEVICE); |
358 RecordRequestDeviceArguments(filters, optional_services); | 376 RecordRequestDeviceArguments(filters, optional_services); |
359 | 377 |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 void BluetoothDispatcherHost::OnGetCharacteristic( | 517 void BluetoothDispatcherHost::OnGetCharacteristic( |
500 int thread_id, | 518 int thread_id, |
501 int request_id, | 519 int request_id, |
502 const std::string& service_instance_id, | 520 const std::string& service_instance_id, |
503 const std::string& characteristic_uuid) { | 521 const std::string& characteristic_uuid) { |
504 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 522 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
505 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_CHARACTERISTIC); | 523 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_CHARACTERISTIC); |
506 RecordGetCharacteristicCharacteristic(characteristic_uuid); | 524 RecordGetCharacteristicCharacteristic(characteristic_uuid); |
507 | 525 |
508 auto device_iter = service_to_device_.find(service_instance_id); | 526 auto device_iter = service_to_device_.find(service_instance_id); |
509 // A service_instance_id not in the map implies a hostile renderer | 527 // Kill the renderer, see "ID Not In Map Note" above. |
510 // because a renderer obtains the service id from this class and | |
511 // it will be added to the map at that time. | |
512 if (device_iter == service_to_device_.end()) { | 528 if (device_iter == service_to_device_.end()) { |
513 // Kill the renderer | |
514 bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_SERVICE_ID); | 529 bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_SERVICE_ID); |
515 return; | 530 return; |
516 } | 531 } |
517 | 532 |
518 // TODO(ortuno): Check if domain has access to device. | 533 // TODO(ortuno): Check if domain has access to device. |
519 // https://crbug.com/493459 | 534 // https://crbug.com/493459 |
520 device::BluetoothDevice* device = | 535 device::BluetoothDevice* device = |
521 adapter_->GetDevice(device_iter->second /* device_instance_id */); | 536 adapter_->GetDevice(device_iter->second /* device_instance_id */); |
522 | 537 |
523 if (device == nullptr) { // See "NETWORK_ERROR Note" above. | 538 if (device == nullptr) { // See "NETWORK_ERROR Note" above. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 void BluetoothDispatcherHost::OnReadValue( | 582 void BluetoothDispatcherHost::OnReadValue( |
568 int thread_id, | 583 int thread_id, |
569 int request_id, | 584 int request_id, |
570 const std::string& characteristic_instance_id) { | 585 const std::string& characteristic_instance_id) { |
571 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 586 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
572 RecordWebBluetoothFunctionCall( | 587 RecordWebBluetoothFunctionCall( |
573 UMAWebBluetoothFunction::CHARACTERISTIC_READ_VALUE); | 588 UMAWebBluetoothFunction::CHARACTERISTIC_READ_VALUE); |
574 | 589 |
575 auto characteristic_iter = | 590 auto characteristic_iter = |
576 characteristic_to_service_.find(characteristic_instance_id); | 591 characteristic_to_service_.find(characteristic_instance_id); |
577 // A characteristic_instance_id not in the map implies a hostile renderer | 592 |
578 // because a renderer obtains the characteristic id from this class and | 593 // Kill the renderer, see "ID Not In Map Note" above. |
579 // it will be added to the map at that time. | |
580 if (characteristic_iter == characteristic_to_service_.end()) { | 594 if (characteristic_iter == characteristic_to_service_.end()) { |
581 // Kill the renderer | |
582 bad_message::ReceivedBadMessage(this, | 595 bad_message::ReceivedBadMessage(this, |
583 bad_message::BDH_INVALID_CHARACTERISTIC_ID); | 596 bad_message::BDH_INVALID_CHARACTERISTIC_ID); |
584 return; | 597 return; |
585 } | 598 } |
586 const std::string& service_instance_id = characteristic_iter->second; | 599 const std::string& service_instance_id = characteristic_iter->second; |
587 | 600 |
588 auto device_iter = service_to_device_.find(service_instance_id); | 601 auto device_iter = service_to_device_.find(service_instance_id); |
589 | 602 |
590 CHECK(device_iter != service_to_device_.end()); | 603 CHECK(device_iter != service_to_device_.end()); |
591 | 604 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
639 // get a value with length > 512, we can assume it's a hostile | 652 // get a value with length > 512, we can assume it's a hostile |
640 // renderer and kill it. | 653 // renderer and kill it. |
641 if (value.size() > 512) { | 654 if (value.size() > 512) { |
642 bad_message::ReceivedBadMessage( | 655 bad_message::ReceivedBadMessage( |
643 this, bad_message::BDH_INVALID_WRITE_VALUE_LENGTH); | 656 this, bad_message::BDH_INVALID_WRITE_VALUE_LENGTH); |
644 return; | 657 return; |
645 } | 658 } |
646 | 659 |
647 auto characteristic_iter = | 660 auto characteristic_iter = |
648 characteristic_to_service_.find(characteristic_instance_id); | 661 characteristic_to_service_.find(characteristic_instance_id); |
649 // A characteristic_instance_id not in the map implies a hostile renderer | 662 |
650 // because a renderer obtains the characteristic id from this class and | 663 // Kill the renderer, see "ID Not In Map Note" above. |
651 // it will be added to the map at that time. | |
652 if (characteristic_iter == characteristic_to_service_.end()) { | 664 if (characteristic_iter == characteristic_to_service_.end()) { |
653 bad_message::ReceivedBadMessage(this, | 665 bad_message::ReceivedBadMessage(this, |
654 bad_message::BDH_INVALID_CHARACTERISTIC_ID); | 666 bad_message::BDH_INVALID_CHARACTERISTIC_ID); |
655 return; | 667 return; |
656 } | 668 } |
657 const std::string& service_instance_id = characteristic_iter->second; | 669 const std::string& service_instance_id = characteristic_iter->second; |
658 | 670 |
659 auto device_iter = service_to_device_.find(service_instance_id); | 671 auto device_iter = service_to_device_.find(service_instance_id); |
660 | 672 |
661 CHECK(device_iter != service_to_device_.end()); | 673 CHECK(device_iter != service_to_device_.end()); |
(...skipping 25 matching lines...) Expand all Loading... |
687 WebBluetoothError::CharacteristicNoLongerExists)); | 699 WebBluetoothError::CharacteristicNoLongerExists)); |
688 return; | 700 return; |
689 } | 701 } |
690 characteristic->WriteRemoteCharacteristic( | 702 characteristic->WriteRemoteCharacteristic( |
691 value, base::Bind(&BluetoothDispatcherHost::OnWriteValueSuccess, | 703 value, base::Bind(&BluetoothDispatcherHost::OnWriteValueSuccess, |
692 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), | 704 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), |
693 base::Bind(&BluetoothDispatcherHost::OnWriteValueFailed, | 705 base::Bind(&BluetoothDispatcherHost::OnWriteValueFailed, |
694 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); | 706 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); |
695 } | 707 } |
696 | 708 |
| 709 void BluetoothDispatcherHost::OnStartNotifications( |
| 710 int thread_id, |
| 711 int request_id, |
| 712 const std::string& characteristic_instance_id) { |
| 713 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 714 RecordWebBluetoothFunctionCall( |
| 715 UMAWebBluetoothFunction::CHARACTERISTIC_START_NOTIFICATIONS); |
| 716 |
| 717 // BluetoothDispatcher will never send a request for a characteristic |
| 718 // already subscribed to notifications. |
| 719 if (characteristic_id_to_notify_session_.find(characteristic_instance_id) != |
| 720 characteristic_id_to_notify_session_.end()) { |
| 721 bad_message::ReceivedBadMessage( |
| 722 this, bad_message::BDH_CHARACTERISTIC_ALREADY_SUBSCRIBED); |
| 723 return; |
| 724 } |
| 725 |
| 726 // TODO(ortuno): Check if notify/indicate bit is set. |
| 727 // http://crbug.com/538869 |
| 728 |
| 729 auto characteristic_iter = |
| 730 characteristic_to_service_.find(characteristic_instance_id); |
| 731 |
| 732 // Kill the renderer, see "ID Not In Map Note" above. |
| 733 if (characteristic_iter == characteristic_to_service_.end()) { |
| 734 bad_message::ReceivedBadMessage(this, |
| 735 bad_message::BDH_INVALID_CHARACTERISTIC_ID); |
| 736 return; |
| 737 } |
| 738 |
| 739 const std::string& service_instance_id = characteristic_iter->second; |
| 740 auto device_iter = service_to_device_.find(service_instance_id); |
| 741 CHECK(device_iter != service_to_device_.end()); |
| 742 |
| 743 device::BluetoothDevice* device = |
| 744 adapter_->GetDevice(device_iter->second /* device_instance_id */); |
| 745 if (device == nullptr) { // See "NETWORK_ERROR Note" above. |
| 746 RecordStartNotificationsOutcome(UMAGATTOperationOutcome::NO_DEVICE); |
| 747 Send(new BluetoothMsg_StartNotificationsError( |
| 748 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange)); |
| 749 return; |
| 750 } |
| 751 |
| 752 BluetoothGattService* service = device->GetGattService(service_instance_id); |
| 753 if (service == nullptr) { |
| 754 RecordStartNotificationsOutcome(UMAGATTOperationOutcome::NO_SERVICE); |
| 755 Send(new BluetoothMsg_StartNotificationsError( |
| 756 thread_id, request_id, WebBluetoothError::ServiceNoLongerExists)); |
| 757 return; |
| 758 } |
| 759 |
| 760 BluetoothGattCharacteristic* characteristic = |
| 761 service->GetCharacteristic(characteristic_instance_id); |
| 762 if (characteristic == nullptr) { |
| 763 RecordStartNotificationsOutcome(UMAGATTOperationOutcome::NO_CHARACTERISTIC); |
| 764 Send(new BluetoothMsg_StartNotificationsError( |
| 765 thread_id, request_id, |
| 766 WebBluetoothError::CharacteristicNoLongerExists)); |
| 767 return; |
| 768 } |
| 769 |
| 770 characteristic->StartNotifySession( |
| 771 base::Bind(&BluetoothDispatcherHost::OnStartNotifySessionSuccess, |
| 772 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), |
| 773 base::Bind(&BluetoothDispatcherHost::OnStartNotifySessionFailed, |
| 774 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); |
| 775 } |
| 776 void BluetoothDispatcherHost::OnStopNotifications( |
| 777 int thread_id, |
| 778 int request_id, |
| 779 const std::string& characteristic_instance_id) { |
| 780 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 781 RecordWebBluetoothFunctionCall( |
| 782 UMAWebBluetoothFunction::CHARACTERISTIC_STOP_NOTIFICATIONS); |
| 783 |
| 784 auto notify_session_iter = |
| 785 characteristic_id_to_notify_session_.find(characteristic_instance_id); |
| 786 if (notify_session_iter == characteristic_id_to_notify_session_.end()) { |
| 787 Send(new BluetoothMsg_StopNotificationsSuccess(thread_id, request_id)); |
| 788 return; |
| 789 } |
| 790 notify_session_iter->second->Stop( |
| 791 base::Bind(&BluetoothDispatcherHost::OnStopNotifySession, |
| 792 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id, |
| 793 characteristic_instance_id)); |
| 794 } |
| 795 |
697 void BluetoothDispatcherHost::OnDiscoverySessionStarted( | 796 void BluetoothDispatcherHost::OnDiscoverySessionStarted( |
698 int chooser_id, | 797 int chooser_id, |
699 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { | 798 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { |
700 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 799 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
701 VLOG(1) << "Started discovery session for " << chooser_id; | 800 VLOG(1) << "Started discovery session for " << chooser_id; |
702 if (RequestDeviceSession* session = | 801 if (RequestDeviceSession* session = |
703 request_device_sessions_.Lookup(chooser_id)) { | 802 request_device_sessions_.Lookup(chooser_id)) { |
704 session->discovery_session = discovery_session.Pass(); | 803 session->discovery_session = discovery_session.Pass(); |
705 | 804 |
706 // Arrange to stop discovery later. | 805 // Arrange to stop discovery later. |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
921 void BluetoothDispatcherHost::OnWriteValueFailed( | 1020 void BluetoothDispatcherHost::OnWriteValueFailed( |
922 int thread_id, | 1021 int thread_id, |
923 int request_id, | 1022 int request_id, |
924 device::BluetoothGattService::GattErrorCode error_code) { | 1023 device::BluetoothGattService::GattErrorCode error_code) { |
925 // TranslateGATTError calls RecordGATTOperationOutcome. | 1024 // TranslateGATTError calls RecordGATTOperationOutcome. |
926 Send(new BluetoothMsg_WriteCharacteristicValueError( | 1025 Send(new BluetoothMsg_WriteCharacteristicValueError( |
927 thread_id, request_id, | 1026 thread_id, request_id, |
928 TranslateGATTError(error_code, UMAGATTOperation::CHARACTERISTIC_WRITE))); | 1027 TranslateGATTError(error_code, UMAGATTOperation::CHARACTERISTIC_WRITE))); |
929 } | 1028 } |
930 | 1029 |
| 1030 void BluetoothDispatcherHost::OnStartNotifySessionSuccess( |
| 1031 int thread_id, |
| 1032 int request_id, |
| 1033 scoped_ptr<device::BluetoothGattNotifySession> notify_session) { |
| 1034 RecordStartNotificationsOutcome(UMAGATTOperationOutcome::SUCCESS); |
| 1035 |
| 1036 characteristic_id_to_notify_session_.insert( |
| 1037 notify_session->GetCharacteristicIdentifier(), notify_session.Pass()); |
| 1038 Send(new BluetoothMsg_StartNotificationsSuccess(thread_id, request_id)); |
| 1039 } |
| 1040 |
| 1041 void BluetoothDispatcherHost::OnStartNotifySessionFailed( |
| 1042 int thread_id, |
| 1043 int request_id, |
| 1044 device::BluetoothGattService::GattErrorCode error_code) { |
| 1045 // TranslateGATTError calls RecordGATTOperationOutcome. |
| 1046 Send(new BluetoothMsg_StartNotificationsError( |
| 1047 thread_id, request_id, |
| 1048 TranslateGATTError(error_code, UMAGATTOperation::START_NOTIFICATIONS))); |
| 1049 } |
| 1050 |
| 1051 void BluetoothDispatcherHost::OnStopNotifySession( |
| 1052 int thread_id, |
| 1053 int request_id, |
| 1054 const std::string& characteristic_instance_id) { |
| 1055 characteristic_id_to_notify_session_.erase(characteristic_instance_id); |
| 1056 Send(new BluetoothMsg_StopNotificationsSuccess(thread_id, request_id)); |
| 1057 } |
| 1058 |
931 void BluetoothDispatcherHost::ShowBluetoothOverviewLink() { | 1059 void BluetoothDispatcherHost::ShowBluetoothOverviewLink() { |
932 NOTIMPLEMENTED(); | 1060 NOTIMPLEMENTED(); |
933 } | 1061 } |
934 | 1062 |
935 void BluetoothDispatcherHost::ShowBluetoothPairingLink() { | 1063 void BluetoothDispatcherHost::ShowBluetoothPairingLink() { |
936 NOTIMPLEMENTED(); | 1064 NOTIMPLEMENTED(); |
937 } | 1065 } |
938 | 1066 |
939 void BluetoothDispatcherHost::ShowBluetoothAdapterOffLink() { | 1067 void BluetoothDispatcherHost::ShowBluetoothAdapterOffLink() { |
940 NOTIMPLEMENTED(); | 1068 NOTIMPLEMENTED(); |
941 } | 1069 } |
942 | 1070 |
943 } // namespace content | 1071 } // namespace content |
OLD | NEW |