|
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: Easy dialing plugin. |
|
15 * |
|
16 */ |
|
17 |
|
18 // INCLUDE FILES |
|
19 |
|
20 #include "easydialingplugin.h" |
|
21 #include "easydialinglistbox.h" |
|
22 #include "easydialinglogger.h" |
|
23 #include "easydialingpanics.h" |
|
24 #include "easydialingcenreplistener.h" |
|
25 #include "easydialingcontactdatamanager.h" |
|
26 #include "easydialingutils.h" |
|
27 #include <easydialingpluginresources.rsg> |
|
28 |
|
29 // AVKON and drawing header files |
|
30 #include <gdi.h> |
|
31 #include <aknlists.h> |
|
32 #include <AknUtils.h> |
|
33 #include <e32cmn.h> |
|
34 #include <bidivisual.h> |
|
35 |
|
36 // Predictive search header files |
|
37 #include <CPsSettings.h> |
|
38 #include <CPsQuery.h> |
|
39 #include <CPsQueryItem.h> |
|
40 #include <CPsClientData.h> |
|
41 #include <CPsPattern.h> |
|
42 #include <CPsRequestHandler.h> |
|
43 |
|
44 // Virtual phonebook header files |
|
45 #include <VPbkContactStoreUris.h> |
|
46 #include <CVPbkContactStoreUriArray.h> |
|
47 #include <TVPbkContactStoreUriPtr.h> |
|
48 #include <CVPbkContactLinkArray.h> |
|
49 #include <VPbkEng.rsg> // contains virtual phonebook data fields |
|
50 #include <phoneui.rsg> |
|
51 |
|
52 // CCA Launcher header files. |
|
53 #include <ccafactory.h> |
|
54 #include <mccaparameter.h> |
|
55 #include <mccaconnection.h> |
|
56 #include <mccaconnectionext.h> |
|
57 |
|
58 // Service provider settings api |
|
59 #include <spsettingsvoiputils.h> |
|
60 |
|
61 // AIW header files |
|
62 #include <AiwContactAssignDataTypes.h> |
|
63 #include <AiwContactSelectionDataTypes.h> |
|
64 |
|
65 // CCA contactor service. |
|
66 #include "edcontactorservice.h" |
|
67 |
|
68 // Open system trace |
|
69 #include "OstTraceDefinitions.h" |
|
70 #ifdef OST_TRACE_COMPILER_IN_USE |
|
71 #include "easydialingpluginTraces.h" |
|
72 #endif |
|
73 |
|
74 #include <phoneappcommands.hrh> |
|
75 #include <bautils.h> // for BaflUtils |
|
76 |
|
77 // EXTERNAL DATA STRUCTURES |
|
78 |
|
79 // EXTERNAL FUNCTION PROTOTYPES |
|
80 |
|
81 // CONSTANTS |
|
82 const TInt KEDMaximumMatchingContactsCount = 100; |
|
83 const TInt KEasyDialingListBoxModelGranularity = 8; |
|
84 const TInt KEasyDialingMaximumMatchingParts = 10; |
|
85 const TInt KErrEasyDialingNoFirstNamePCSIndexing = -2000; |
|
86 const TInt KErrEasyDialingNoLastNamePCSIndexing = -2001; |
|
87 |
|
88 const TInt KEDFlushContactDataManagerLimit = 20; |
|
89 |
|
90 const TText KHighlightSeparatorChar = 0x1F; |
|
91 _LIT(KHighlightSeparatorCharAsLiteral,"\x1F"); |
|
92 const TText KListFieldSeparatorChar = '\t'; |
|
93 |
|
94 const TText KArabicAndSouthEastAsianRangeStart = 0x0600; |
|
95 const TText KArabicAndSouthEastAsianRangeEnd = 0x19FF; |
|
96 const TText KArabicPresentationFormsARangenStart = 0xFB50; |
|
97 const TText KArabicPresentationFormsARangeEnd = 0xFDFF; |
|
98 const TText KArabicPresentationFormsBRangenStart = 0xFE70; |
|
99 const TText KArabicPresentationFormsBRangeEnd = 0xFEFF; |
|
100 |
|
101 const TInt KMaxRunInfoArrayCount = 20; |
|
102 |
|
103 // MACROS |
|
104 |
|
105 // LOCAL CONSTANTS AND MACROS |
|
106 _LIT(KResourceFile, "\\resource\\easydialingpluginresources.rsc"); |
|
107 |
|
108 // MODULE DATA STRUCTURES |
|
109 |
|
110 // LOCAL FUNCTION PROTOTYPES |
|
111 |
|
112 TInt CompareTPsMatchLocation( const TPsMatchLocation& a1, const TPsMatchLocation& a2); |
|
113 |
|
114 void AppendStringWithMatchDataL( |
|
115 TDes& aBuffer, |
|
116 const TDesC& aText, |
|
117 CPSRequestHandler* aPSHandler, |
|
118 const CPsQuery* aPSQuery ); |
|
119 |
|
120 TBool HighlightingSupportedForText( const TDesC& aText ); |
|
121 |
|
122 inline TBool HighlightingSupportedForScript( TText aChar ); |
|
123 |
|
124 TBool IsStrictlyBidirectional( const TDesC& aText ); |
|
125 |
|
126 static HBufC* AllocWithoutHighlightSeparatorsLC( TDesC& aDesc ); |
|
127 |
|
128 static TBool IsItuTCharacter( TChar aChar ); |
|
129 |
|
130 // FORWARD DECLARATIONS |
|
131 |
|
132 using namespace AknLayoutScalable_Avkon; |
|
133 |
|
134 |
|
135 // ----------------------------------------------------------------------------- |
|
136 // CEasyDialingPlugin |
|
137 // The default c++ constructor |
|
138 // ----------------------------------------------------------------------------- |
|
139 // |
|
140 CEasyDialingPlugin::CEasyDialingPlugin() |
|
141 : iActionToBeLaunched( ENoActionDefined ) |
|
142 { |
|
143 } |
|
144 |
|
145 // ----------------------------------------------------------------------------- |
|
146 // NewL |
|
147 // Create instance of concrete ECOM interface implementation. |
|
148 // ----------------------------------------------------------------------------- |
|
149 // |
|
150 CEasyDialingPlugin* CEasyDialingPlugin::NewL() |
|
151 { |
|
152 OstTrace0( TRACE_NORMAL, CEASYDIALINGPLUGIN_NEWL_LOAD_PLUGIN, "Loading plugin.." ); |
|
153 LOGSTRING("EasyDialingPlugin: Loading plugin.."); |
|
154 |
|
155 CEasyDialingPlugin* self = new (ELeave) CEasyDialingPlugin; |
|
156 CleanupStack::PushL( self ); |
|
157 self->ConstructL(); |
|
158 CleanupStack::Pop( self ); |
|
159 |
|
160 OstTrace0( TRACE_NORMAL, CEASYDIALINGPLUGIN_NEWL_LOAD_PLUGIN_OK, "Loading plugin completed succesfully" ); |
|
161 LOGSTRING("EasyDialingPlugin: Loading plugin completed succesfully"); |
|
162 return self; |
|
163 } |
|
164 |
|
165 // ----------------------------------------------------------------------------- |
|
166 // ConstructL |
|
167 // Main construction handled here. Creates connection to the predictive search |
|
168 // engine and initialises all member data. |
|
169 // ----------------------------------------------------------------------------- |
|
170 // |
|
171 void CEasyDialingPlugin::ConstructL() |
|
172 { |
|
173 // Create a contact store array. |
|
174 HBufC* defaultCdb = VPbkContactStoreUris::DefaultCntDbUri().AllocLC(); |
|
175 iContactDataStores.AppendL( defaultCdb ); |
|
176 CleanupStack::Pop( defaultCdb ); |
|
177 |
|
178 // Create a contact manager instance. |
|
179 iContactStoreUriArray = CVPbkContactStoreUriArray::NewL(); |
|
180 iContactStoreUriArray->AppendL( TVPbkContactStoreUriPtr( VPbkContactStoreUris::DefaultCntDbUri() ) ); |
|
181 iContactManager = CVPbkContactManager::NewL( *iContactStoreUriArray ); |
|
182 |
|
183 // Set contact store observer to listen to contact store events. |
|
184 iContactManager->ContactStoresL().OpenAllL( *this ); |
|
185 |
|
186 PERF_MEASURE_START |
|
187 |
|
188 InitPredictiveContactSearchL(); |
|
189 |
|
190 PERF_MEASURE_STOP |
|
191 |
|
192 // Find a handle to ca launcher extension MCCAConnectionExt. |
|
193 // Easydialing has to use the extension API, because it needs function CloseAppL |
|
194 // only found in extension. |
|
195 // MCCAConnection extension has to be obtained through MCCAParameter extension, |
|
196 // since MCCAConnection is not designed to be extensible API. |
|
197 MCCAParameter* parameter = TCCAFactory::NewParameterL(); |
|
198 TAny* any = parameter->CcaParameterExtension( KMCCAConnectionExtUid ); |
|
199 |
|
200 // Parameter can be deallocated since "any" containing pointer to contact launcher |
|
201 // is not tied to parameter in any way. |
|
202 parameter->Close(); |
|
203 |
|
204 // Cast the pointer into contact launcher object. |
|
205 User::LeaveIfNull( any ); |
|
206 iContactLauncher = static_cast<MCCAConnectionExt*>( any ); |
|
207 |
|
208 iCenrepListener = CEasyDialingCenrepListener::NewL(this); |
|
209 |
|
210 iContactDataManager = new (ELeave) CEasyDialingContactDataManager(iContactManager); |
|
211 iContactDataManager->ConstructL(); |
|
212 iContactDataManager->SetObserver(this); |
|
213 |
|
214 iContactorService = CEDContactorService::NewL( this ); |
|
215 |
|
216 // EasyDialing resource file is attempted to be read from the same directory where the |
|
217 // executed binary is located |
|
218 TFileName dllFileName; |
|
219 Dll::FileName( dllFileName ); |
|
220 |
|
221 TParse parse; |
|
222 User::LeaveIfError( parse.Set(KResourceFile, &dllFileName, NULL) ); |
|
223 TFileName resourceFileName( parse.FullName() ); |
|
224 |
|
225 BaflUtils::NearestLanguageFile( iCoeEnv->FsSession(), resourceFileName ); |
|
226 iResourceFileOffset = iCoeEnv->AddResourceFileL( resourceFileName ); |
|
227 |
|
228 SetComponentsToInheritVisibility( ETrue ); |
|
229 } |
|
230 |
|
231 // --------------------------------------------------------- |
|
232 // ~CEasyDialingPlugin |
|
233 // The desctructor |
|
234 // --------------------------------------------------------- |
|
235 // |
|
236 CEasyDialingPlugin::~CEasyDialingPlugin() |
|
237 { |
|
238 iObservers.Reset(); |
|
239 |
|
240 if ( iContactManager ) |
|
241 { |
|
242 TRAP_IGNORE( iContactManager->ContactStoresL().CloseAll( *this ) ); |
|
243 } |
|
244 |
|
245 delete iCenrepListener; |
|
246 delete iContactDataManager; |
|
247 delete iPredictiveSearchQuery; |
|
248 delete iContactManager; |
|
249 delete iContactStoreUriArray; |
|
250 iContactDataStores.ResetAndDestroy(); |
|
251 |
|
252 if (iPredictiveContactSearchHandler) |
|
253 { |
|
254 iPredictiveContactSearchHandler->RemoveObserver(this); |
|
255 } |
|
256 delete iPredictiveContactSearchHandler; |
|
257 |
|
258 delete iListBoxModel; |
|
259 |
|
260 delete iContactListBox; |
|
261 |
|
262 if (iContactLauncher) |
|
263 { |
|
264 iContactLauncher->Close(); |
|
265 } |
|
266 |
|
267 delete iContactorService; |
|
268 |
|
269 iCoeEnv->DeleteResourceFile( iResourceFileOffset ); |
|
270 |
|
271 delete iInputBlocker; |
|
272 |
|
273 if ( iAsyncCallBack ) |
|
274 { |
|
275 iAsyncCallBack->Cancel(); |
|
276 } |
|
277 delete iAsyncCallBack; |
|
278 |
|
279 OstTrace0( TRACE_NORMAL, CEASYDIALINGPLUGIN_UNLOAD_PLUGIN, "Plugin unloaded" ); |
|
280 LOGSTRING("EasyDialingPlugin: Plugin unloaded"); |
|
281 } |
|
282 |
|
283 |
|
284 // ----------------------------------------------------------------------------- |
|
285 // Initialize |
|
286 // Initialises easy dialing. |
|
287 // ----------------------------------------------------------------------------- |
|
288 // |
|
289 void CEasyDialingPlugin::InitializeL( CCoeControl& aParent ) |
|
290 { |
|
291 SetContainerWindowL( aParent ); |
|
292 SetMopParent( &aParent ); |
|
293 |
|
294 TCallBack asyncCallBack( AsyncCallBackToLaunchAction, this ); |
|
295 iAsyncCallBack = new ( ELeave ) CAsyncCallBack( asyncCallBack, |
|
296 CActive::EPriorityStandard ); |
|
297 |
|
298 iContactListBox = new (ELeave) CEasyDialingListBox(); |
|
299 iListBoxModel = new(ELeave) CDesCArrayFlat( KEasyDialingListBoxModelGranularity ); |
|
300 |
|
301 iContactListBox->ConstructL( CEikListBox::EPaintedSelection |
|
302 | CEikListBox::ENoFirstLetterMatching |
|
303 | CEikListBox::EDisableItemSpecificMenu, |
|
304 iContactDataManager ); |
|
305 iContactListBox->SetListBoxObserver(this); |
|
306 |
|
307 iContactListBox->SetMopParent(this); |
|
308 |
|
309 CTextListBoxModel* model = iContactListBox->Model(); |
|
310 model->SetItemTextArray( iListBoxModel ); |
|
311 model->SetOwnershipType( ELbmDoesNotOwnItemArray ); |
|
312 |
|
313 |
|
314 iContactListBox->MakeVisible( EFalse ); |
|
315 |
|
316 SetFocus( EFalse ); |
|
317 iContactListBox->ActivateL(); |
|
318 |
|
319 } |
|
320 |
|
321 |
|
322 // ----------------------------------------------------------------------------- |
|
323 // Reset |
|
324 // Resets easydialing plugin. |
|
325 // ----------------------------------------------------------------------------- |
|
326 // |
|
327 void CEasyDialingPlugin::Reset() |
|
328 { |
|
329 // PCS searches completing must be discarded, if the complete |
|
330 // after Reset() -call. |
|
331 iDiscardCompletingSearches = ETrue; |
|
332 |
|
333 iNewSearchNeeded = EFalse; |
|
334 iSearchString.Zero(); |
|
335 iListBoxModel->Reset(); |
|
336 iNumberOfNames = 0; |
|
337 iContactListBox->MakeVisible( EFalse ); |
|
338 iContactDataManager->Reset(); |
|
339 if ( IsFocused() ) |
|
340 { |
|
341 SetFocus( EFalse ); |
|
342 } |
|
343 } |
|
344 |
|
345 |
|
346 // ----------------------------------------------------------------------------- |
|
347 // InitPredictiveContactSearchL |
|
348 // Initialises predictive contact search. |
|
349 // ----------------------------------------------------------------------------- |
|
350 // |
|
351 void CEasyDialingPlugin::InitPredictiveContactSearchL() |
|
352 { |
|
353 iPredictiveContactSearchHandler = CPSRequestHandler::NewL(); |
|
354 iPredictiveContactSearchHandler->AddObserverL(this); |
|
355 |
|
356 // Put the searched contact fields into array. |
|
357 RArray<TInt> contact_fields; |
|
358 CleanupClosePushL(contact_fields); |
|
359 |
|
360 // Check which relevant contact fields are indexed in PCS search. |
|
361 iFirstNamePCSIndex = FindContactFieldPCSIndexL( R_VPBK_FIELD_TYPE_FIRSTNAME ); |
|
362 iLastNamePCSIndex = FindContactFieldPCSIndexL( R_VPBK_FIELD_TYPE_LASTNAME ); |
|
363 iCompanyNamePCSIndex = FindContactFieldPCSIndexL( R_VPBK_FIELD_TYPE_COMPANYNAME ); |
|
364 |
|
365 // If first name and last name are not indexed in PCS, easy dialing plugin |
|
366 // can not function reasonably. The function leaves, which in turn causes |
|
367 // the plugin not to be initialized. |
|
368 // Company name not being indexed is not as severe case, and does not cause a leave. |
|
369 // Fields used in PCS indexing are configured in cenrep 2000B5C6. |
|
370 if ( iFirstNamePCSIndex == KErrNotFound ) |
|
371 { |
|
372 OstTrace0( TRACE_ERROR, CEASYDIALINGPLUGIN_INITPREDICTIVECONTACTSEARCHL_ERROR_NO_FIRST_NAME, "ERROR, PCS does not support first name indexing!" ); |
|
373 LOGSTRING("EasyDialingPlugin: PCS does not support first name indexing => Leave"); |
|
374 User::Leave( KErrEasyDialingNoFirstNamePCSIndexing ); |
|
375 } |
|
376 if ( iLastNamePCSIndex == KErrNotFound ) |
|
377 { |
|
378 OstTrace0( TRACE_ERROR, CEASYDIALINGPLUGIN_INITPREDICTIVECONTACTSEARCHL_ERROR_NO_LAST_NAME, "ERROR, PCS does not support last name indexing!" ); |
|
379 LOGSTRING("EasyDialingPlugin: PCS does not support last name indexing => Leave"); |
|
380 User::Leave( KErrEasyDialingNoLastNamePCSIndexing ); |
|
381 } |
|
382 |
|
383 // First name, last name and company name (if supported) are used in PCS search. |
|
384 contact_fields.Append(R_VPBK_FIELD_TYPE_FIRSTNAME); |
|
385 contact_fields.Append(R_VPBK_FIELD_TYPE_LASTNAME); |
|
386 if ( iCompanyNamePCSIndex != KErrNotFound ) |
|
387 { |
|
388 contact_fields.Append(R_VPBK_FIELD_TYPE_COMPANYNAME); |
|
389 } |
|
390 |
|
391 // Create and fill ps settings object. |
|
392 CPsSettings* ps_settings = CPsSettings::NewL(); |
|
393 CleanupStack::PushL(ps_settings); |
|
394 |
|
395 ps_settings->SetSearchUrisL(iContactDataStores); |
|
396 ps_settings->SetMaxResults(KEDMaximumMatchingContactsCount); |
|
397 ps_settings->SetSortType(EAlphabetical); |
|
398 ps_settings->SetDisplayFieldsL(contact_fields); |
|
399 |
|
400 // Set the PCS settings. |
|
401 iPredictiveContactSearchHandler->SetSearchSettingsL(*ps_settings); |
|
402 |
|
403 CleanupStack::PopAndDestroy(ps_settings); |
|
404 CleanupStack::PopAndDestroy(&contact_fields); |
|
405 |
|
406 iPredictiveSearchQuery = CPsQuery::NewL(); |
|
407 } |
|
408 |
|
409 // ----------------------------------------------------------------------------- |
|
410 // OfferKeyEventL |
|
411 // Check the received keypad event and performs user |
|
412 // actions related to it. |
|
413 // ----------------------------------------------------------------------------- |
|
414 // |
|
415 TKeyResponse CEasyDialingPlugin::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType) |
|
416 { |
|
417 TKeyResponse keyResponse = EKeyWasNotConsumed; |
|
418 |
|
419 if ( aKeyEvent.iCode == 0 && aKeyEvent.iScanCode != EStdKeyDevice3) |
|
420 { |
|
421 return keyResponse; |
|
422 } |
|
423 |
|
424 TInt keyCode = aKeyEvent.iCode; |
|
425 |
|
426 // Swap right and left key codes in mirrored layout. This needs to be done |
|
427 // also for action menu grid as CAknGrid handles arrow keys like this: |
|
428 // left key = next column (not item!) and right is previous column and |
|
429 // grid layout (LtR/RtL) is not taken into account when movement is done |
|
430 // in columns (always like in LtR layout). So if right key should move |
|
431 // focus to the right also in mirroded layout, key codes must be switched. |
|
432 // This kind of approach is used also e.g. in application grid. |
|
433 if ( AknLayoutUtils::LayoutMirrored() ) |
|
434 { |
|
435 if ( keyCode == EKeyRightArrow ) keyCode = EKeyLeftArrow; |
|
436 else if ( keyCode == EKeyLeftArrow ) keyCode = EKeyRightArrow; |
|
437 } |
|
438 |
|
439 |
|
440 if ( IsFocused() ) |
|
441 { |
|
442 if ( keyCode == EKeyUpArrow ) |
|
443 { |
|
444 // if the focus is on the top-most item |
|
445 if ( iContactListBox->CurrentItemIndex() == 0) |
|
446 { |
|
447 // then focus jumps off the component. |
|
448 SetFocus( EFalse ); |
|
449 DrawDeferred(); |
|
450 keyResponse = EKeyWasConsumed; |
|
451 } |
|
452 else |
|
453 { |
|
454 keyResponse = iContactListBox->OfferKeyEventL( aKeyEvent, aType ); |
|
455 } |
|
456 } |
|
457 else if ( keyCode == EKeyDownArrow ) |
|
458 { |
|
459 // if the focus is on the bottom-most item |
|
460 if ( iContactListBox->CurrentItemIndex() == (iNumberOfNames - 1) ) |
|
461 { |
|
462 // then focus jumps off the component. |
|
463 SetFocus( EFalse ); |
|
464 DrawDeferred(); |
|
465 keyResponse = EKeyWasConsumed; |
|
466 } |
|
467 else |
|
468 { |
|
469 keyResponse = iContactListBox->OfferKeyEventL( aKeyEvent, aType ); |
|
470 } |
|
471 } |
|
472 |
|
473 else if ( keyCode == EKeyRightArrow ) |
|
474 { |
|
475 iRememberFocus = ETrue; |
|
476 AsyncActionLaunchL( ELaunchCurrentContact ); |
|
477 keyResponse = EKeyWasConsumed; |
|
478 } |
|
479 |
|
480 else if ( keyCode == EKeyLeftArrow ) |
|
481 { |
|
482 // then focus jumps off the component. |
|
483 SetFocus( EFalse ); |
|
484 DrawDeferred(); |
|
485 keyResponse = EKeyWasConsumed; |
|
486 } |
|
487 |
|
488 else |
|
489 { |
|
490 // then focus jumps off the component. |
|
491 SetFocus( EFalse ); |
|
492 } |
|
493 } |
|
494 |
|
495 else if ( iNumberOfNames > 0 ) // not in focus but there are contacts to show |
|
496 { |
|
497 if ( keyCode == EKeyUpArrow || keyCode == EKeyDownArrow ) |
|
498 { |
|
499 SetFocus( ETrue ); |
|
500 keyResponse = iContactListBox->SetFocusedWithKeyEventL( aKeyEvent, aType ); |
|
501 } |
|
502 } |
|
503 return keyResponse; |
|
504 } |
|
505 |
|
506 |
|
507 // ----------------------------------------------------------------------------- |
|
508 // CountComponentControls |
|
509 // |
|
510 // ----------------------------------------------------------------------------- |
|
511 // |
|
512 TInt CEasyDialingPlugin::CountComponentControls() const |
|
513 { |
|
514 return iNumberOfNames > 0 ? 1 : 0; |
|
515 } |
|
516 |
|
517 |
|
518 // ----------------------------------------------------------------------------- |
|
519 // ComponentControl |
|
520 // |
|
521 // ----------------------------------------------------------------------------- |
|
522 // |
|
523 CCoeControl* CEasyDialingPlugin::ComponentControl( TInt aIndex ) const |
|
524 { |
|
525 return aIndex == 0 ? iContactListBox : NULL; |
|
526 } |
|
527 |
|
528 |
|
529 // ----------------------------------------------------------------------------- |
|
530 // MakeVisible |
|
531 // |
|
532 // ----------------------------------------------------------------------------- |
|
533 // |
|
534 void CEasyDialingPlugin::MakeVisible( TBool aVisible ) |
|
535 { |
|
536 if ( aVisible != IsVisible() ) |
|
537 { |
|
538 CCoeControl::MakeVisible( aVisible ); |
|
539 |
|
540 if ( !aVisible && IsFocused() ) |
|
541 { |
|
542 SetFocus( EFalse ); |
|
543 } |
|
544 } |
|
545 } |
|
546 |
|
547 |
|
548 // ----------------------------------------------------------------------------- |
|
549 // SizeChanged |
|
550 // |
|
551 // ----------------------------------------------------------------------------- |
|
552 // |
|
553 void CEasyDialingPlugin::SizeChanged() |
|
554 { |
|
555 TRect rect = Rect(); |
|
556 // convert rect to absolute coordinates |
|
557 rect.SetRect( PositionRelativeToScreen(), rect.Size() ); |
|
558 |
|
559 iContactListBox->SetMaxRect( rect ); |
|
560 iContactListBox->SetRectToNumberOfItems( iNumberOfNames ); |
|
561 } |
|
562 |
|
563 |
|
564 // ----------------------------------------------------------------------------- |
|
565 // FocusChanged |
|
566 // |
|
567 // ----------------------------------------------------------------------------- |
|
568 // |
|
569 void CEasyDialingPlugin::FocusChanged( TDrawNow aDrawNow ) |
|
570 { |
|
571 iContactListBox->SetFocus( IsFocused() ); |
|
572 if( !IsFocused() ) |
|
573 { |
|
574 // To be on the safe side, cancel async callback and reset input block. |
|
575 CancelActionLaunchAndInputBlock(); |
|
576 } |
|
577 CCoeControl::FocusChanged( aDrawNow ); |
|
578 InformObservers( MDialingExtensionObserver::EFocusChanged ); |
|
579 } |
|
580 |
|
581 |
|
582 // ----------------------------------------------------------------------------- |
|
583 // SetInputL |
|
584 // |
|
585 // ----------------------------------------------------------------------------- |
|
586 // |
|
587 void CEasyDialingPlugin::SetInputL( const TDesC& aSearchString ) |
|
588 { |
|
589 if ( !IsEnabled() ) |
|
590 { |
|
591 return; |
|
592 } |
|
593 OstTraceExt1( TRACE_NORMAL, CEASYDIALINGPLUGIN_SET_INPUT, "SetInput: '%S' ", aSearchString ); |
|
594 LOGSTRING1("EasyDialingPlugin: SetInput: '%S'", &aSearchString ); |
|
595 |
|
596 // Earlier here was a test if the search string is the same as the one used in previous search. |
|
597 // If it was, no search was done but function returned immediately. |
|
598 // This has now been removed. It is possible that contacts have changed, and a new search |
|
599 // may be needed even if the search string is the same. |
|
600 |
|
601 // Check if search string is just empty space or 0-length. Decision was made that no |
|
602 // matches are shown if search string is just space (would show all contacts) |
|
603 // even if somebody might have unnamed contacts. Should be quite rare. |
|
604 // It's assumed later on in the code that string is not just empty space. |
|
605 TLex searchString( aSearchString ); |
|
606 searchString.SkipSpace(); |
|
607 if ( searchString.Eos() ) |
|
608 { |
|
609 // the end of the string reached after skipping empty space |
|
610 Reset(); |
|
611 } |
|
612 else // proper search string |
|
613 { |
|
614 iSearchString.Copy( aSearchString.Left( iSearchString.MaxLength() ) ); |
|
615 LaunchSearchL(); |
|
616 } |
|
617 } |
|
618 |
|
619 |
|
620 // ----------------------------------------------------------------------------- |
|
621 // MatchingContactCount |
|
622 // |
|
623 // ----------------------------------------------------------------------------- |
|
624 // |
|
625 TInt CEasyDialingPlugin::MatchingContactCount() |
|
626 { |
|
627 return iNumberOfNames; |
|
628 } |
|
629 |
|
630 |
|
631 // ----------------------------------------------------------------------------- |
|
632 // CEasyDialingPlugin::StoreReady |
|
633 // From MVPbkContactStoreListObserver. |
|
634 // |
|
635 // ----------------------------------------------------------------------------- |
|
636 // |
|
637 void CEasyDialingPlugin::StoreReady(MVPbkContactStore& /* aContactStore */) |
|
638 { |
|
639 |
|
640 } |
|
641 |
|
642 |
|
643 // ----------------------------------------------------------------------------- |
|
644 // CEasyDialingPlugin::StoreUnavailable |
|
645 // From MVPbkContactStoreListObserver. |
|
646 // |
|
647 // ----------------------------------------------------------------------------- |
|
648 // |
|
649 void CEasyDialingPlugin::StoreUnavailable(MVPbkContactStore& /* aContactStore */, TInt /* aReason */) |
|
650 { |
|
651 |
|
652 } |
|
653 |
|
654 |
|
655 // ----------------------------------------------------------------------------- |
|
656 // CEasyDialingPlugin::HandleStoreEventL |
|
657 // From MVPbkContactStoreListObserver. |
|
658 // |
|
659 // ----------------------------------------------------------------------------- |
|
660 // |
|
661 void CEasyDialingPlugin::HandleStoreEventL( MVPbkContactStore& /* aContactStore */, |
|
662 TVPbkContactStoreEvent aStoreEvent) |
|
663 { |
|
664 // Store's observers are informed one by one using active object so one shouldn't |
|
665 // perform search syncronously as one must try to ensure that PCS has had a |
|
666 // chance to update its store. However there seems to be no way to be |
|
667 // 100% sure that PCS is up-to-date when search is launched: telephony app |
|
668 // has such a high priority and there are no APIs to query PCS' status. |
|
669 switch ( aStoreEvent.iEventType ) |
|
670 { |
|
671 case TVPbkContactStoreEvent::EContactAdded: |
|
672 case TVPbkContactStoreEvent::EContactDeleted: |
|
673 case TVPbkContactStoreEvent::EContactChanged: |
|
674 { |
|
675 if ( iSearchString.Length() > 0 ) |
|
676 { |
|
677 if ( iContactLauncherActive ) |
|
678 { |
|
679 // Set the flag to make a search when communication launcher exits. |
|
680 iNewSearchNeeded = ETrue; |
|
681 } |
|
682 else |
|
683 { |
|
684 // We get here if user e.g. leaves dialer open and goes to Contacts |
|
685 // application and does some editing. |
|
686 AsyncActionLaunchL( ELaunchSearch ); |
|
687 } |
|
688 } |
|
689 } |
|
690 |
|
691 break; |
|
692 |
|
693 default: |
|
694 |
|
695 break; |
|
696 } |
|
697 |
|
698 |
|
699 |
|
700 } |
|
701 |
|
702 |
|
703 // ----------------------------------------------------------------------------- |
|
704 // CEasyDialingPlugin::OpenComplete |
|
705 // From MVPbkContactStoreListObserver. |
|
706 // |
|
707 // ----------------------------------------------------------------------------- |
|
708 // |
|
709 void CEasyDialingPlugin::OpenComplete() |
|
710 { |
|
711 } |
|
712 |
|
713 // ----------------------------------------------------------------------------- |
|
714 // EasyDialingSettingsChanged |
|
715 // From MEasyDialingCenrepListenerObserver |
|
716 // ----------------------------------------------------------------------------- |
|
717 // |
|
718 void CEasyDialingPlugin::EasyDialingSettingsChanged( TInt aValue ) |
|
719 { |
|
720 if ( aValue == 0 ) |
|
721 { |
|
722 Reset(); |
|
723 InformObservers( MDialingExtensionObserver::EEasyDialingDisabled ); |
|
724 } |
|
725 else if ( aValue == 1 ) |
|
726 { |
|
727 InformObservers( MDialingExtensionObserver::EEasyDialingEnabled ); |
|
728 } |
|
729 MakeVisible( aValue ); |
|
730 } |
|
731 |
|
732 // ----------------------------------------------------------------------------- |
|
733 // EasyDialingContactThumbnailsSettingsChanged |
|
734 // From MEasyDialingCenrepListenerObserver |
|
735 // ----------------------------------------------------------------------------- |
|
736 // |
|
737 void CEasyDialingPlugin::EasyDialingContactThumbnailsSettingsChanged( TInt aThumbnailSettingValue ) |
|
738 { |
|
739 iContactDataManager->SetContactThumbnailSetting( aThumbnailSettingValue ); |
|
740 iContactDataManager->Reload(); |
|
741 DrawDeferred(); |
|
742 } |
|
743 |
|
744 // ----------------------------------------------------------------------------- |
|
745 // AllContactDataLoaded |
|
746 // From MContactDataManagerObserver |
|
747 // ----------------------------------------------------------------------------- |
|
748 // |
|
749 void CEasyDialingPlugin::AllContactDataLoaded() |
|
750 { |
|
751 iContactListBox->DrawDeferred(); |
|
752 } |
|
753 |
|
754 // ----------------------------------------------------------------------------- |
|
755 // InformContactorEvent |
|
756 // From MEDContactorObserver |
|
757 // ----------------------------------------------------------------------------- |
|
758 // |
|
759 void CEasyDialingPlugin::InformContactorEvent( MEDContactorObserver::TEvent aEvent ) |
|
760 { |
|
761 |
|
762 // This callback function simply propagates the events to its own listener. |
|
763 switch ( aEvent ) |
|
764 { |
|
765 case MEDContactorObserver::ECommunicationStarted: |
|
766 InformObservers( MDialingExtensionObserver::ECommunicationStarted ); |
|
767 break; |
|
768 case MEDContactorObserver::ECommunicationCancelled: |
|
769 InformObservers( MDialingExtensionObserver::ECommunicationCancelled ); |
|
770 break; |
|
771 default: |
|
772 break; |
|
773 } |
|
774 |
|
775 // Reset focus unless it is flagged to be remembered. |
|
776 if ( ! iRememberFocus ) |
|
777 { |
|
778 SetFocus( EFalse ); |
|
779 DrawDeferred(); |
|
780 } |
|
781 |
|
782 iRememberFocus = EFalse; |
|
783 } |
|
784 |
|
785 // ----------------------------------------------------------------------------- |
|
786 // Draw |
|
787 // The actual UI drawing function. Draws the easy dialing popup bubble on the |
|
788 // idle screen. |
|
789 // ----------------------------------------------------------------------------- |
|
790 // |
|
791 void CEasyDialingPlugin::Draw( const TRect& /* aRect */ ) const |
|
792 { |
|
793 return; |
|
794 } |
|
795 |
|
796 |
|
797 // ----------------------------------------------------------------------------- |
|
798 // LaunchSearchL |
|
799 // Initiates predictive contact search. |
|
800 // ----------------------------------------------------------------------------- |
|
801 // |
|
802 void CEasyDialingPlugin::LaunchSearchL() |
|
803 { |
|
804 if ( iSearchString.Length() == 0 ) |
|
805 { |
|
806 return; |
|
807 } |
|
808 |
|
809 iDiscardCompletingSearches = EFalse; |
|
810 iNewSearchNeeded = EFalse; |
|
811 |
|
812 iPredictiveSearchQuery->Reset(); |
|
813 |
|
814 for ( TInt i = 0; i < iSearchString.Length(); i++ ) |
|
815 { |
|
816 // Add a query item |
|
817 CPsQueryItem* item = CPsQueryItem::NewL(); |
|
818 CleanupStack::PushL(item); |
|
819 |
|
820 item->SetCharacter( iSearchString[i] ); |
|
821 |
|
822 // The PCS mode used with character is based on character itself, |
|
823 // not to the keyboard it is made with. While this is not strictly |
|
824 // identical to checking the used keyboard, this behaves identically |
|
825 // in most of the normal cases, and makes the logic simpler. |
|
826 if ( IsItuTCharacter( iSearchString[i] ) ) |
|
827 { |
|
828 item->SetMode( EItut ); |
|
829 } |
|
830 else |
|
831 { |
|
832 item->SetMode( EQwerty ); |
|
833 } |
|
834 |
|
835 iPredictiveSearchQuery->AppendL(*item); |
|
836 |
|
837 // Previous CPsQuery::AppendL takes the ownership of item. |
|
838 // Do not delete item. |
|
839 CleanupStack::Pop(item); |
|
840 } |
|
841 |
|
842 // Issue the search. SearchL is asynchronous function => returns immediately. |
|
843 iPredictiveContactSearchHandler->SearchL(*iPredictiveSearchQuery); |
|
844 } |
|
845 |
|
846 |
|
847 // ----------------------------------------------------------------------------- |
|
848 // HandlePsResultsUpdate from MPsResultsObserver |
|
849 // Called after predictive search has been completed. |
|
850 // ----------------------------------------------------------------------------- |
|
851 // |
|
852 void CEasyDialingPlugin::HandlePsResultsUpdate( RPointerArray<CPsClientData>& aResults, RPointerArray<CPsPattern>& aSeqs ) |
|
853 { |
|
854 if (iCenrepListener && iCenrepListener->Value() == 0) |
|
855 { |
|
856 // Easydialing is off. We should arrive here only if user turned it off while a search was happening. |
|
857 Reset(); |
|
858 return; |
|
859 } |
|
860 TRAPD( leaveError, HandlePsResultsUpdateL( aResults, aSeqs ) ); |
|
861 |
|
862 if( leaveError ) |
|
863 { |
|
864 OstTrace1( TRACE_ERROR, CEASYDIALINGPLUGIN_HANDLEPSRESULTSUPDATE, "HandlePsResultsUpdate failed: %d", leaveError ); |
|
865 LOGSTRING1("EasyDialingPlugin: HandlePsResultsUpdate failed: %d", leaveError ); |
|
866 } |
|
867 } |
|
868 |
|
869 |
|
870 // ----------------------------------------------------------------------------- |
|
871 // HandlePsError from MPsResultsObserver |
|
872 // Called when search error happens. |
|
873 // ----------------------------------------------------------------------------- |
|
874 // |
|
875 void CEasyDialingPlugin::HandlePsError( TInt aErrorCode ) |
|
876 { |
|
877 OstTrace1( TRACE_ERROR, CEASYDIALINGPLUGIN_HANDLEPSERROR, "PCS Error: %d", aErrorCode ); |
|
878 LOGSTRING1("EasyDialingPlugin: PCS Error: %d", aErrorCode ); |
|
879 } |
|
880 |
|
881 // ----------------------------------------------------------------------------- |
|
882 // CachingStatus from MPsResultsObserver |
|
883 // Called to update caching status. |
|
884 // ----------------------------------------------------------------------------- |
|
885 // |
|
886 void CEasyDialingPlugin::CachingStatus( TCachingStatus& aStatus, TInt& aError ) |
|
887 { |
|
888 OstTraceExt2( TRACE_NORMAL, CEASYDIALINGPLUGIN_CACHINGSTATUS, "PCS CachingStatus: %d, error: %d", ( TUint )( aStatus ), aError ); |
|
889 LOGSTRING2("EasyDialingPlugin: PCS CachingStatus: %d, error: %d", aStatus, aError ); |
|
890 } |
|
891 |
|
892 |
|
893 // ----------------------------------------------------------------------------- |
|
894 // FindContactFieldPCSIndex |
|
895 // Searches the index that stores the given contact field. |
|
896 // To see possible contact field numbering, see file "vpbkeng.rsg". |
|
897 // ----------------------------------------------------------------------------- |
|
898 // |
|
899 TInt CEasyDialingPlugin::FindContactFieldPCSIndexL( TInt aIndex ) |
|
900 { |
|
901 RArray<TInt> fieldOrder; |
|
902 CleanupClosePushL( fieldOrder ); |
|
903 |
|
904 // Current implementation searches only from default database. |
|
905 // Later this may be expanded to search SIM contacts as well. |
|
906 HBufC* default_cdb = VPbkContactStoreUris::DefaultCntDbUri().AllocLC(); |
|
907 |
|
908 iPredictiveContactSearchHandler->GetDataOrderL( *default_cdb, fieldOrder ); |
|
909 |
|
910 for ( TInt i = 0; i < fieldOrder.Count(); i++) |
|
911 { |
|
912 if ( fieldOrder[i] == aIndex ) |
|
913 { |
|
914 CleanupStack::PopAndDestroy( default_cdb ); |
|
915 CleanupStack::PopAndDestroy( &fieldOrder ); |
|
916 return i; |
|
917 } |
|
918 } |
|
919 |
|
920 CleanupStack::PopAndDestroy( default_cdb ); |
|
921 CleanupStack::PopAndDestroy( &fieldOrder ); |
|
922 return KErrNotFound; |
|
923 } |
|
924 |
|
925 |
|
926 // ----------------------------------------------------------------------------- |
|
927 // HandlePsResultsUpdateL |
|
928 // This function does the actual callback fork, and must be trapped inside |
|
929 // HandlePsResultsUpdateL. |
|
930 // ----------------------------------------------------------------------------- |
|
931 // |
|
932 void CEasyDialingPlugin::HandlePsResultsUpdateL( RPointerArray<CPsClientData>& aResults, RPointerArray<CPsPattern>& /*aSeqs*/ ) |
|
933 { |
|
934 // If iDiscardCompletingSearches is ETrue, don't show search results but just return. |
|
935 // If easydialing has been reset with reset function, no searches completed after that |
|
936 // can be shown. |
|
937 // This is done like this because there seems not to be a feasible way of cancelling all |
|
938 // PCS search request in PCS API. CancelRequest does not work here. |
|
939 if ( iDiscardCompletingSearches ) |
|
940 { |
|
941 return; |
|
942 } |
|
943 |
|
944 iListBoxModel->Reset(); |
|
945 iContactListBox->HandleItemRemovalL(); |
|
946 |
|
947 TInt numberOfPCSMatches( aResults.Count() ); |
|
948 |
|
949 // Resetting the contactdatamanager causes the thumbnails to flicker a bit, because |
|
950 // we need to load the thumbnails again. But if there are lots of search results, or |
|
951 // lots of loaded thumbnails in the manager, matching the search results to the |
|
952 // thumbnail manager contents may take too much time. If there are lots of results, |
|
953 // it is likely that the contents of the listbox change anyway, so the flickering |
|
954 // doesn't matter too much. This also limits the memory usage of the manager. |
|
955 // But if there are fewer search results, it is worth trying to match them |
|
956 // with the contents of thumbnail manager. |
|
957 |
|
958 TBool matchThumbnails(ETrue); |
|
959 if ( numberOfPCSMatches > KEDFlushContactDataManagerLimit ) |
|
960 { |
|
961 iContactDataManager->Reset(); |
|
962 matchThumbnails = EFalse; |
|
963 } |
|
964 |
|
965 OstTrace1( TRACE_NORMAL, CEASYDIALINGPLUGIN_HANDLEPSRESULTSUPDATEL_MATCHES, "Matching results from PCS: %d", numberOfPCSMatches ); |
|
966 LOGSTRING1("EasyDialingPlugin: Matching results from PCS: %d", numberOfPCSMatches ); |
|
967 |
|
968 if ( numberOfPCSMatches > 0 ) |
|
969 { |
|
970 // retrieve the name order before adding |
|
971 CPbkContactEngine* pbkEngine = CPbkContactEngine::NewL(); |
|
972 CleanupStack::PushL( pbkEngine ); |
|
973 CPbkContactEngine::TPbkNameOrder nameOrder = pbkEngine->NameDisplayOrderL(); |
|
974 CleanupStack::PopAndDestroy( pbkEngine ); |
|
975 |
|
976 // map results to old contact match data |
|
977 for( TInt i = 0; i < numberOfPCSMatches; i++ ) |
|
978 { |
|
979 TInt indexFromEnd = numberOfPCSMatches - i - 1; |
|
980 |
|
981 MVPbkContactLink* link = iPredictiveContactSearchHandler->ConvertToVpbkLinkLC( |
|
982 *(aResults[indexFromEnd]), *iContactManager ); |
|
983 if ( !iContactDataManager->IsFavL( link ) ) |
|
984 { |
|
985 // handle favourites separately, in another loop |
|
986 HBufC* contactString = CreateContactStringLC( aResults[ indexFromEnd ], nameOrder ); |
|
987 CreateListBoxContactStringL( *contactString, link, matchThumbnails, EFalse ); |
|
988 CleanupStack::PopAndDestroy( contactString ); |
|
989 } |
|
990 CleanupStack::PopAndDestroy( link ); |
|
991 |
|
992 OstTraceExt2( TRACE_NORMAL, CEASYDIALINGPLUGIN_HANDLEPSRESULTSUPDATEL_SHOW_MATCH, "Contact #%d: '%S'", i+1, iContactStringCreationBuffer ); |
|
993 LOGSTRING2("EasyDialingPlugin: Contact #%d: '%S'", i+1, &iContactStringCreationBuffer ); |
|
994 } |
|
995 |
|
996 TInt numberOfFavs( iContactDataManager->NumberOfFavsL() ); |
|
997 TBuf<KBufferMaxLen> results; |
|
998 for ( TInt i = 0; i < numberOfFavs; i++ ) |
|
999 { |
|
1000 // check if this fav matches the search |
|
1001 HBufC* favContactString = iContactDataManager->FavContactStringLC( i, nameOrder ); |
|
1002 results = KNullDesC; |
|
1003 iPredictiveContactSearchHandler->LookupMatchL( |
|
1004 *iPredictiveSearchQuery, *favContactString, results ); |
|
1005 if ( results.Length() > 0 ) |
|
1006 { |
|
1007 // matches, add this fav to listbox. |
|
1008 MVPbkContactLink* link = iContactDataManager->FavLinkLC( i ); |
|
1009 CreateListBoxContactStringL( *favContactString, link, matchThumbnails, ETrue ); |
|
1010 CleanupStack::PopAndDestroy(); //link |
|
1011 } |
|
1012 CleanupStack::PopAndDestroy( favContactString ); |
|
1013 } |
|
1014 |
|
1015 iNumberOfNames = iListBoxModel->Count(); |
|
1016 iContactListBox->SetRectToNumberOfItems( iNumberOfNames ); |
|
1017 iContactListBox->HandleItemAdditionL(); |
|
1018 // Scroll the list to bottom |
|
1019 iContactListBox->ScrollToMakeItemVisible( iNumberOfNames-1 ); |
|
1020 |
|
1021 iContactListBox->MakeVisible( ETrue ); |
|
1022 } |
|
1023 else |
|
1024 { |
|
1025 iNumberOfNames = 0; |
|
1026 iContactListBox->MakeVisible( EFalse ); |
|
1027 } |
|
1028 |
|
1029 if ( IsFocused() ) |
|
1030 { |
|
1031 SetFocus( EFalse ); |
|
1032 } |
|
1033 |
|
1034 DrawDeferred(); |
|
1035 |
|
1036 InformObservers( MDialingExtensionObserver::ESearchComplete ); |
|
1037 } |
|
1038 |
|
1039 |
|
1040 // ----------------------------------------------------------------------------- |
|
1041 // void CCASimpleNotifyL() |
|
1042 // Implements MCCAObserver notification interface. |
|
1043 // |
|
1044 // ----------------------------------------------------------------------------- |
|
1045 // |
|
1046 void CEasyDialingPlugin::CCASimpleNotifyL( TNotifyType aType, TInt aReason ) |
|
1047 { |
|
1048 OstTraceExt2( TRACE_NORMAL, CEASYDIALINGPLUGIN_CCASIMPLENOTIFYL, "CCASimpleNotifyL: type: %d, reason: %d", ( TUint )( aType ), aReason ); |
|
1049 LOGSTRING2("EasyDialingPlugin: CCASimpleNotifyL: type: %d, reason: %d", (TInt)aType, aReason ); |
|
1050 |
|
1051 iContactLauncherActive = EFalse; |
|
1052 |
|
1053 CAknAppUi* appUi = static_cast<CAknAppUi*>( iCoeEnv->AppUi() ); |
|
1054 appUi->HandleCommandL( EPhoneCmdBlockingDialogClosed ); |
|
1055 |
|
1056 // If contacts have been edited during contact launcher being open, a new search |
|
1057 // needs to be done. |
|
1058 if ( iNewSearchNeeded ) |
|
1059 { |
|
1060 // The cached information in contact data manager may be outdated. Call to reload makes sure that when the |
|
1061 // search is made, all data is loaded again. |
|
1062 iContactDataManager->Reload(); |
|
1063 |
|
1064 LaunchSearchL(); |
|
1065 } |
|
1066 |
|
1067 // Give up focus, if iRememberFocus flag is not set. |
|
1068 if ( ! iRememberFocus ) |
|
1069 { |
|
1070 SetFocus( EFalse ); |
|
1071 DrawDeferred(); |
|
1072 } |
|
1073 iRememberFocus = EFalse; |
|
1074 |
|
1075 // Inform observers. |
|
1076 InformObservers( MDialingExtensionObserver::ECCALauncherExit ); |
|
1077 } |
|
1078 |
|
1079 |
|
1080 // ----------------------------------------------------------------------------- |
|
1081 // void LaunchCurrentContactL() |
|
1082 // Implements MCCAObserver notification interface. |
|
1083 // |
|
1084 // ----------------------------------------------------------------------------- |
|
1085 // |
|
1086 void CEasyDialingPlugin::LaunchCurrentContactL() |
|
1087 { |
|
1088 __ASSERT_DEBUG( iNumberOfNames > 0, EasyDialingPanic( EEasyDialingPanicNoResults ) ); |
|
1089 __ASSERT_DEBUG( iContactListBox->CurrentItemIndex() >= 0, EasyDialingPanic( EEasyDialingPanicNoContactSelected ) ); |
|
1090 |
|
1091 if (( iContactLauncherActive ) || ( iNumberOfNames == 0 ) || ( !iContactListBox ) || ( iContactListBox->CurrentItemIndex() < 0 )) |
|
1092 { |
|
1093 OstTrace0( TRACE_ERROR, CEASYDIALINGPLUGIN_LAUNCHCURRENTCONTACTL_ERROR, "LaunchCurrentContactL: Parameter error" ); |
|
1094 LOGSTRING("EasyDialingPlugin: LaunchCurrentContactL - Parameter error"); |
|
1095 return; |
|
1096 } |
|
1097 |
|
1098 MCCAParameter* launchParameters = TCCAFactory::NewParameterL(); |
|
1099 CleanupClosePushL( *launchParameters ); |
|
1100 |
|
1101 // ESoftExit flag causes that ca launcher will not close the |
|
1102 // client application in any circumstance. |
|
1103 // Application hosting easydialing is telephone application. |
|
1104 // It must never be closed, so we must use this flag. |
|
1105 launchParameters->SetConnectionFlag(MCCAParameter::ESoftExit); |
|
1106 |
|
1107 launchParameters->SetContactDataFlag(MCCAParameter::EContactLink); |
|
1108 |
|
1109 // Get the contact link of the current contact item. |
|
1110 HBufC8* contact8 = iContactListBox->CurrentContactLinkLC(); |
|
1111 |
|
1112 // Expand it into 16-bit descriptor because cca launcher api expects this. |
|
1113 HBufC16* contact16 = HBufC16::NewLC( contact8->Length() ); |
|
1114 contact16->Des().Copy( *contact8 ); |
|
1115 |
|
1116 launchParameters->SetContactDataL( *contact16 ); |
|
1117 |
|
1118 CleanupStack::PopAndDestroy( contact16 ); |
|
1119 CleanupStack::PopAndDestroy( contact8 ); |
|
1120 |
|
1121 TPtrC selectedName = iListBoxModel->MdcaPoint( iContactListBox->CurrentItemIndex() ); |
|
1122 OstTraceExt1( TRACE_NORMAL, CEASYDIALINGPLUGIN_LAUNCHCURRENTCONTACTL_LAUNCH_CCA, "Launch CL for contact: '%S'", selectedName ); |
|
1123 LOGSTRING1("EasyDialingPlugin: Launch CL for contact: '%S'", &selectedName ); |
|
1124 |
|
1125 iContactLauncher->LaunchAppL( *launchParameters, this ); |
|
1126 |
|
1127 // Ownership of parameter transferred to CCA launcher => pop but do not destroy. |
|
1128 CleanupStack::Pop( launchParameters ); |
|
1129 |
|
1130 |
|
1131 iContactLauncherActive = ETrue; |
|
1132 CAknAppUi* appUi = static_cast<CAknAppUi*>( iCoeEnv->AppUi() ); |
|
1133 appUi->HandleCommandL( EPhoneCmdBlockingDialogLaunched ); |
|
1134 } |
|
1135 |
|
1136 |
|
1137 // ----------------------------------------------------------------------------- |
|
1138 // CreateListBoxContactStringL |
|
1139 // |
|
1140 // ----------------------------------------------------------------------------- |
|
1141 // |
|
1142 void CEasyDialingPlugin::CreateListBoxContactStringL( |
|
1143 const TDesC& aContactString, |
|
1144 MVPbkContactLink *aLink, |
|
1145 TBool aMatchThumbnails, |
|
1146 TBool aFav ) |
|
1147 { |
|
1148 // Construct the contact string for the listbox model. |
|
1149 iContactStringCreationBuffer.Zero(); |
|
1150 |
|
1151 // Append contact thumbnail id. |
|
1152 HBufC* thumbnailId = iContactDataManager->GetThumbnailIdL( aLink, aMatchThumbnails, aFav ); |
|
1153 iContactStringCreationBuffer.Append( *thumbnailId ); |
|
1154 delete thumbnailId; |
|
1155 iContactStringCreationBuffer.Append( KListFieldSeparatorChar ); |
|
1156 |
|
1157 AppendStringWithMatchDataL( |
|
1158 iContactStringCreationBuffer, |
|
1159 aContactString, |
|
1160 iPredictiveContactSearchHandler, |
|
1161 iPredictiveSearchQuery ); |
|
1162 |
|
1163 // Append the whole string to listbox model. |
|
1164 iListBoxModel->AppendL( iContactStringCreationBuffer ); |
|
1165 } |
|
1166 |
|
1167 // ----------------------------------------------------------------------------- |
|
1168 // CreateContactStringLC |
|
1169 // |
|
1170 // ----------------------------------------------------------------------------- |
|
1171 // |
|
1172 HBufC* CEasyDialingPlugin::CreateContactStringLC( CPsClientData* aResult, CPbkContactEngine::TPbkNameOrder aNameOrder ) |
|
1173 { |
|
1174 TPtr firstName = aResult->Data( iFirstNamePCSIndex )->Des(); |
|
1175 TPtr lastName = aResult->Data( iLastNamePCSIndex )->Des(); |
|
1176 TPtr companyName( NULL, 0 ); |
|
1177 |
|
1178 if ( iCompanyNamePCSIndex != KErrNotFound ) |
|
1179 { |
|
1180 companyName.Set( aResult->Data( iCompanyNamePCSIndex )->Des() ); |
|
1181 } |
|
1182 return EasyDialingUtils::CreateContactStringLC( firstName, lastName, companyName, aNameOrder ); |
|
1183 } |
|
1184 |
|
1185 |
|
1186 // ----------------------------------------------------------------------------- |
|
1187 // AddObserverL |
|
1188 // |
|
1189 // ----------------------------------------------------------------------------- |
|
1190 // |
|
1191 void CEasyDialingPlugin::AddObserverL( MDialingExtensionObserver* aObserver ) |
|
1192 { |
|
1193 if ( !aObserver ) |
|
1194 { |
|
1195 return; |
|
1196 } |
|
1197 |
|
1198 User::LeaveIfError( iObservers.Append( aObserver ) ); |
|
1199 } |
|
1200 |
|
1201 |
|
1202 // ----------------------------------------------------------------------------- |
|
1203 // RemoveObserver |
|
1204 // |
|
1205 // Removes the parameter observer from observer list if found. If same observer |
|
1206 // has registered multiple times (which is unnecessary), removed just the first |
|
1207 // registration. |
|
1208 // ----------------------------------------------------------------------------- |
|
1209 // |
|
1210 void CEasyDialingPlugin::RemoveObserver( MDialingExtensionObserver* aObserver ) |
|
1211 { |
|
1212 for ( TInt i = 0; i < iObservers.Count(); i++ ) |
|
1213 { |
|
1214 if ( iObservers[i] == aObserver) |
|
1215 { |
|
1216 iObservers.Remove( i ); |
|
1217 return; |
|
1218 } |
|
1219 } |
|
1220 } |
|
1221 |
|
1222 |
|
1223 // ----------------------------------------------------------------------------- |
|
1224 // InformObservers |
|
1225 // Informs all registered observers of easy dialing events. |
|
1226 // ----------------------------------------------------------------------------- |
|
1227 // |
|
1228 void CEasyDialingPlugin::InformObservers( MDialingExtensionObserver::TEvent aEvent ) |
|
1229 { |
|
1230 for ( TInt i = 0; i < iObservers.Count(); i++ ) |
|
1231 { |
|
1232 iObservers[i]->HandleDialingExtensionEvent( aEvent ); |
|
1233 } |
|
1234 } |
|
1235 |
|
1236 // ----------------------------------------------------------------------------- |
|
1237 // CbaResourceId |
|
1238 // Returns EasyDialingPlugin specific CBA resource ID that |
|
1239 // Phone application can use when updating Soft Keys. |
|
1240 // ----------------------------------------------------------------------------- |
|
1241 // |
|
1242 TInt CEasyDialingPlugin::CbaResourceId() |
|
1243 { |
|
1244 return R_EASYDIALING_CBA; |
|
1245 } |
|
1246 |
|
1247 |
|
1248 // ----------------------------------------------------------------------------- |
|
1249 // MenuResourceId |
|
1250 // Returns EasyDialingPlugin specific menu resource ID that |
|
1251 // Phone application can use when easydialing is in focus. |
|
1252 // ----------------------------------------------------------------------------- |
|
1253 // |
|
1254 TInt CEasyDialingPlugin::MenuResourceId() |
|
1255 { |
|
1256 return R_EASYDIALING_MENUBAR; |
|
1257 } |
|
1258 |
|
1259 |
|
1260 // ----------------------------------------------------------------------------- |
|
1261 // InitializeMenuPaneL |
|
1262 // Initializes easy dialing menu pane. This function is meant to be called in |
|
1263 // DynInitMenuPaneL of the application, if the application wants to use easy |
|
1264 // dialing menu. |
|
1265 // ----------------------------------------------------------------------------- |
|
1266 // |
|
1267 TBool CEasyDialingPlugin::InitializeMenuPaneL( CEikMenuPane& aMenuPane, TInt aMenuResourceId ) |
|
1268 { |
|
1269 if ( aMenuResourceId == R_PHONEUIDIALER_OPTIONS_MENU ) |
|
1270 { |
|
1271 TInt index( KErrNotFound ); |
|
1272 // To be on the safe side - place holder was added into phoneui.rss. |
|
1273 if ( aMenuPane.MenuItemExists( EEasyDialingSettingsItemPlaceHolder, index ) ) |
|
1274 { |
|
1275 // Add first menu item (= on/off submenu) after placeHolder item and |
|
1276 // then delete that (empty) placeHolder. |
|
1277 aMenuPane.AddMenuItemsL( R_EASYDIALING_OPTIONS_ON_OFF_MENU_ITEM, |
|
1278 EEasyDialingSettingsItemPlaceHolder ); |
|
1279 aMenuPane.DeleteMenuItem( EEasyDialingSettingsItemPlaceHolder ); |
|
1280 |
|
1281 LOGSTRING("EasyDialingPlugin::InitializeMenuPaneL: Added on/off menu into dialer's menu" ); |
|
1282 } |
|
1283 |
|
1284 // Return EFalse as only one menu item was added here. |
|
1285 return EFalse; |
|
1286 } |
|
1287 |
|
1288 else if ( aMenuResourceId == R_EASYDIALING_MENU ) |
|
1289 { |
|
1290 TBool voiceCall = EFalse; |
|
1291 TBool videoCall = EFalse; |
|
1292 TBool message = EFalse; |
|
1293 |
|
1294 if ( iContactListBox->CurrentItemIndex() >= 0 ) |
|
1295 { |
|
1296 TInt index = iContactListBox->CurrentContactDataIndex(); |
|
1297 |
|
1298 voiceCall = iContactDataManager->VoiceCallAvailable( index ); |
|
1299 videoCall = iContactDataManager->VideoCallAvailable( index ); |
|
1300 message = iContactDataManager->UniEditorAvailable( index ); |
|
1301 } |
|
1302 |
|
1303 // Call menu item is not show if neither voice call nor video call are possible. |
|
1304 aMenuPane.SetItemDimmed( EEasyDialingVoiceCall, !voiceCall && !videoCall ); |
|
1305 aMenuPane.SetItemDimmed( EEasyDialingSendMessage, !message ); |
|
1306 |
|
1307 LOGSTRING("EasyDialingPlugin::InitializeMenuPaneL: InitializeMenuPaneL done" ); |
|
1308 |
|
1309 return ETrue; |
|
1310 } |
|
1311 |
|
1312 else if ( aMenuResourceId == R_EASYDIALING_OPTIONS_CALL_MENU ) |
|
1313 { |
|
1314 TBool voiceCall = EFalse; |
|
1315 TBool videoCall = EFalse; |
|
1316 |
|
1317 if ( iContactListBox->CurrentItemIndex() >= 0 ) |
|
1318 { |
|
1319 TInt index = iContactListBox->CurrentContactDataIndex(); |
|
1320 |
|
1321 voiceCall = iContactDataManager->VoiceCallAvailable( index ); |
|
1322 videoCall = iContactDataManager->VideoCallAvailable( index ); |
|
1323 } |
|
1324 |
|
1325 aMenuPane.SetItemDimmed( EEasyDialingVoiceCall, !voiceCall ); |
|
1326 aMenuPane.SetItemDimmed( EEasyDialingVideoCall, !videoCall ); |
|
1327 |
|
1328 LOGSTRING("EasyDialingPlugin::InitializeMenuPaneL: InitializeMenuPaneL for call submenu done" ); |
|
1329 |
|
1330 return ETrue; |
|
1331 } |
|
1332 |
|
1333 else if ( aMenuResourceId == R_EASYDIALING_OPTIONS_ON_OFF_CASCADE_MENU ) |
|
1334 { |
|
1335 if ( IsEnabled() ) |
|
1336 { |
|
1337 aMenuPane.SetItemButtonState( EEasyDialingOn, EEikMenuItemSymbolOn ); |
|
1338 } |
|
1339 else |
|
1340 { |
|
1341 aMenuPane.SetItemButtonState( EEasyDialingOff, EEikMenuItemSymbolOn ); |
|
1342 } |
|
1343 |
|
1344 LOGSTRING("EasyDialingPlugin::InitializeMenuPaneL: InitializeMenuPaneL for on/off submenu done" ); |
|
1345 |
|
1346 return ETrue; |
|
1347 } |
|
1348 |
|
1349 else |
|
1350 { |
|
1351 return EFalse; |
|
1352 } |
|
1353 } |
|
1354 |
|
1355 // ----------------------------------------------------------------------------- |
|
1356 // HandleCommandL |
|
1357 // Method for handling EasyDialingPlugin specific commands. |
|
1358 // ----------------------------------------------------------------------------- |
|
1359 // |
|
1360 TBool CEasyDialingPlugin::HandleCommandL( TInt aCommand ) |
|
1361 { |
|
1362 // Input blocker can't block controls higher on the control stack than |
|
1363 // ECoeStackPriorityDialog so we will get HandleCommandL calls from |
|
1364 // phoneappui (CBA) when input blocker is active (=not NULL). |
|
1365 |
|
1366 if ( iInputBlocker && aCommand != EEasyDialingCallHandlingActivated ) |
|
1367 { |
|
1368 // Some action is already being launched since iInputBlocker exists. |
|
1369 // Only call activation command requires always action from this plugin. |
|
1370 return ETrue; |
|
1371 } |
|
1372 |
|
1373 |
|
1374 TBool ret(EFalse); |
|
1375 |
|
1376 switch( aCommand ) |
|
1377 { |
|
1378 case EEasyDialingOpenContact: |
|
1379 |
|
1380 iRememberFocus = ETrue; |
|
1381 AsyncActionLaunchL( ELaunchCurrentContact ); |
|
1382 ret = ETrue; |
|
1383 break; |
|
1384 |
|
1385 // EEasyDialingEnterKeyAction is sent when Enter key is pressed. |
|
1386 // EEasyDialingMakeCall is sent when send key or send toolbar button or send menu item is pressed. |
|
1387 case EEasyDialingVoiceCall: // fall through |
|
1388 case EEasyDialingEnterKeyAction: |
|
1389 // Make a call. |
|
1390 iRememberFocus = ETrue; |
|
1391 AsyncActionLaunchL( ECallCurrentContact ); |
|
1392 ret = ETrue; |
|
1393 break; |
|
1394 |
|
1395 // Video call is selectable only through menu. |
|
1396 case EEasyDialingVideoCall: |
|
1397 // Make a video call. |
|
1398 iRememberFocus = ETrue; |
|
1399 AsyncActionLaunchL( EVideoCallCurrentContact ); |
|
1400 ret = ETrue; |
|
1401 break; |
|
1402 |
|
1403 // Uni-editor message is selectable only through menu. |
|
1404 case EEasyDialingSendMessage: |
|
1405 // Create a message. |
|
1406 iRememberFocus = ETrue; |
|
1407 AsyncActionLaunchL( ESendMessageCurrentContact ); |
|
1408 ret = ETrue; |
|
1409 break; |
|
1410 |
|
1411 // EEasyDialingCallHandlingActivated is sent when the in-call-ui of telephony gets activated |
|
1412 case EEasyDialingCallHandlingActivated: |
|
1413 |
|
1414 iRememberFocus = EFalse; |
|
1415 // Stop input block and async action launch in case they are active. |
|
1416 CancelActionLaunchAndInputBlock(); |
|
1417 // Close down number selection popup in case it happens to be open. |
|
1418 iContactorService->CancelService(); |
|
1419 // Close down communication launcher if it's active |
|
1420 if ( iContactLauncherActive ) |
|
1421 { |
|
1422 iNewSearchNeeded = EFalse; |
|
1423 iContactLauncher->CloseAppL(); |
|
1424 } |
|
1425 ret = ETrue; |
|
1426 break; |
|
1427 |
|
1428 case EEasyDialingOn: |
|
1429 |
|
1430 iCenrepListener->SetEasyDialingSettingsValue( 1 ); |
|
1431 ret = ETrue; |
|
1432 break; |
|
1433 |
|
1434 case EEasyDialingOff: |
|
1435 |
|
1436 iCenrepListener->SetEasyDialingSettingsValue( 0 ); |
|
1437 ret = ETrue; |
|
1438 break; |
|
1439 |
|
1440 case EEasyDialingClosePopup: |
|
1441 |
|
1442 // Not only Number Entry is removed but also closes down number selection popup in case it happens to be open. |
|
1443 iContactorService->CancelService(); |
|
1444 ret = ETrue; |
|
1445 break; |
|
1446 |
|
1447 default: |
|
1448 break; |
|
1449 } |
|
1450 return ret; |
|
1451 } |
|
1452 |
|
1453 // ----------------------------------------------------------------------------- |
|
1454 // IsEnabled |
|
1455 // Check if Easy dialing is enabled in the settings |
|
1456 // ----------------------------------------------------------------------------- |
|
1457 // |
|
1458 TBool CEasyDialingPlugin::IsEnabled() |
|
1459 { |
|
1460 return ( iCenrepListener->Value() != 0 ); |
|
1461 } |
|
1462 |
|
1463 // ----------------------------------------------------------------------------- |
|
1464 // AsyncActionLaunchL |
|
1465 // Use asynchronous callback to launch action. While action is being launched, |
|
1466 // input blocker is used to avoid OfferKeyEvent and HandlePointerEvent calls |
|
1467 // coming in. Both end key and application key work despite of input blocker. |
|
1468 // Input blocker can't block phoneappui's cba so extra check is needed in |
|
1469 // HandleCommandL method. |
|
1470 // ----------------------------------------------------------------------------- |
|
1471 // |
|
1472 void CEasyDialingPlugin::AsyncActionLaunchL( const TEasyDialingAction aAction ) |
|
1473 { |
|
1474 iActionToBeLaunched = aAction; |
|
1475 |
|
1476 CancelActionLaunchAndInputBlock(); |
|
1477 |
|
1478 if ( aAction == ELaunchSearch ) |
|
1479 { |
|
1480 // Must be set as low as possible to enable PCS to update its store. |
|
1481 iAsyncCallBack->SetPriority( CActive::EPriorityIdle ); |
|
1482 } |
|
1483 else |
|
1484 { |
|
1485 iAsyncCallBack->SetPriority( CActive::EPriorityStandard ); |
|
1486 } |
|
1487 |
|
1488 iAsyncCallBack->CallBack(); // activates callback request |
|
1489 |
|
1490 // By defining cancel handler, we don't block all input but system is still |
|
1491 // able to deactivate the view etc. |
|
1492 iInputBlocker = CAknInputBlock::NewCancelHandlerLC( this ); |
|
1493 CleanupStack::Pop( iInputBlocker ); |
|
1494 |
|
1495 // This means that iInputBlocker is deleted by CAknInputBlock when |
|
1496 // it's cancelled ( we get a callback where iInputBlocker is set to NULL). |
|
1497 iInputBlocker->SetCancelDelete( iInputBlocker ); |
|
1498 } |
|
1499 |
|
1500 // ----------------------------------------------------------------------------- |
|
1501 // AsyncCallBackToLaunchAction |
|
1502 // Callback function for CAsyncCallBack class. |
|
1503 // ----------------------------------------------------------------------------- |
|
1504 // |
|
1505 TInt CEasyDialingPlugin::AsyncCallBackToLaunchAction( TAny* aPtr ) |
|
1506 { |
|
1507 CEasyDialingPlugin* plugin = static_cast<CEasyDialingPlugin*>( aPtr ); |
|
1508 |
|
1509 TRAP_IGNORE( plugin->DoLaunchActionL() ); |
|
1510 |
|
1511 // Stop input block if active (=not NULL). |
|
1512 if ( plugin->iInputBlocker ) |
|
1513 { |
|
1514 plugin->iInputBlocker->Cancel(); |
|
1515 } |
|
1516 |
|
1517 plugin->iActionToBeLaunched = ENoActionDefined; |
|
1518 |
|
1519 return KErrNone; |
|
1520 } |
|
1521 |
|
1522 // ----------------------------------------------------------------------------- |
|
1523 // DoLaunchActionL |
|
1524 // |
|
1525 // ----------------------------------------------------------------------------- |
|
1526 // |
|
1527 void CEasyDialingPlugin::DoLaunchActionL( ) |
|
1528 { |
|
1529 // If ELaunchCurrentContact, then we launch cca launcher. |
|
1530 if ( iActionToBeLaunched == ELaunchCurrentContact ) |
|
1531 { |
|
1532 LaunchCurrentContactL(); |
|
1533 return; |
|
1534 } |
|
1535 else if ( iActionToBeLaunched == ELaunchSearch ) |
|
1536 { |
|
1537 LaunchSearchL(); |
|
1538 return; |
|
1539 } |
|
1540 |
|
1541 // If not for launching current contact or performing search, |
|
1542 // the action is launching some communication method. |
|
1543 |
|
1544 if ( iContactorService->IsBusy() ) |
|
1545 { |
|
1546 LOGSTRING("EasyDialingPlugin: LaunchActionL - contactor service is busy!"); |
|
1547 return; |
|
1548 } |
|
1549 |
|
1550 // Get current contact link. |
|
1551 HBufC8* contact8 = iContactListBox->CurrentContactLinkLC(); |
|
1552 |
|
1553 TPtrC contactString( iListBoxModel->MdcaPoint( iContactListBox->CurrentItemIndex() ) ); |
|
1554 |
|
1555 TPtrC fullNameSeparators; |
|
1556 TInt error = TextUtils::ColumnText( fullNameSeparators , 1, &contactString ); |
|
1557 __ASSERT_DEBUG( error == KErrNone, EasyDialingPanic( EEasyDialingPanicInvalidListBoxModelString ) ); |
|
1558 |
|
1559 // Remove highlight separators. It is possible that some contactor API has problem with them. |
|
1560 HBufC* fullName = AllocWithoutHighlightSeparatorsLC( fullNameSeparators ); |
|
1561 |
|
1562 VPbkFieldTypeSelectorFactory::TVPbkContactActionTypeSelector selector( |
|
1563 VPbkFieldTypeSelectorFactory::EEmptySelector ); |
|
1564 |
|
1565 switch ( iActionToBeLaunched ) |
|
1566 { |
|
1567 case ECallCurrentContact: |
|
1568 { |
|
1569 // Easy Dialing provides pretty much the same functionality for big Call icon |
|
1570 // and Send key than phonebook's contact list view by using aiw interface |
|
1571 // in edcontactor. |
|
1572 // At this point one must however check whether to use voip or voice call selector - |
|
1573 // otherwise correct logic is provided by aiw interface. |
|
1574 // Note that Easy Dialing ignores default numbers and addresses set for |
|
1575 // action types and shows always the number and address list if there are |
|
1576 // more than one possible number/address for some action. |
|
1577 |
|
1578 CSPSettingsVoIPUtils* sPSettings = CSPSettingsVoIPUtils::NewLC(); |
|
1579 |
|
1580 if ( sPSettings->IsPreferredTelephonyVoIP() ) |
|
1581 { |
|
1582 selector = VPbkFieldTypeSelectorFactory::EVOIPCallSelector; |
|
1583 } |
|
1584 else |
|
1585 { |
|
1586 selector = VPbkFieldTypeSelectorFactory::EVoiceCallSelector; |
|
1587 } |
|
1588 |
|
1589 CleanupStack::PopAndDestroy( sPSettings ); |
|
1590 } |
|
1591 break; |
|
1592 |
|
1593 case EVideoCallCurrentContact: |
|
1594 |
|
1595 selector = VPbkFieldTypeSelectorFactory::EVideoCallSelector; |
|
1596 break; |
|
1597 |
|
1598 case ESendMessageCurrentContact: |
|
1599 |
|
1600 selector = VPbkFieldTypeSelectorFactory::EUniEditorSelector; |
|
1601 break; |
|
1602 |
|
1603 default: |
|
1604 CleanupStack::PopAndDestroy( fullName ); |
|
1605 CleanupStack::PopAndDestroy( contact8 ); |
|
1606 __ASSERT_DEBUG( EFalse, EasyDialingPanic( EEasyDialingActionNotSupported ) ); |
|
1607 return; |
|
1608 } |
|
1609 |
|
1610 CEDContactorService::TCSParameter param( selector, *contact8, 0, *fullName ); |
|
1611 |
|
1612 iContactorService->ExecuteServiceL( param ); |
|
1613 |
|
1614 CleanupStack::PopAndDestroy( fullName ); |
|
1615 CleanupStack::PopAndDestroy( contact8 ); |
|
1616 } |
|
1617 |
|
1618 |
|
1619 // ----------------------------------------------------------------------------- |
|
1620 // CancelActionLaunchAndInputBlock |
|
1621 // Should be called when focus is lost or when call ui is activated. |
|
1622 // ----------------------------------------------------------------------------- |
|
1623 // |
|
1624 void CEasyDialingPlugin::CancelActionLaunchAndInputBlock() |
|
1625 { |
|
1626 iAsyncCallBack->Cancel(); |
|
1627 if ( iInputBlocker ) |
|
1628 { |
|
1629 iInputBlocker->Cancel(); |
|
1630 } |
|
1631 } |
|
1632 |
|
1633 // ----------------------------------------------------------------------------- |
|
1634 // HandleListBoxEventL |
|
1635 // EasyDialerListBox calls this function when listbox events are reported |
|
1636 // to observers. |
|
1637 // ----------------------------------------------------------------------------- |
|
1638 // |
|
1639 void CEasyDialingPlugin::HandleListBoxEventL( CEikListBox* /*aListBox*/, TListBoxEvent aEventType ) |
|
1640 { |
|
1641 LOGSTRING1( "EasyDialingPlugin: HandleListBoxEventL( %d ) - Enter", aEventType ); |
|
1642 |
|
1643 switch( aEventType ) |
|
1644 { |
|
1645 case EEventItemSingleClicked: |
|
1646 // 9.2. Selecting contact initiates call |
|
1647 AsyncActionLaunchL( ECallCurrentContact ); |
|
1648 break; |
|
1649 |
|
1650 case KEasyDialingContactLongTapped: |
|
1651 AsyncActionLaunchL( ELaunchCurrentContact ); |
|
1652 break; |
|
1653 |
|
1654 // We are not interested about the other listbox events. |
|
1655 default: |
|
1656 break; |
|
1657 } |
|
1658 } |
|
1659 |
|
1660 // ----------------------------------------------------------------------------- |
|
1661 // From MAknInputBlockCancelHandler. |
|
1662 // Called when input block is cancelled. |
|
1663 // ----------------------------------------------------------------------------- |
|
1664 // |
|
1665 void CEasyDialingPlugin::AknInputBlockCancel() |
|
1666 { |
|
1667 LOGSTRING("EasyDialingPlugin: AknInputBlockCancel"); |
|
1668 |
|
1669 // iInputBlocker will be deleted right after this callback by CAknInputBlock |
|
1670 // cause we are using CAknInputBlock::SetCancelDelete method. |
|
1671 iInputBlocker = NULL; |
|
1672 } |
|
1673 |
|
1674 /* |
|
1675 * ============================================================================== |
|
1676 * |
|
1677 * Local functions |
|
1678 * |
|
1679 * ============================================================================== |
|
1680 */ |
|
1681 |
|
1682 |
|
1683 |
|
1684 // ----------------------------------------------------------------------------- |
|
1685 // CompareTPsMatchLocation |
|
1686 // Compares two TPsMatchLocation objects based on where the match |
|
1687 // is located in the search string. This used in ordering matches |
|
1688 // based on their location. |
|
1689 // ----------------------------------------------------------------------------- |
|
1690 // |
|
1691 TInt CompareTPsMatchLocation( const TPsMatchLocation& a1, const TPsMatchLocation& a2) |
|
1692 { |
|
1693 if ( a1.index == a2.index ) |
|
1694 { |
|
1695 return 0; |
|
1696 } |
|
1697 return ( a1.index > a2.index ) ? 1 : -1; |
|
1698 } |
|
1699 |
|
1700 |
|
1701 // ----------------------------------------------------------------------------- |
|
1702 // AppendStringWithMatchDataL |
|
1703 // Appends a string with match data into a TDes buffer. Match data is a string |
|
1704 // where matching and non-matching parts are separated by matching hightlight separator |
|
1705 // characters. |
|
1706 // ----------------------------------------------------------------------------- |
|
1707 // |
|
1708 void AppendStringWithMatchDataL( |
|
1709 TDes& aBuffer, |
|
1710 const TDesC& aText, |
|
1711 CPSRequestHandler* aPSHandler, |
|
1712 const CPsQuery* aPSQuery ) |
|
1713 { |
|
1714 if ( HighlightingSupportedForText( aText ) ) |
|
1715 { |
|
1716 CDesCArrayFlat* matchingParts = new (ELeave) CDesCArrayFlat(KEasyDialingMaximumMatchingParts); |
|
1717 CleanupStack::PushL( matchingParts ); |
|
1718 |
|
1719 RArray<TPsMatchLocation> matchIndices; |
|
1720 CleanupClosePushL( matchIndices ); |
|
1721 |
|
1722 aPSHandler->LookupL( *aPSQuery , aText , *matchingParts, matchIndices ); |
|
1723 |
|
1724 // Sort matchIndices array. Later handling assumes it to be sorted according to index field. |
|
1725 TLinearOrder<TPsMatchLocation> order( CompareTPsMatchLocation ); |
|
1726 matchIndices.Sort( order ); |
|
1727 |
|
1728 TInt numberOfIndices = matchIndices.Count(); |
|
1729 TInt textOffset = 0; |
|
1730 |
|
1731 for (TInt i = 0; i < numberOfIndices ; i++ ) |
|
1732 { |
|
1733 TInt matchingPartStart = matchIndices[i].index; |
|
1734 TInt matchingPartLength = matchIndices[i].length; |
|
1735 |
|
1736 // Append the non-matching part (if exists) |
|
1737 if ( matchingPartStart > textOffset ) |
|
1738 { |
|
1739 TPtrC notMatchingPart = aText.Mid( textOffset, matchingPartStart - textOffset ); |
|
1740 aBuffer.Append( notMatchingPart ); |
|
1741 } |
|
1742 |
|
1743 // Append matching separator charactes. |
|
1744 aBuffer.Append( KHighlightSeparatorChar ); |
|
1745 |
|
1746 TPtrC matchingPart = aText.Mid( matchingPartStart, matchingPartLength ); |
|
1747 aBuffer.Append( matchingPart ); |
|
1748 |
|
1749 // Append matching separator charactes. |
|
1750 aBuffer.Append( KHighlightSeparatorChar ); |
|
1751 |
|
1752 textOffset = matchingPartStart + matchingPartLength; |
|
1753 } |
|
1754 |
|
1755 CleanupStack::PopAndDestroy( &matchIndices ); |
|
1756 CleanupStack::PopAndDestroy( matchingParts ); |
|
1757 |
|
1758 // Now there still may be one not matching part to be appended. |
|
1759 if ( textOffset < aText.Length() ) |
|
1760 { |
|
1761 TPtrC notMatchingPart = aText.Mid( textOffset, aText.Length() - textOffset ); |
|
1762 aBuffer.Append( notMatchingPart ); |
|
1763 } |
|
1764 } |
|
1765 else // HighlightingSupportedForText( aText ) |
|
1766 { |
|
1767 aBuffer.Append( aText ); |
|
1768 } |
|
1769 } |
|
1770 |
|
1771 // ----------------------------------------------------------------------------- |
|
1772 // HighlightingSupportedForText |
|
1773 // Checks if highlighting of matching text part is supported for the combination |
|
1774 // of scripts used in the given text |
|
1775 // ----------------------------------------------------------------------------- |
|
1776 // |
|
1777 TBool HighlightingSupportedForText( const TDesC& aText ) |
|
1778 { |
|
1779 // Highlighting for text is supported unless it contains one ore more |
|
1780 // characters written with unsupported script. |
|
1781 TBool supported = ETrue; |
|
1782 for ( TInt i = 0 ; i < aText.Length() && supported ; ++i ) |
|
1783 { |
|
1784 supported = HighlightingSupportedForScript( aText[i] ); |
|
1785 } |
|
1786 |
|
1787 // ... or it contains both LTR and RTL blocks |
|
1788 if ( supported ) |
|
1789 { |
|
1790 supported = !IsStrictlyBidirectional( aText ); |
|
1791 } |
|
1792 |
|
1793 return supported; |
|
1794 } |
|
1795 |
|
1796 // ----------------------------------------------------------------------------- |
|
1797 // HighlightingSupportedForScript |
|
1798 // Checks if highlighting of matching text part is supported for the script |
|
1799 // of given character |
|
1800 // ----------------------------------------------------------------------------- |
|
1801 // |
|
1802 TBool HighlightingSupportedForScript( TText aChar ) |
|
1803 { |
|
1804 // For now, we don't support highlighting for any Arabic or South East Asian |
|
1805 // script. This is because many of these scripts use rendering rules |
|
1806 // which cause problems for our simple highlighting logic designed for |
|
1807 // Latin script. |
|
1808 |
|
1809 TBool belongsToUnsupportedRange = |
|
1810 ( aChar >= KArabicAndSouthEastAsianRangeStart && aChar <= KArabicAndSouthEastAsianRangeEnd ) || |
|
1811 ( aChar >= KArabicPresentationFormsARangenStart && aChar <= KArabicPresentationFormsARangeEnd ) || |
|
1812 ( aChar >= KArabicPresentationFormsBRangenStart && aChar <= KArabicPresentationFormsBRangeEnd ); |
|
1813 return !belongsToUnsupportedRange; |
|
1814 } |
|
1815 |
|
1816 // ----------------------------------------------------------------------------- |
|
1817 // IsStrictlyBidirectional |
|
1818 // |
|
1819 // Returns true if argument descriptor contains both left-to-right and |
|
1820 // right-to-left blocks |
|
1821 // ----------------------------------------------------------------------------- |
|
1822 // |
|
1823 TBool IsStrictlyBidirectional( const TDesC& aText ) |
|
1824 { |
|
1825 TBool bothDirectionsFound = EFalse; |
|
1826 |
|
1827 // TRunInfoArray contains information of the directionalities of the different sections of the aText |
|
1828 TBidirectionalState::TRunInfo array[ KMaxRunInfoArrayCount ]; |
|
1829 |
|
1830 // Initialize the TBidiLogicalToVisual converter for making the conversion from logical to visual order |
|
1831 TBidiLogicalToVisual converter( aText, array, KMaxRunInfoArrayCount ); |
|
1832 |
|
1833 // Do the reordering. Amount of different directionality sections is returned. |
|
1834 TInt blockCount = converter.Reorder(); |
|
1835 if ( blockCount > KMaxRunInfoArrayCount ) |
|
1836 { |
|
1837 // If there are more directionality blocks than we are prepared to handle, then we don't |
|
1838 // know the directionality of them all. Report this as bidirectional to be on the safe side. |
|
1839 // This should be an extremely rare special case. |
|
1840 bothDirectionsFound = ETrue; |
|
1841 } |
|
1842 else if ( blockCount > 1 ) |
|
1843 { |
|
1844 // If there are more than one directionality blocks, go through all of them and |
|
1845 // check if the resolved direction changes in any of the blocks. |
|
1846 TUint8 firstDirection = array[0].iDirection; |
|
1847 for ( TInt i = 1 ; i < blockCount && !bothDirectionsFound ; i++ ) |
|
1848 { |
|
1849 if ( array[i].iDirection != firstDirection ) |
|
1850 { |
|
1851 bothDirectionsFound = ETrue; |
|
1852 } |
|
1853 } |
|
1854 } |
|
1855 |
|
1856 return bothDirectionsFound; |
|
1857 } |
|
1858 |
|
1859 |
|
1860 // ----------------------------------------------------------------------------- |
|
1861 // AllocWithoutHighlightSeparatorsLC |
|
1862 // |
|
1863 // Allocates a copy of the parameter descriptor with highlight separators |
|
1864 // removed. |
|
1865 // ----------------------------------------------------------------------------- |
|
1866 // |
|
1867 static HBufC* AllocWithoutHighlightSeparatorsLC( TDesC& aDesc ) |
|
1868 { |
|
1869 HBufC* resultDesc = aDesc.AllocLC(); |
|
1870 TPtr ptr = resultDesc->Des(); |
|
1871 AknTextUtils::StripCharacters( ptr, KHighlightSeparatorCharAsLiteral ); |
|
1872 return resultDesc; |
|
1873 } |
|
1874 |
|
1875 |
|
1876 // ----------------------------------------------------------------------------- |
|
1877 // IsItuTCharacter |
|
1878 // |
|
1879 // Test whether parameter character is a number pad character "0123456789#*+" |
|
1880 // ----------------------------------------------------------------------------- |
|
1881 // |
|
1882 static TBool IsItuTCharacter( TChar aChar ) |
|
1883 { |
|
1884 return aChar.IsDigit() || |
|
1885 aChar.GetCategory() == TChar::EArabicNumber || |
|
1886 aChar == TChar('#') || |
|
1887 aChar == TChar('*') || |
|
1888 aChar == TChar('+'); |
|
1889 } |
|
1890 |
|
1891 // End of File |
|
1892 |