|
1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 // User includes |
|
17 #include "watcherlog.h" |
|
18 #include "indicatorwatcher.h" |
|
19 |
|
20 // System includes |
|
21 #include <sacls.h> |
|
22 |
|
23 #include <commsdat.h> |
|
24 |
|
25 // |
|
26 // ------> Global exports |
|
27 // |
|
28 |
|
29 |
|
30 // |
|
31 // ------> CIndicatorWatcher (source) |
|
32 // |
|
33 |
|
34 CIndicatorWatcher::CIndicatorWatcher() |
|
35 : CPhoneWatcher() |
|
36 { |
|
37 } |
|
38 |
|
39 CIndicatorWatcher* CIndicatorWatcher::NewL(TAny* /*aWatcherParams*/) |
|
40 { |
|
41 CIndicatorWatcher* self= new (ELeave) CIndicatorWatcher(); |
|
42 CleanupStack::PushL(self); |
|
43 self->ConstructL(); |
|
44 CleanupStack::Pop(); |
|
45 return self; |
|
46 } |
|
47 |
|
48 void CIndicatorWatcher::ConstructL() |
|
49 { |
|
50 CWatcherBase::ConstructL(); |
|
51 iCallStateWatcher = new (ELeave) CCallStateWatcher(Phone()); |
|
52 |
|
53 /* Attach to properties for minimum access time */ |
|
54 User::LeaveIfError(iCurrentCallProperty.Attach(KUidSystemCategory, KUidCurrentCall.iUid)); |
|
55 User::LeaveIfError(iChargerStatusProperty.Attach(KUidSystemCategory, KUidChargerStatus.iUid)); |
|
56 User::LeaveIfError(iNetworkStatusProperty.Attach(KUidSystemCategory, KUidNetworkStatus.iUid)); |
|
57 } |
|
58 |
|
59 CIndicatorWatcher::~CIndicatorWatcher() |
|
60 { |
|
61 Cancel(); |
|
62 delete iCallStateWatcher; |
|
63 iCurrentCallProperty.Close(); |
|
64 iChargerStatusProperty.Close(); |
|
65 iNetworkStatusProperty.Close(); |
|
66 } |
|
67 |
|
68 // |
|
69 // |
|
70 // |
|
71 |
|
72 void CIndicatorWatcher::HandlePhoneStateEventL(TInt aCompletionCode) |
|
73 { |
|
74 switch(IndicatorState()) |
|
75 { |
|
76 case EIndicatorNotYetInitialised: |
|
77 case EIndicatorRequestInitialIndicator: |
|
78 LOGINDICATOR1("IndicatorWatcher : Requesting initial indicator values"); |
|
79 Phone().GetIndicator(iStatus, iIndicatorInfo); |
|
80 IndicatorState() = EIndicatorWaitingForInitialIndicator; |
|
81 SetActive(); |
|
82 break; |
|
83 |
|
84 case EIndicatorWaitingForInitialIndicator: |
|
85 IndicatorState() = EIndicatorIssuingIndicatorChangeNotification; |
|
86 HandleIndicatorUpdateL(aCompletionCode); |
|
87 break; |
|
88 |
|
89 case EIndicatorIssuingIndicatorChangeNotification: |
|
90 HandleIndicatorUpdateL(aCompletionCode); |
|
91 break; |
|
92 |
|
93 default: |
|
94 __ASSERT_DEBUG(0, IndicatorPanic(EUnexpectedState)); |
|
95 } |
|
96 } |
|
97 |
|
98 void CIndicatorWatcher::HandleCancel() |
|
99 { |
|
100 if (Phone().SubSessionHandle() == KNullHandle) |
|
101 return; |
|
102 |
|
103 if (IndicatorState() == EIndicatorWaitingForInitialIndicator) |
|
104 Phone().CancelAsyncRequest(EMobilePhoneGetIndicator); |
|
105 else if (IndicatorState() == EIndicatorIssuingIndicatorChangeNotification) |
|
106 { |
|
107 Phone().CancelAsyncRequest(EMobilePhoneNotifyIndicatorChange); |
|
108 if (iCallStateWatcher) |
|
109 iCallStateWatcher->Cancel(); |
|
110 } |
|
111 } |
|
112 |
|
113 void CIndicatorWatcher::ReleasePhoneResources() |
|
114 // |
|
115 // Called by the phone watcher base class. Release any telephony related |
|
116 // resources and reset and state. |
|
117 // |
|
118 { |
|
119 // This is only called within RunL and therefore we can't be active |
|
120 __ASSERT_DEBUG(!IsActive(), IndicatorPanic(EUnexpectedActiveState)); |
|
121 |
|
122 // Reset state |
|
123 iState = EIndicatorNotYetInitialised; |
|
124 } |
|
125 |
|
126 |
|
127 // |
|
128 // |
|
129 // |
|
130 |
|
131 void CIndicatorWatcher::HandleIndicatorUpdateL(TInt aCompletionCode) |
|
132 { |
|
133 #ifdef _DEBUG |
|
134 LOGINDICATOR2("IndicatorWatcher : Handling phone state change with request result (%d)", aCompletionCode); |
|
135 #else |
|
136 (void) aCompletionCode; |
|
137 #endif |
|
138 |
|
139 #ifdef WATCHER_TESTING |
|
140 // TESTING: |
|
141 { |
|
142 // Get a random number which controls what state we update... |
|
143 TInt index; |
|
144 User::LeaveIfError(RProperty::Get(KUidSystemCategory,KUidTestProp_CallStateChange.iUid, index)); |
|
145 switch(index) |
|
146 { |
|
147 default: |
|
148 case 0: // CALL STATE |
|
149 { |
|
150 TSACurrentCall state = static_cast<TSACurrentCall>(WHelpers::Rand(ESACallNone, ESACallAlternating, TheSeed)); |
|
151 User::LeaveIfError(iCurrentCallProperty.Set(state)); |
|
152 break; |
|
153 } |
|
154 |
|
155 case 1: // BATTERY CHARGER |
|
156 { |
|
157 TSAChargerStatus state = static_cast<TSAChargerStatus>(WHelpers::Rand(ESAChargerConnected, ESAChargerNotCharging, TheSeed)); |
|
158 User::LeaveIfError(iChargerStatusProperty.Set(state)); |
|
159 break; |
|
160 } |
|
161 |
|
162 case 2: // NETWORK AVAILABILITY |
|
163 { |
|
164 TSANetworkStatus state = static_cast<TSANetworkStatus>(WHelpers::Rand(ESANetworkAvailable, ESANetworkUnAvailable, TheSeed)); |
|
165 User::LeaveIfError(iNetworkStatusProperty.Set(state)); |
|
166 break; |
|
167 } |
|
168 } |
|
169 |
|
170 SuspendFor(10); // seconds |
|
171 return; |
|
172 } |
|
173 #else |
|
174 if (aCompletionCode < KErrNone) |
|
175 { |
|
176 // Indicate we don't know what the indicator status is |
|
177 User::LeaveIfError(iCurrentCallProperty.Set(KErrUnknown)); |
|
178 User::LeaveIfError(iChargerStatusProperty.Set(KErrUnknown)); |
|
179 User::LeaveIfError(iNetworkStatusProperty.Set(KErrUnknown)); |
|
180 |
|
181 if (aCompletionCode == KErrNotSupported) |
|
182 { |
|
183 // If the TSY returns 'Not supported' then it isn't |
|
184 // worth re-sending the request, so give up gracefully. |
|
185 SetDisabled(_L("IndicatorNotifier : TSY returned not supported (%d)"), aCompletionCode); |
|
186 } |
|
187 else if (aCompletionCode == KErrCancel) |
|
188 { |
|
189 // Indicator watcher was cancelled |
|
190 SetDisabled(_L("IndicatorNotifier : TSY has cancelled request (%d)"), aCompletionCode); |
|
191 } |
|
192 else if (aCompletionCode == KWatcherBaseModemNotDetected) |
|
193 { |
|
194 // We should release all telephony related resources until the |
|
195 // phone is available again. |
|
196 Cancel(); |
|
197 Reset(); |
|
198 |
|
199 // The modem / phone cannot be found. Wait until it becomes available again... |
|
200 WaitForPhoneToPowerUpL(); |
|
201 } |
|
202 else if (ErrorCountIncrement() >= KErrorRetryCount) |
|
203 { |
|
204 // We've already tried as many times as possible. Shut ourselves down forever. |
|
205 // This watcher will be restarted when the machine is rebooted. |
|
206 SetDisabled(_L("IndicatorNotifier : Max retries reached or exceeded. Shutting down until reboot."), 0); |
|
207 } |
|
208 else |
|
209 SuspendFor(KErrorRetryPausePeriod); |
|
210 } |
|
211 else |
|
212 { |
|
213 LOGINDICATOR1("IndicatorWatcher : Processing successful indicator event"); |
|
214 |
|
215 // Update charger status if there has been a change |
|
216 { |
|
217 TInt chargerState; |
|
218 User::LeaveIfError(iChargerStatusProperty.Get(chargerState)); |
|
219 |
|
220 TInt newChargerState=KErrUnknown; |
|
221 |
|
222 if (iIndicatorInfo & RMobilePhone::KIndChargerConnected) |
|
223 newChargerState=ESAChargerConnected; |
|
224 else |
|
225 newChargerState=ESAChargerDisconnected; |
|
226 |
|
227 if (newChargerState!=chargerState) |
|
228 { |
|
229 LOGINDICATOR2("IndicatorWatcher : New Charger State %d", newChargerState); |
|
230 User::LeaveIfError(iChargerStatusProperty.Set(newChargerState)); |
|
231 } |
|
232 } |
|
233 |
|
234 // Update network available status if there has been a change |
|
235 { |
|
236 TInt networkState; |
|
237 User::LeaveIfError(iNetworkStatusProperty.Get(networkState)); |
|
238 TInt newNetworkState=KErrUnknown; |
|
239 |
|
240 if (iIndicatorInfo & RMobilePhone::KIndNetworkAvailable) |
|
241 newNetworkState=ESANetworkAvailable; |
|
242 else |
|
243 newNetworkState=ESANetworkUnAvailable; |
|
244 |
|
245 if (newNetworkState!=networkState) |
|
246 { |
|
247 LOGINDICATOR2("IndicatorWatcher : New Network State %d", newNetworkState); |
|
248 User::LeaveIfError(iNetworkStatusProperty.Set(newNetworkState)); |
|
249 } |
|
250 } |
|
251 |
|
252 // Update call-in-progress status if there has been a change |
|
253 { |
|
254 TInt callState; |
|
255 User::LeaveIfError(iCurrentCallProperty.Get(callState)); |
|
256 TInt newCallState=KErrUnknown; |
|
257 |
|
258 if ((iIndicatorInfo & RMobilePhone::KIndCallInProgress) && |
|
259 (callState <= ESACallNone)) |
|
260 { |
|
261 newCallState=iCallStateWatcher->StartCallStateMonitor(); |
|
262 } |
|
263 else if (!(iIndicatorInfo & RMobilePhone::KIndCallInProgress)) |
|
264 { |
|
265 iCallStateWatcher->Cancel(); |
|
266 newCallState=ESACallNone; |
|
267 } |
|
268 |
|
269 if (newCallState!=callState) |
|
270 { |
|
271 LOGINDICATOR2("IndicatorWatcher : New Call State %d", newCallState); |
|
272 User::LeaveIfError(iCurrentCallProperty.Set(newCallState)); |
|
273 } |
|
274 } |
|
275 |
|
276 // Issue another request |
|
277 Phone().NotifyIndicatorChange(iStatus, iIndicatorInfo); |
|
278 SetActive(); |
|
279 } |
|
280 #endif |
|
281 } |
|
282 |
|
283 // |
|
284 // |
|
285 // |
|
286 // |
|
287 |
|
288 CCallStateWatcher::CCallStateWatcher(RMobilePhone& aPhone, TInt aPriority) |
|
289 : CActive(aPriority), iPhone(aPhone) |
|
290 { |
|
291 CActiveScheduler::Add(this); |
|
292 } |
|
293 |
|
294 CCallStateWatcher::~CCallStateWatcher() |
|
295 { |
|
296 Cancel(); |
|
297 } |
|
298 |
|
299 TInt CCallStateWatcher::StartCallStateMonitor() |
|
300 { |
|
301 TInt state=KErrUnknown; |
|
302 TInt lineCount = 0; |
|
303 |
|
304 // Find the line and call to open permanently |
|
305 TInt error = iPhone.EnumerateLines(lineCount); |
|
306 if (error) |
|
307 return state; |
|
308 |
|
309 for(TInt i = 0; i<lineCount; i++) |
|
310 { |
|
311 RPhone::TLineInfo lineInfo; |
|
312 error = iPhone.GetLineInfo(i, lineInfo); |
|
313 if (error) |
|
314 break; // and return state unknown |
|
315 |
|
316 error = iLine.Open(iPhone,lineInfo.iName); |
|
317 if (error) |
|
318 break; // and return state unknown |
|
319 |
|
320 TInt callCount=0; |
|
321 error = iLine.EnumerateCall(callCount); |
|
322 if (error) |
|
323 { |
|
324 iLine.Close(); |
|
325 break; |
|
326 } |
|
327 |
|
328 // There may be more than one call - but this watcher only supports |
|
329 // monitoring first call found |
|
330 RLine::TCallInfo callInfo; |
|
331 TBool found=EFalse; |
|
332 for(TInt i=0;i<callCount;i++) |
|
333 { |
|
334 error = iLine.GetCallInfo(i,callInfo); |
|
335 if((error==KErrNone)&& |
|
336 (callInfo.iStatus!=RCall::EStatusIdle)&& |
|
337 (callInfo.iStatus!=RCall::EStatusUnknown)) |
|
338 { |
|
339 found=ETrue; |
|
340 break; |
|
341 } |
|
342 } |
|
343 |
|
344 if(found) |
|
345 { |
|
346 error = iCall.OpenExistingCall(iLine, callInfo.iCallName); |
|
347 if (error) |
|
348 { |
|
349 // Found the line to monitor but can't open call |
|
350 iLine.Close(); |
|
351 return state; |
|
352 } |
|
353 |
|
354 state = GetCallState(); |
|
355 |
|
356 if (state!=KErrUnknown) |
|
357 { |
|
358 // Now monitor for further state changes |
|
359 iCall.NotifyMobileCallStatusChange(iStatus,iCallState); |
|
360 SetActive(); |
|
361 break; |
|
362 } |
|
363 else |
|
364 { |
|
365 iCall.Close(); |
|
366 iLine.Close(); |
|
367 return state; |
|
368 } |
|
369 |
|
370 } // end of if (callCount>0) |
|
371 else |
|
372 { |
|
373 // Close this line and look at next one |
|
374 iLine.Close(); |
|
375 } |
|
376 |
|
377 } // end of for loop |
|
378 |
|
379 return state; |
|
380 } |
|
381 |
|
382 |
|
383 void CCallStateWatcher::RunL() |
|
384 { |
|
385 if (iStatus.Int() == KErrNone) |
|
386 { |
|
387 TInt callState; |
|
388 User::LeaveIfError(RProperty::Get(KUidSystemCategory, KUidCurrentCall.iUid, callState)); |
|
389 |
|
390 TInt newCallState=KErrUnknown; |
|
391 |
|
392 newCallState=GetCallState(); |
|
393 |
|
394 if (newCallState!=callState) |
|
395 User::LeaveIfError(RProperty::Set(KUidSystemCategory,KUidCurrentCall.iUid,newCallState)); |
|
396 |
|
397 if (newCallState != KErrUnknown) |
|
398 { |
|
399 // Now monitor for further state changes |
|
400 iCall.NotifyMobileCallStatusChange(iStatus,iCallState); |
|
401 SetActive(); |
|
402 } |
|
403 else |
|
404 { |
|
405 iCall.Close(); |
|
406 iLine.Close(); |
|
407 } |
|
408 } |
|
409 else |
|
410 { |
|
411 iCall.Close(); |
|
412 iLine.Close(); |
|
413 } |
|
414 } |
|
415 |
|
416 |
|
417 void CCallStateWatcher::DoCancel() |
|
418 { |
|
419 iCall.CancelAsyncRequest(EMobileCallNotifyMobileCallStatusChange); |
|
420 iCall.Close(); |
|
421 iLine.Close(); |
|
422 } |
|
423 |
|
424 TInt CCallStateWatcher::RunError(TInt /*aError*/) |
|
425 { |
|
426 // Release resources |
|
427 iCall.Close(); |
|
428 iLine.Close(); |
|
429 return KErrNone; |
|
430 } |
|
431 |
|
432 TInt CCallStateWatcher::GetCallState() |
|
433 { |
|
434 TInt state=KErrUnknown; |
|
435 |
|
436 RMobileCall::TMobileCallInfoV1 info; |
|
437 RMobileCall::TMobileCallInfoV1Pckg infoPckg(info); |
|
438 |
|
439 TInt error = iCall.GetMobileCallInfo(infoPckg); |
|
440 if (error) |
|
441 { |
|
442 // Found the call to monitor but can't get information |
|
443 return state; |
|
444 } |
|
445 |
|
446 switch (info.iStatus) |
|
447 { |
|
448 case RMobileCall::EStatusRinging: |
|
449 state = ESACallRinging; |
|
450 break; |
|
451 case RMobileCall::EStatusDialling: |
|
452 state = ESACallDialling; |
|
453 break; |
|
454 case RMobileCall::EStatusConnecting: |
|
455 state = ESACallAlerting; |
|
456 break; |
|
457 case RMobileCall::EStatusAnswering: |
|
458 state = ESACallAnswering; |
|
459 break; |
|
460 case RMobileCall::EStatusDisconnecting: |
|
461 case RMobileCall::EStatusDisconnectingWithInband: |
|
462 state = ESACallDisconnecting; |
|
463 break; |
|
464 case RMobileCall::EStatusConnected: |
|
465 case RMobileCall::EStatusHold: |
|
466 case RMobileCall::EStatusReconnectPending: |
|
467 { |
|
468 // Call is connected, so update with type of connected call |
|
469 if((info.iValid & RMobileCall::KCallAlternating)&& |
|
470 (info.iAlternatingCall != RMobilePhone::EAlternatingModeSingle)) |
|
471 state = ESACallAlternating; |
|
472 else |
|
473 { |
|
474 switch (info.iService) |
|
475 { |
|
476 case RMobilePhone::EVoiceService: |
|
477 case RMobilePhone::EAuxVoiceService: |
|
478 state = ESACallVoice; |
|
479 break; |
|
480 case RMobilePhone::ECircuitDataService: |
|
481 state = ESACallData; |
|
482 break; |
|
483 case RMobilePhone::EFaxService: |
|
484 state = ESACallFax; |
|
485 break; |
|
486 default: |
|
487 // Not a valid call service |
|
488 break; |
|
489 } |
|
490 } |
|
491 } |
|
492 break; |
|
493 default: |
|
494 // must be idle state - or special idle state |
|
495 state = ESACallNone; |
|
496 break; |
|
497 } |
|
498 |
|
499 return state; |
|
500 } |
|
501 |
|
502 // |
|
503 // |
|
504 // |
|
505 |
|
506 // |
|
507 // Panic Function |
|
508 // |
|
509 void CIndicatorWatcher::IndicatorPanic(TWatcherPanic aPanicNumber) |
|
510 { |
|
511 _LIT(panicText,"Indicator Watcher"); |
|
512 User::Panic(panicText,aPanicNumber); |
|
513 } |
|
514 |
|
515 |
|
516 |
|
517 |
|
518 |
|
519 |
|
520 |