1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: class for searching BT devices |
|
15 * |
|
16 */ |
|
17 #include "basicdevdiscoverer.h" |
|
18 #include <btservices/devdiscoveryobserver.h> |
|
19 #include "btserviceutilconsts.h" |
|
20 |
|
21 // ---------------------------------------------------------- |
|
22 // CBasicDevDiscoverer::CBasicDevDiscoverer |
|
23 // ---------------------------------------------------------- |
|
24 // |
|
25 CBasicDevDiscoverer::CBasicDevDiscoverer( MDevDiscoveryObserver& aObserver ) |
|
26 : iObserver( aObserver ) |
|
27 { |
|
28 } |
|
29 |
|
30 // ---------------------------------------------------------- |
|
31 // CBasicDevDiscoverer::ConstructL |
|
32 // ---------------------------------------------------------- |
|
33 // |
|
34 void CBasicDevDiscoverer::ConstructL() |
|
35 { |
|
36 User::LeaveIfError( iSocketServer.Connect() ); |
|
37 iActive = CBtSimpleActive::NewL( *this, BtServiceUtil::EBluetoothInquiry ); |
|
38 } |
|
39 |
|
40 // ---------------------------------------------------------- |
|
41 // CBasicDevDiscoverer::NewL |
|
42 // ---------------------------------------------------------- |
|
43 // |
|
44 CBasicDevDiscoverer* CBasicDevDiscoverer::NewL( MDevDiscoveryObserver& aObserver ) |
|
45 { |
|
46 CBasicDevDiscoverer* self = new (ELeave) |
|
47 CBasicDevDiscoverer( aObserver ); |
|
48 CleanupStack::PushL( self ); |
|
49 self->ConstructL(); |
|
50 CleanupStack::Pop( self ); |
|
51 return self; |
|
52 } |
|
53 |
|
54 // ---------------------------------------------------------- |
|
55 // CBasicDevDiscoverer:: |
|
56 // ---------------------------------------------------------- |
|
57 // |
|
58 CBasicDevDiscoverer::~CBasicDevDiscoverer() |
|
59 { |
|
60 delete iActive; |
|
61 Reset(); |
|
62 iSocketServer.Close(); |
|
63 iDevices.Close(); |
|
64 } |
|
65 |
|
66 // ---------------------------------------------------------- |
|
67 // CBasicDevDiscoverer::SetObserver |
|
68 // ---------------------------------------------------------- |
|
69 // |
|
70 void CBasicDevDiscoverer::SetObserver( MDevDiscoveryObserver& aObserver ) |
|
71 { |
|
72 iObserver = aObserver; |
|
73 } |
|
74 |
|
75 // ---------------------------------------------------------- |
|
76 // CBasicDevDiscoverer:: |
|
77 // ---------------------------------------------------------- |
|
78 // |
|
79 void CBasicDevDiscoverer::Cancel() |
|
80 { |
|
81 iActive->Cancel(); |
|
82 iHostResolver.Close(); |
|
83 iDevices.ResetAndDestroy(); |
|
84 } |
|
85 |
|
86 // ---------------------------------------------------------- |
|
87 // CBasicDevDiscoverer:: |
|
88 // ---------------------------------------------------------- |
|
89 // |
|
90 void CBasicDevDiscoverer::DiscoverDeviceL(TBTMajorDeviceClass aDeviceClass ) |
|
91 { |
|
92 // This class supports only one request at the time: |
|
93 if ( iActive->IsActive() ) |
|
94 { |
|
95 User::Leave( KErrInUse ); |
|
96 } |
|
97 Reset(); |
|
98 iMajorDeviceClassFilter = aDeviceClass; |
|
99 _LIT( KLinkMgrDes, "BTLinkManager" ); |
|
100 // Associate with bluetooth Link Manager. |
|
101 TProtocolName protocol( KLinkMgrDes ); |
|
102 TProtocolDesc pInfo; |
|
103 User::LeaveIfError( iSocketServer.FindProtocol( protocol, pInfo)); |
|
104 User::LeaveIfError( iHostResolver.Open(iSocketServer, |
|
105 pInfo.iAddrFamily, pInfo.iProtocol)); |
|
106 iActive->SetRequestId( BtServiceUtil::EBluetoothInquiry ); |
|
107 iInquirySockAddr.SetAction( KHostResInquiry + KHostResEir + KHostResIgnoreCache ); |
|
108 // We always do Generic Inquiry. |
|
109 // Limited Inquiry could be added here in future on business need. |
|
110 iInquirySockAddr.SetIAC(KGIAC); |
|
111 iHostResolver.GetByAddress( iInquirySockAddr, iEntry, iActive->RequestStatus() ); |
|
112 iActive->GoActive(); |
|
113 } |
|
114 |
|
115 // ---------------------------------------------------------- |
|
116 // CBasicDevDiscoverer::RequestCompletedL |
|
117 // Inform caller for received device and issue next EIR/Name request |
|
118 // if the request was successful. |
|
119 // ---------------------------------------------------------- |
|
120 // |
|
121 void CBasicDevDiscoverer::RequestCompletedL( CBtSimpleActive* aActive, TInt aStatus ) |
|
122 { |
|
123 TInt errToObserver( aStatus ); |
|
124 // position in array iDevices: the device item the observer will be notified of. |
|
125 TInt devToNotify ( KErrNotFound ); |
|
126 |
|
127 if ( aActive->RequestId() == BtServiceUtil::EBluetoothInquiry ) |
|
128 { |
|
129 if ( aStatus == KErrNone ) |
|
130 { |
|
131 TInt pos = HandleInquiryResultL(); |
|
132 // continue to inquiry for more devices in range |
|
133 iHostResolver.Next( iEntry, iActive->RequestStatus() ); |
|
134 iActive->GoActive(); |
|
135 if ( pos > KErrNotFound && iDevices[pos]->iName.Length() > 0 ) |
|
136 { |
|
137 devToNotify = pos; |
|
138 } |
|
139 } |
|
140 else if( iDevices.Count() > 0 ) |
|
141 { |
|
142 // an error from inquiry operation. |
|
143 // we move to next step to get device names if some devices have been |
|
144 // found but without a name. |
|
145 iPagingNamePos = iDevices.Count() - 1; |
|
146 aActive->SetRequestId( BtServiceUtil::EBluetoothPageDeviceName ); |
|
147 PageNextDeviceName(); |
|
148 } |
|
149 } |
|
150 else if ( aActive->RequestId() == BtServiceUtil::EBluetoothPageDeviceName ) |
|
151 { |
|
152 errToObserver = KErrNone; |
|
153 devToNotify = iPagingNamePos; |
|
154 // the name in iEntry was reset before paging operation, so we |
|
155 // can rely on this length() at this time: |
|
156 if ( aStatus == KErrNone && iEntry().iName.Length() > 0 ) |
|
157 { |
|
158 iDevices[iPagingNamePos]->iName = iEntry().iName; |
|
159 } |
|
160 // the return error is not checked here. We continue to page the rest |
|
161 // device names. |
|
162 --iPagingNamePos; |
|
163 PageNextDeviceName(); |
|
164 } |
|
165 // request ID is BtServiceUtil::EAsyncNotifyDeviceSearchCompleted |
|
166 else |
|
167 { |
|
168 iObserver.HandleDiscoveryCompleted( errToObserver ); |
|
169 return; |
|
170 } |
|
171 |
|
172 // AO not active means that this is neither inquiring nor paging name. |
|
173 // Schedule an operation completion callback: |
|
174 if ( !iActive->IsActive() && |
|
175 aActive->RequestId() != BtServiceUtil::EAsyncNotifyDeviceSearchCompleted ) |
|
176 { |
|
177 // We inform the client of operation completion asynchronously, so that |
|
178 // we will not end up with problems, e.g., invalid memory, |
|
179 // if the client issues more request in the callback context. |
|
180 aActive->SetRequestId( BtServiceUtil::EAsyncNotifyDeviceSearchCompleted ); |
|
181 aActive->RequestStatus() = KRequestPending; |
|
182 TRequestStatus* sta = &aActive->RequestStatus(); |
|
183 User::RequestComplete( sta, errToObserver ); |
|
184 aActive->GoActive(); |
|
185 } |
|
186 |
|
187 // This could be possible in both inquiry and paging operations. |
|
188 if ( devToNotify > KErrNotFound ) |
|
189 { |
|
190 // This device record is not used any more after we have informed client. |
|
191 // Extract it and push to cleanup for detroy. |
|
192 // This is to prevent peak memory usage in case of a great number of |
|
193 // devices being in range. |
|
194 CDeviceSearchRecord* rec = iDevices[devToNotify]; |
|
195 iDevices.Remove( devToNotify ); |
|
196 CleanupStack::PushL( rec ); |
|
197 iObserver.HandleNextDiscoveryResultL( rec->iAddr, rec->iName ); |
|
198 CleanupStack::PopAndDestroy( rec ); |
|
199 } |
|
200 } |
|
201 |
|
202 // ---------------------------------------------------------- |
|
203 // CBasicDevDiscoverer::DoCancelRequest |
|
204 // ---------------------------------------------------------- |
|
205 // |
|
206 void CBasicDevDiscoverer::CancelRequest( TInt aId ) |
|
207 { |
|
208 // host resolver needs to be cancelled. |
|
209 // For request BtServiceUtil::EAsyncNotifyDeviceSearchCompleted, we |
|
210 // are doing self-completing. Thus, nothing is needed now. |
|
211 if ( aId == BtServiceUtil::EBluetoothInquiry || |
|
212 aId == BtServiceUtil::EBluetoothPageDeviceName ) |
|
213 { |
|
214 iHostResolver.Cancel(); |
|
215 } |
|
216 } |
|
217 |
|
218 // ---------------------------------------------------------- |
|
219 // CBasicDevDiscoverer::HandleError |
|
220 // Inform UI from error occured. |
|
221 // ---------------------------------------------------------- |
|
222 // |
|
223 void CBasicDevDiscoverer::HandleError( CBtSimpleActive* aActive, TInt aError ) |
|
224 { |
|
225 // We might have issued an request to Host Resolver in RequestCompleted(). |
|
226 // Cancel AO just in case: |
|
227 aActive->Cancel(); |
|
228 Reset(); |
|
229 // We cannot proceed more. Inform client: |
|
230 iObserver.HandleDiscoveryCompleted( aError ); |
|
231 } |
|
232 |
|
233 // ---------------------------------------------------------- |
|
234 // CBasicDevDiscoverer:: |
|
235 // ---------------------------------------------------------- |
|
236 // |
|
237 void CBasicDevDiscoverer::PageNextDeviceName() |
|
238 { |
|
239 // reset the name in entry so that previous result will |
|
240 // not propogate if the next paging operation fails. |
|
241 iEntry().iName.Zero(); |
|
242 for (; iPagingNamePos > -1; --iPagingNamePos ) |
|
243 { |
|
244 // Get the next in-range device that has no device name yet |
|
245 // This is practically meaning that the device would be |
|
246 // < v2.1 |
|
247 if( iDevices[iPagingNamePos]->iName.Length() == 0 ) |
|
248 { |
|
249 iInquirySockAddr.SetAction( KHostResName + KHostResIgnoreCache ); |
|
250 TBTDevAddr btaddr = iDevices[iPagingNamePos]->iAddr.BTAddr(); |
|
251 iInquirySockAddr.SetBTAddr( iDevices[iPagingNamePos]->iAddr.BTAddr() ); |
|
252 iInquirySockAddr.SetIAC(KGIAC); |
|
253 iHostResolver.GetByAddress( iInquirySockAddr, iEntry, iActive->RequestStatus() ); |
|
254 iActive->GoActive(); |
|
255 break; |
|
256 } |
|
257 } |
|
258 } |
|
259 |
|
260 // ---------------------------------------------------------- |
|
261 // CBasicDevDiscoverer::HandleInquiryResultL |
|
262 // Inform of properties of the found BTdevice, |
|
263 // which passes the search filter. Its name would be retrived |
|
264 // later if not contained by the first round of inquiry. |
|
265 // ---------------------------------------------------------- |
|
266 // |
|
267 TInt CBasicDevDiscoverer::HandleInquiryResultL() |
|
268 { |
|
269 TInquirySockAddr& sa = TInquirySockAddr::Cast( iEntry().iAddr ); |
|
270 // parse the inquiry result if this device passes the filters: |
|
271 if ( iMajorDeviceClassFilter == EMajorDeviceMisc |
|
272 || sa.MajorClassOfDevice() == iMajorDeviceClassFilter ) |
|
273 { |
|
274 CDeviceSearchRecord* record = NewInstanceL( sa ); |
|
275 CleanupStack::PushL( record ); |
|
276 iDevices.InsertL(record, 0 ); |
|
277 CleanupStack::Pop( record ); |
|
278 |
|
279 TBTDeviceName devName; |
|
280 TBluetoothNameRecordWrapper eir( iEntry() ); |
|
281 TInt length = eir.GetDeviceNameLength(); |
|
282 TBool isComplete( EFalse ); |
|
283 if( length > 0 ) |
|
284 { |
|
285 User::LeaveIfError( eir.GetDeviceName( record->iName, isComplete) ); |
|
286 } |
|
287 return 0; |
|
288 } |
|
289 return KErrNotFound; |
|
290 } |
|
291 |
|
292 // ---------------------------------------------------------- |
|
293 // CBasicDevDiscoverer::CompleteDiscovery |
|
294 // ---------------------------------------------------------- |
|
295 // |
|
296 CDeviceSearchRecord* CBasicDevDiscoverer::NewInstanceL( |
|
297 const TInquirySockAddr& aAddr, const TDesC& aName ) |
|
298 { |
|
299 CDeviceSearchRecord* record = new (ELeave) CDeviceSearchRecord(); |
|
300 record->iAddr = aAddr; |
|
301 record->iName = aName; |
|
302 return record; |
|
303 } |
|
304 |
|
305 // ---------------------------------------------------------- |
|
306 // CBasicDevDiscoverer::Reset |
|
307 // ---------------------------------------------------------- |
|
308 // |
|
309 void CBasicDevDiscoverer::Reset() |
|
310 { |
|
311 // Free the cache of host Resolver. |
|
312 iHostResolver.Close(); |
|
313 // Clean previous in-range devices whose proximity status |
|
314 // may have been changed. |
|
315 iDevices.ResetAndDestroy(); |
|
316 } |
|
317 |
|
318 // End of File |
|