Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / device / bluetooth / bluetooth_discovery_manager_mac.mm
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.
4
5 #include "device/bluetooth/bluetooth_discovery_manager_mac.h"
6
7 #import <IOBluetooth/objc/IOBluetoothDevice.h>
8 #import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
9
10 #include "base/mac/scoped_nsobject.h"
11 #include "base/mac/sdk_forward_declarations.h"
12 #include "base/logging.h"
13
14 namespace device {
15
16 class BluetoothDiscoveryManagerMacClassic;
17
18 }  // namespace device
19
20 // IOBluetoothDeviceInquiryDelegate implementation.
21 @interface BluetoothDeviceInquiryDelegate
22     : NSObject<IOBluetoothDeviceInquiryDelegate> {
23  @private
24   device::BluetoothDiscoveryManagerMacClassic* manager_;  // weak
25 }
26
27 - (id)initWithManager:(device::BluetoothDiscoveryManagerMacClassic*)manager;
28
29 @end
30
31 namespace device {
32
33 // ementation of BluetoothDiscoveryManagerMac for Bluetooth classic device
34 // discovery, using the IOBluetooth framework.
35 class BluetoothDiscoveryManagerMacClassic
36     : public BluetoothDiscoveryManagerMac {
37  public:
38   explicit BluetoothDiscoveryManagerMacClassic(Observer* observer)
39       : BluetoothDiscoveryManagerMac(observer),
40         should_do_discovery_(false),
41         inquiry_running_(false),
42         inquiry_delegate_(
43             [[BluetoothDeviceInquiryDelegate alloc] initWithManager:this]),
44         inquiry_([[IOBluetoothDeviceInquiry alloc]
45             initWithDelegate:inquiry_delegate_]) {}
46
47   virtual ~BluetoothDiscoveryManagerMacClassic() {}
48
49   // BluetoothDiscoveryManagerMac override.
50   virtual bool IsDiscovering() const OVERRIDE { return should_do_discovery_; }
51
52   // BluetoothDiscoveryManagerMac override.
53   virtual bool StartDiscovery() OVERRIDE {
54     DVLOG(1) << "Bluetooth Classic: StartDiscovery";
55     DCHECK(!should_do_discovery_);
56
57     DVLOG(1) << "Discovery requested";
58     should_do_discovery_ = true;
59
60     if (inquiry_running_) {
61       DVLOG(1) << "Device inquiry already running";
62       return true;
63     }
64
65     DVLOG(1) << "Requesting to start device inquiry";
66     if ([inquiry_ start] != kIOReturnSuccess) {
67       DVLOG(1) << "Failed to start device inquiry";
68
69       // Set |should_do_discovery_| to false here. Since we're reporting an
70       // error, we're indicating that the adapter call StartDiscovery again
71       // if needed.
72       should_do_discovery_ = false;
73       return false;
74     }
75
76     DVLOG(1) << "Device inquiry start was successful";
77     return true;
78   }
79
80   // BluetoothDiscoveryManagerMac override.
81   virtual bool StopDiscovery() OVERRIDE {
82     DVLOG(1) << "Bluetooth Classic: StopDiscovery";
83     DCHECK(should_do_discovery_);
84
85     should_do_discovery_ = false;
86
87     if (!inquiry_running_) {
88       DVLOG(1) << "No device inquiry running; discovery stopped";
89       return true;
90     }
91
92     DVLOG(1) << "Requesting to stop device inquiry";
93     IOReturn status = [inquiry_ stop];
94     if (status == kIOReturnSuccess) {
95       DVLOG(1) << "Device inquiry stop was successful";
96       return true;
97     }
98
99     if (status == kIOReturnNotPermitted) {
100       DVLOG(1) << "Device inquiry was already stopped";
101       return true;
102     }
103
104     LOG(WARNING) << "Failed to stop device inquiry";
105     return false;
106   }
107
108   // Called by BluetoothDeviceInquiryDelegate.
109   void DeviceInquiryStarted(IOBluetoothDeviceInquiry* inquiry) {
110     DCHECK(!inquiry_running_);
111
112     DVLOG(1) << "Device inquiry started!";
113
114     // If discovery was requested to stop in the mean time, stop the inquiry.
115     if (!should_do_discovery_) {
116       DVLOG(1) << "Discovery stop was requested earlier. Stopping inquiry";
117       [inquiry stop];
118       return;
119     }
120
121     inquiry_running_ = true;
122   }
123
124   void DeviceFound(IOBluetoothDeviceInquiry* inquiry,
125                    IOBluetoothDevice* device) {
126     DCHECK(observer_);
127     observer_->DeviceFound(device);
128   }
129
130   void DeviceInquiryComplete(IOBluetoothDeviceInquiry* inquiry,
131                              IOReturn error,
132                              bool aborted) {
133     DCHECK_EQ(inquiry_, inquiry);
134     DCHECK(observer_);
135     DVLOG(1) << "Device inquiry complete";
136     inquiry_running_ = false;
137
138     // If discovery is no longer desired, notify observers that discovery
139     // has stopped and return.
140     if (!should_do_discovery_) {
141       observer_->DiscoveryStopped(false /* unexpected */);
142       return;
143     }
144
145     // If discovery has stopped due to an unexpected reason, notify the
146     // observers and return.
147     if (error != kIOReturnSuccess) {
148       DVLOG(1) << "Inquiry has stopped with an error: " << error;
149       should_do_discovery_ = false;
150       observer_->DiscoveryStopped(true /* unexpected */);
151       return;
152     }
153
154     DVLOG(1) << "Restarting device inquiry";
155
156     if ([inquiry_ start] == kIOReturnSuccess) {
157       DVLOG(1) << "Device inquiry restart was successful";
158       return;
159     }
160
161     DVLOG(1) << "Failed to restart discovery";
162     should_do_discovery_ = false;
163     DCHECK(observer_);
164     observer_->DiscoveryStopped(true /* unexpected */);
165   }
166
167  private:
168   // The requested discovery state.
169   bool should_do_discovery_;
170
171   // The current inquiry state.
172   bool inquiry_running_;
173
174   // Objective-C objects for running and tracking device inquiry.
175   base::scoped_nsobject<BluetoothDeviceInquiryDelegate> inquiry_delegate_;
176   base::scoped_nsobject<IOBluetoothDeviceInquiry> inquiry_;
177
178   DISALLOW_COPY_AND_ASSIGN(BluetoothDiscoveryManagerMacClassic);
179 };
180
181 BluetoothDiscoveryManagerMac::BluetoothDiscoveryManagerMac(
182     Observer* observer) : observer_(observer) {
183   DCHECK(observer);
184 }
185
186 BluetoothDiscoveryManagerMac::~BluetoothDiscoveryManagerMac() {
187 }
188
189 // static
190 BluetoothDiscoveryManagerMac* BluetoothDiscoveryManagerMac::CreateClassic(
191     Observer* observer) {
192   return new BluetoothDiscoveryManagerMacClassic(observer);
193 }
194
195 }  // namespace device
196
197 @implementation BluetoothDeviceInquiryDelegate
198
199 - (id)initWithManager:
200           (device::BluetoothDiscoveryManagerMacClassic*)manager {
201   if ((self = [super init]))
202     manager_ = manager;
203
204   return self;
205 }
206
207 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender {
208   manager_->DeviceInquiryStarted(sender);
209 }
210
211 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
212                           device:(IOBluetoothDevice*)device {
213   manager_->DeviceFound(sender, device);
214 }
215
216 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
217                         error:(IOReturn)error
218                       aborted:(BOOL)aborted {
219   manager_->DeviceInquiryComplete(sender, error, aborted);
220 }
221
222 @end