|
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: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "btdevicemodel_p.h" |
|
19 #include <QDateTime> |
|
20 #include <btservices/advancedevdiscoverer.h> |
|
21 #include <btengconnman.h> |
|
22 #include "btuiutil.h" |
|
23 #include "btuidevtypemap.h" |
|
24 #include "btqtconstants.h" |
|
25 |
|
26 /*! |
|
27 Constructor. |
|
28 */ |
|
29 BtDeviceModelPrivate::BtDeviceModelPrivate( BtDeviceModel& model, QObject *parent ) |
|
30 : QObject( parent ), mModel( model ), mDiscover( 0 ), mSeqNum( 0 ) |
|
31 { |
|
32 mDeviceRepo = 0; |
|
33 isSearchingDevice = false; |
|
34 TRAP_IGNORE({ |
|
35 mDeviceRepo = CBtDevRepository::NewL(); |
|
36 }); |
|
37 Q_CHECK_PTR( mDeviceRepo ); |
|
38 TRAP_IGNORE( mDeviceRepo->AddObserverL( this ) ); |
|
39 |
|
40 if ( mDeviceRepo->IsInitialized() ) { |
|
41 initializeDataStore(); |
|
42 } |
|
43 } |
|
44 |
|
45 /*! |
|
46 Destructor. |
|
47 */ |
|
48 BtDeviceModelPrivate::~BtDeviceModelPrivate() |
|
49 { |
|
50 delete mDeviceRepo; |
|
51 delete mDiscover; |
|
52 } |
|
53 |
|
54 |
|
55 /*! |
|
56 Tells whether the given column is in the range of the setting list. |
|
57 |
|
58 \param row the row number to be checked |
|
59 \param col the column number to be checked |
|
60 |
|
61 \return true if the given row and column are valid; false otherwise. |
|
62 */ |
|
63 bool BtDeviceModelPrivate::isValid( int row, int column) const |
|
64 { |
|
65 return row >= 0 && row < mData.count() && column == 0; |
|
66 } |
|
67 |
|
68 /*! |
|
69 \return the total amount of rows. |
|
70 |
|
71 */ |
|
72 int BtDeviceModelPrivate::rowCount() const |
|
73 { |
|
74 return mData.count(); |
|
75 } |
|
76 |
|
77 /*! |
|
78 \return the total amount of columns. |
|
79 |
|
80 */ |
|
81 int BtDeviceModelPrivate::columnCount() const |
|
82 { |
|
83 return 1; |
|
84 } |
|
85 |
|
86 /*! |
|
87 Gets the value within a data item. |
|
88 \param val contains the value at return. |
|
89 \param row the row number which the value is from |
|
90 \param col the column number which the value is from |
|
91 \param role the role identifier of the value. |
|
92 */ |
|
93 void BtDeviceModelPrivate::data(QVariant& val, int row, int col, int role ) const |
|
94 { |
|
95 if ( isValid( row, col ) ) { |
|
96 val = mData.at( row ).value( role ); |
|
97 } |
|
98 else { |
|
99 val = QVariant( QVariant::Invalid ); |
|
100 } |
|
101 } |
|
102 |
|
103 /*! |
|
104 Gets the whole item data at the specified column |
|
105 \param row the row number of the item data to be returned |
|
106 \param col the column number of the item data to be returned |
|
107 \return the item data |
|
108 */ |
|
109 BtuiModelDataItem BtDeviceModelPrivate::itemData( int row, int col ) const |
|
110 { |
|
111 if ( isValid( row, col ) ) { |
|
112 return mData.at( row ); |
|
113 } |
|
114 return BtuiModelDataItem(); |
|
115 } |
|
116 |
|
117 |
|
118 /*! |
|
119 Requests the model to searching Bluetooth devices. |
|
120 \return true if the request is accepted; false otherwise |
|
121 */ |
|
122 bool BtDeviceModelPrivate::searchDevice() |
|
123 { |
|
124 int err ( 0 ); |
|
125 removeTransientDevices(); |
|
126 if ( !mDiscover ) { |
|
127 TRAP(err, mDiscover = CAdvanceDevDiscoverer::NewL( *mDeviceRepo, *this) ); |
|
128 } |
|
129 if ( !err ) { |
|
130 TRAP(err, mDiscover->DiscoverDeviceL() ); |
|
131 } |
|
132 isSearchingDevice = true; |
|
133 return err == 0; |
|
134 } |
|
135 |
|
136 /*! |
|
137 Cancels a possible outstanding device search request. |
|
138 */ |
|
139 void BtDeviceModelPrivate::cancelSearchDevice() |
|
140 { |
|
141 if ( mDiscover ) { |
|
142 isSearchingDevice = false; |
|
143 mDiscover->CancelDiscovery(); |
|
144 } |
|
145 } |
|
146 |
|
147 /*! |
|
148 Removes transient (not-in-registry) devices |
|
149 (added as the result of device search). |
|
150 */ |
|
151 void BtDeviceModelPrivate::removeTransientDevices() |
|
152 { |
|
153 // clear in-range property for all device items in this model. |
|
154 int cnt = mData.count(); |
|
155 for ( int i = mData.count() - 1; i > -1; --i) |
|
156 { |
|
157 const BtuiModelDataItem& qtdev = mData.at(i); |
|
158 if(isDeviceInRange(qtdev)) { |
|
159 if(isDeviceInRegistry(qtdev)) { |
|
160 // we cannot remove this device as it is in registry. |
|
161 // remove it in-range property. |
|
162 setMajorProperty(mData[i], BtuiDevProperty::InRange, false); |
|
163 updateRssi(mData[i], RssiInvalid); |
|
164 updateSeqNum(mData[i], -1); |
|
165 emit deviceDataChanged(i, this); |
|
166 } |
|
167 else { |
|
168 // this device is not in-registry. Delete it from local |
|
169 // store. |
|
170 emit beginRemoveDevices(i, i, this); |
|
171 mData.removeAt( i ); |
|
172 emit endRemoveDevices(); |
|
173 } |
|
174 } |
|
175 } |
|
176 } |
|
177 |
|
178 /*! |
|
179 callback from repository. |
|
180 re-initialize our store. |
|
181 */ |
|
182 void BtDeviceModelPrivate::RepositoryInitialized() |
|
183 { |
|
184 initializeDataStore(); |
|
185 } |
|
186 |
|
187 /*! |
|
188 callback from repository. |
|
189 update our store. |
|
190 */ |
|
191 void BtDeviceModelPrivate::DeletedFromRegistry( const TBTDevAddr& addr ) |
|
192 { |
|
193 int i = indexOf( addr ); |
|
194 if ( i > -1 ) { |
|
195 if ( isSearchingDevice && isDeviceInRange( mData.at(i) ) ) { |
|
196 // device searching is ongoing, and it is in-range. we can not |
|
197 // remove it from model now. |
|
198 // clear-registry related properties, so that |
|
199 // we get a chance to clean it after device searching later. |
|
200 setMajorProperty(mData[i], BtuiDevProperty::RegistryProperties, false); |
|
201 emit deviceDataChanged(i, this); |
|
202 } |
|
203 else { |
|
204 emit beginRemoveDevices(i, i, this); |
|
205 mData.removeAt( i ); |
|
206 emit endRemoveDevices(); |
|
207 } |
|
208 } |
|
209 } |
|
210 |
|
211 /*! |
|
212 callback from repository. |
|
213 update our store. |
|
214 */ |
|
215 void BtDeviceModelPrivate::AddedToRegistry( const CBtDevExtension& dev ) |
|
216 { |
|
217 ChangedInRegistry( dev, 0 ); |
|
218 } |
|
219 |
|
220 /*! |
|
221 callback from repository. |
|
222 update our store. |
|
223 */ |
|
224 void BtDeviceModelPrivate::ChangedInRegistry( |
|
225 const CBtDevExtension& dev, TUint similarity ) |
|
226 { |
|
227 int i = indexOf( dev.Addr() ); |
|
228 if ( i == -1 ) { |
|
229 BtuiModelDataItem devData; |
|
230 if ( !isSearchingDevice ) { |
|
231 // Rssi is only available at device inquiry stage. |
|
232 // We initialize this property to an invalid value |
|
233 updateRssi(devData, RssiInvalid); |
|
234 } |
|
235 // add device-in-registry property: |
|
236 setMajorProperty(devData, BtuiDevProperty::InRegistry, true); |
|
237 updateDeviceProperty(devData, dev, 0 ); |
|
238 emit beginInsertDevices( mData.count(), mData.count(), this ); |
|
239 mData.append( devData ); |
|
240 emit endInsertDevices(); |
|
241 } |
|
242 else { |
|
243 updateDeviceProperty(mData[i], dev, similarity ); |
|
244 setMajorProperty(mData[i], BtuiDevProperty::InRegistry, true); |
|
245 emit deviceDataChanged( i, this ); |
|
246 } |
|
247 } |
|
248 |
|
249 /*! |
|
250 callback from repository. |
|
251 update our store. |
|
252 */ |
|
253 void BtDeviceModelPrivate::ServiceConnectionChanged( |
|
254 const CBtDevExtension& dev, TBool connected ) |
|
255 { |
|
256 int i = indexOf( dev.Addr() ); |
|
257 if ( i > -1 ) { |
|
258 int preconn = BtuiDevProperty::Connected |
|
259 & mData[i][BtDeviceModel::MajorPropertyRole].toInt(); |
|
260 // we only update and signal if connection status is really |
|
261 // changed: |
|
262 if ( ( preconn != 0 && !connected ) |
|
263 || ( preconn == 0 && connected ) ) { |
|
264 setMajorProperty(mData[i], BtuiDevProperty::Connected, connected ); |
|
265 emit deviceDataChanged( i, this ); |
|
266 } |
|
267 } |
|
268 // it is impossible that a device has connected but it is not in |
|
269 // our local store according to current bteng services. |
|
270 // need to take more care in future when this becomes possible. |
|
271 } |
|
272 |
|
273 /*! |
|
274 callback from device search. |
|
275 update our store. |
|
276 */ |
|
277 void BtDeviceModelPrivate::HandleNextDiscoveryResultL( |
|
278 const TInquirySockAddr& inqAddr, const TDesC& name ) |
|
279 { |
|
280 int pos = indexOf( inqAddr.BTAddr() ); |
|
281 const CBtDevExtension* dev = mDeviceRepo->Device( inqAddr.BTAddr() ); |
|
282 |
|
283 //RssiRole |
|
284 int rssi( RssiInvalid ); // initialize to an invalid value. |
|
285 if( inqAddr.ResultFlags() & TInquirySockAddr::ERssiValid ) { |
|
286 rssi = inqAddr.Rssi(); |
|
287 } |
|
288 |
|
289 if ( pos == -1 ) { |
|
290 BtuiModelDataItem devData; |
|
291 setMajorProperty(devData, BtuiDevProperty::InRange, true); |
|
292 updateRssi(devData, rssi); |
|
293 updateSeqNum( devData, mSeqNum++ ); |
|
294 CBtDevExtension* devExt(NULL); |
|
295 TRAP_IGNORE( { |
|
296 devExt = CBtDevExtension::NewLC( inqAddr, name ); |
|
297 CleanupStack::Pop(); }); |
|
298 updateDeviceProperty(devData, *devExt, 0); |
|
299 delete devExt; |
|
300 emit beginInsertDevices( mData.count(), mData.count(), this ); |
|
301 mData.append( devData ); |
|
302 emit endInsertDevices(); |
|
303 } |
|
304 else { |
|
305 setMajorProperty(mData[pos], BtuiDevProperty::InRange, true); |
|
306 updateRssi(mData[pos], rssi); |
|
307 updateSeqNum( mData[pos], mSeqNum++ ); |
|
308 emit deviceDataChanged( pos, this ); |
|
309 } |
|
310 } |
|
311 |
|
312 /*! |
|
313 callback from device search. |
|
314 inform client. |
|
315 */ |
|
316 void BtDeviceModelPrivate::HandleDiscoveryCompleted( TInt error ) |
|
317 { |
|
318 isSearchingDevice = false; |
|
319 // Reset the sequence number for the next search |
|
320 mSeqNum = 0; |
|
321 emit deviceSearchCompleted( (int) error ); |
|
322 } |
|
323 |
|
324 void BtDeviceModelPrivate::initializeDataStore() |
|
325 { |
|
326 |
|
327 mSeqNum = 0; // reset when starting search again |
|
328 |
|
329 // it is possible that we are searching devices. |
|
330 // We use a simple but not-so-efficient method to update the model. |
|
331 |
|
332 // If the device store is not empty, we clear |
|
333 // registry property from these devices first. |
|
334 for (int i = 0; i < mData.count(); ++i) { |
|
335 setMajorProperty(mData[i], BtuiDevProperty::RegistryProperties, false); |
|
336 } |
|
337 if ( mData.count() ) { |
|
338 // need to update view because we have changed device properties. |
|
339 emit deviceDataChanged( 0, mData.count() - 1, this ); |
|
340 } |
|
341 |
|
342 const RDevExtensionArray& devs = mDeviceRepo->AllDevices(); |
|
343 for (int i = 0; i < devs.Count(); ++i) { |
|
344 int pos = indexOf( devs[i]->Addr() ); |
|
345 if ( pos > -1 ) { |
|
346 // add device-in-registry property: |
|
347 setMajorProperty(mData[pos], BtuiDevProperty::InRegistry, true); |
|
348 updateDeviceProperty(mData[pos], *(devs[i]), 0); |
|
349 updateSeqNum(mData[pos], -1); |
|
350 emit deviceDataChanged( pos, this ); |
|
351 } |
|
352 else { |
|
353 BtuiModelDataItem devData; |
|
354 // add device-in-registry property: |
|
355 setMajorProperty(devData, BtuiDevProperty::InRegistry, true); |
|
356 updateDeviceProperty(devData, *( devs[i] ), 0 ); |
|
357 updateSeqNum(devData, -1); |
|
358 emit beginInsertDevices(mData.count(), mData.count(), this ); |
|
359 mData.append( devData ); |
|
360 emit endInsertDevices(); |
|
361 } |
|
362 } |
|
363 } |
|
364 |
|
365 void BtDeviceModelPrivate::updateDeviceProperty(BtuiModelDataItem& qtdev, |
|
366 const CBtDevExtension& dev, TUint similarity ) |
|
367 { |
|
368 // similarity is not used currently. |
|
369 // It is possible to gain better performance |
|
370 // with this info to avoid re-manipulate |
|
371 // unchanged properties. |
|
372 Q_UNUSED(similarity); |
|
373 |
|
374 //DevDisplayNameRole |
|
375 QString str = QString::fromUtf16( |
|
376 dev.Alias().Ptr(), dev.Alias().Length() ); |
|
377 qtdev[BtDeviceModel::NameAliasRole] = QVariant( str ); |
|
378 |
|
379 //DevAddrReadableRole |
|
380 addrSymbianToReadbleString( str, dev.Addr() ); |
|
381 qtdev[BtDeviceModel::ReadableBdaddrRole] = QVariant( str ); |
|
382 |
|
383 //LastUsedTimeRole |
|
384 TDateTime symDt = dev.Device().Used().DateTime(); |
|
385 QDate date( symDt.Year(), symDt.Month(), symDt.Day() ); |
|
386 QTime time( symDt.Hour(), symDt.Minute(), symDt.MicroSecond() / 1000 ); |
|
387 QDateTime qdt(date, time); |
|
388 qtdev[BtDeviceModel::LastUsedTimeRole] = QVariant(qdt); |
|
389 |
|
390 // set paired status: |
|
391 setMajorProperty(qtdev, BtuiDevProperty::Bonded, isBonded( dev.Device() )); |
|
392 |
|
393 // set blocked status: |
|
394 setMajorProperty(qtdev, BtuiDevProperty::Blocked, |
|
395 dev.Device().GlobalSecurity().Banned() ); |
|
396 // set trusted status: |
|
397 setMajorProperty(qtdev, BtuiDevProperty::Trusted, |
|
398 dev.Device().GlobalSecurity().NoAuthorise() ); |
|
399 // set connected status: |
|
400 // EBTEngConnecting is an intermediate state between connected and not-connected, |
|
401 // we do not treat it as connected: |
|
402 setMajorProperty(qtdev, BtuiDevProperty::Connected, dev.ServiceConnectionStatus() == EBTEngConnected); |
|
403 |
|
404 // Check whether the device has services that are connectable in bteng scope. |
|
405 CBTEngConnMan* connMan( 0 ); |
|
406 TRAP_IGNORE( connMan = CBTEngConnMan::NewL(0)); |
|
407 TBool connectable(EFalse); |
|
408 if ( connMan ) { |
|
409 (void) connMan->IsConnectable(dev.Addr(), dev.Device().DeviceClass(), connectable); |
|
410 delete connMan; |
|
411 } |
|
412 setMajorProperty(qtdev, BtuiDevProperty::Connectable, connectable); |
|
413 |
|
414 int cod = static_cast<int>( dev.Device().DeviceClass().DeviceClass() ); |
|
415 qtdev[BtDeviceModel::CoDRole] = QVariant(cod); |
|
416 |
|
417 int majorDeviceType; |
|
418 int minorDeviceType; |
|
419 // device type is mapped according to CoD: |
|
420 BtuiDevProperty::mapDeiveType(majorDeviceType, minorDeviceType, cod); |
|
421 |
|
422 |
|
423 |
|
424 |
|
425 qtdev[BtDeviceModel::MajorPropertyRole] = |
|
426 QVariant( qtdev[BtDeviceModel::MajorPropertyRole].toInt() | majorDeviceType ); |
|
427 qtdev[BtDeviceModel::MinorPropertyRole] = QVariant( minorDeviceType ); |
|
428 } |
|
429 |
|
430 int BtDeviceModelPrivate::indexOf( const TBTDevAddr& addr ) const |
|
431 { |
|
432 QString addrStr; |
|
433 addrSymbianToReadbleString( addrStr, addr ); |
|
434 for (int i = 0; i < mData.count(); ++i ) { |
|
435 if ( mData.at( i ).value( BtDeviceModel::ReadableBdaddrRole ) |
|
436 == addrStr ) { |
|
437 return i; |
|
438 } |
|
439 } |
|
440 return -1; |
|
441 } |
|
442 |
|
443 void BtDeviceModelPrivate::updateRssi(BtuiModelDataItem& qtdev, int rssi ) |
|
444 { |
|
445 qtdev[BtDeviceModel::RssiRole] = QVariant( rssi ); |
|
446 } |
|
447 |
|
448 void BtDeviceModelPrivate::updateSeqNum(BtuiModelDataItem& qtdev, int seqNum ) |
|
449 { |
|
450 qtdev[BtDeviceModel::SeqNumRole] = QVariant( seqNum ); |
|
451 } |
|
452 |
|
453 /*! |
|
454 Add the specified major property to the device if addto is true. |
|
455 Otherwise the property is removed from the device. |
|
456 */ |
|
457 void BtDeviceModelPrivate::setMajorProperty( |
|
458 BtuiModelDataItem& qtdev, int prop, bool addto) |
|
459 { |
|
460 if ( addto ) { |
|
461 qtdev[BtDeviceModel::MajorPropertyRole] = |
|
462 QVariant( qtdev[BtDeviceModel::MajorPropertyRole].toInt() | prop); |
|
463 } |
|
464 else { |
|
465 qtdev[BtDeviceModel::MajorPropertyRole] = |
|
466 QVariant( qtdev[BtDeviceModel::MajorPropertyRole].toInt() & ~prop); |
|
467 } |
|
468 } |
|
469 |
|
470 bool BtDeviceModelPrivate::isDeviceInRange( const BtuiModelDataItem& qtdev ) |
|
471 { |
|
472 return BtuiDevProperty::InRange & qtdev[BtDeviceModel::MajorPropertyRole].toInt(); |
|
473 } |
|
474 |
|
475 bool BtDeviceModelPrivate::isDeviceInRegistry( const BtuiModelDataItem& qtdev ) |
|
476 { |
|
477 return BtuiDevProperty::InRegistry & qtdev[BtDeviceModel::MajorPropertyRole].toInt(); |
|
478 } |