telephonyutils/telephonywatchers/src/indicatorwatcher.cpp
changeset 0 3553901f7fa8
child 24 6638e7f4bd8f
child 42 3adadc800673
equal deleted inserted replaced
-1:000000000000 0:3553901f7fa8
       
     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