telephonyutils/telephonywatchers/src/indicatorwatcher.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyutils/telephonywatchers/src/indicatorwatcher.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,520 @@
+// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+// User includes
+#include "watcherlog.h"
+#include "indicatorwatcher.h"
+
+// System includes
+#include <sacls.h>
+
+ #include <commsdat.h>
+
+//
+// ------> Global exports
+//
+
+
+//
+// ------> CIndicatorWatcher (source)
+//
+
+CIndicatorWatcher::CIndicatorWatcher()
+:	CPhoneWatcher()
+	{
+	}
+
+CIndicatorWatcher* CIndicatorWatcher::NewL(TAny* /*aWatcherParams*/)
+	{
+	CIndicatorWatcher* self= new (ELeave) CIndicatorWatcher();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CIndicatorWatcher::ConstructL()
+	{
+	CWatcherBase::ConstructL();
+	iCallStateWatcher = new (ELeave) CCallStateWatcher(Phone());
+	
+	/* Attach to properties for minimum access time */
+	User::LeaveIfError(iCurrentCallProperty.Attach(KUidSystemCategory, KUidCurrentCall.iUid)); 
+	User::LeaveIfError(iChargerStatusProperty.Attach(KUidSystemCategory, KUidChargerStatus.iUid)); 
+	User::LeaveIfError(iNetworkStatusProperty.Attach(KUidSystemCategory, KUidNetworkStatus.iUid)); 
+	}
+
+CIndicatorWatcher::~CIndicatorWatcher()
+	{
+	Cancel();
+	delete iCallStateWatcher;
+	iCurrentCallProperty.Close();
+	iChargerStatusProperty.Close();
+	iNetworkStatusProperty.Close();
+	}
+
+//
+//
+//
+
+void CIndicatorWatcher::HandlePhoneStateEventL(TInt aCompletionCode)
+	{
+	switch(IndicatorState())
+		{
+	case EIndicatorNotYetInitialised:
+	case EIndicatorRequestInitialIndicator:
+		LOGINDICATOR1("IndicatorWatcher : Requesting initial indicator values");
+		Phone().GetIndicator(iStatus, iIndicatorInfo);
+		IndicatorState() = EIndicatorWaitingForInitialIndicator;
+		SetActive();
+		break;
+
+	case EIndicatorWaitingForInitialIndicator:
+		IndicatorState() = EIndicatorIssuingIndicatorChangeNotification;
+		HandleIndicatorUpdateL(aCompletionCode);
+		break;
+
+	case EIndicatorIssuingIndicatorChangeNotification:
+		HandleIndicatorUpdateL(aCompletionCode);
+		break;
+
+	default:
+		__ASSERT_DEBUG(0, IndicatorPanic(EUnexpectedState));
+		}
+	}
+
+void CIndicatorWatcher::HandleCancel()
+	{
+	if	(Phone().SubSessionHandle() == KNullHandle)
+		return;
+
+	if	(IndicatorState() == EIndicatorWaitingForInitialIndicator)
+		Phone().CancelAsyncRequest(EMobilePhoneGetIndicator);
+	else if (IndicatorState() == EIndicatorIssuingIndicatorChangeNotification)
+		{
+		Phone().CancelAsyncRequest(EMobilePhoneNotifyIndicatorChange);
+		if (iCallStateWatcher)
+			iCallStateWatcher->Cancel();
+		}
+	}
+
+void CIndicatorWatcher::ReleasePhoneResources()
+//
+//	Called by the phone watcher base class. Release any telephony related
+//	resources and reset and state.
+//
+	{
+	// This is only called within RunL and therefore we can't be active
+	__ASSERT_DEBUG(!IsActive(), IndicatorPanic(EUnexpectedActiveState));
+
+	// Reset state
+	iState = EIndicatorNotYetInitialised;
+	}
+
+
+//
+//
+//
+
+void CIndicatorWatcher::HandleIndicatorUpdateL(TInt aCompletionCode)
+	{
+#ifdef _DEBUG
+	LOGINDICATOR2("IndicatorWatcher : Handling phone state change with request result (%d)", aCompletionCode);
+#else
+	(void) aCompletionCode;
+#endif
+
+#ifdef WATCHER_TESTING
+	// TESTING: 
+	{	
+	// Get a random number which controls what state we update...
+	TInt index;
+	User::LeaveIfError(RProperty::Get(KUidSystemCategory,KUidTestProp_CallStateChange.iUid, index));
+	switch(index)
+		{
+	default:
+	case 0: // CALL STATE
+		{
+		TSACurrentCall state = static_cast<TSACurrentCall>(WHelpers::Rand(ESACallNone, ESACallAlternating, TheSeed));
+		User::LeaveIfError(iCurrentCallProperty.Set(state));
+		break;
+		}
+
+	case 1: // BATTERY CHARGER
+		{
+		TSAChargerStatus state = static_cast<TSAChargerStatus>(WHelpers::Rand(ESAChargerConnected, ESAChargerNotCharging, TheSeed));
+		User::LeaveIfError(iChargerStatusProperty.Set(state));
+		break;
+		}
+
+	case 2: // NETWORK AVAILABILITY
+		{
+		TSANetworkStatus state = static_cast<TSANetworkStatus>(WHelpers::Rand(ESANetworkAvailable, ESANetworkUnAvailable, TheSeed));
+		User::LeaveIfError(iNetworkStatusProperty.Set(state));
+		break;
+		}
+		}
+
+	SuspendFor(10); // seconds
+	return;
+	}
+#else
+	if	(aCompletionCode < KErrNone)
+		{
+		// Indicate we don't know what the indicator status is
+		User::LeaveIfError(iCurrentCallProperty.Set(KErrUnknown));
+		User::LeaveIfError(iChargerStatusProperty.Set(KErrUnknown));
+		User::LeaveIfError(iNetworkStatusProperty.Set(KErrUnknown));
+
+		if	(aCompletionCode == KErrNotSupported)
+			{
+			// If the TSY returns 'Not supported' then it isn't 
+			// worth re-sending the request, so give up gracefully.
+			SetDisabled(_L("IndicatorNotifier : TSY returned not supported (%d)"), aCompletionCode);
+			}
+		else if	(aCompletionCode == KErrCancel)
+			{
+			// Indicator watcher was cancelled
+			SetDisabled(_L("IndicatorNotifier : TSY has cancelled request (%d)"), aCompletionCode);
+			}
+		else if	(aCompletionCode == KWatcherBaseModemNotDetected)
+			{
+			// We should release all telephony related resources until the
+			// phone is available again.
+			Cancel();
+			Reset();
+
+			// The modem / phone cannot be found. Wait until it becomes available again...
+			WaitForPhoneToPowerUpL();
+			}
+		else if	(ErrorCountIncrement() >= KErrorRetryCount)
+			{
+			// We've already tried as many times as possible. Shut ourselves down forever.
+			// This watcher will be restarted when the machine is rebooted.
+			SetDisabled(_L("IndicatorNotifier : Max retries reached or exceeded. Shutting down until reboot."), 0);
+			}
+		else
+			SuspendFor(KErrorRetryPausePeriod);
+		}
+	else
+		{
+		LOGINDICATOR1("IndicatorWatcher : Processing successful indicator event");
+	
+		// Update charger status if there has been a change
+		{
+		TInt chargerState;
+		User::LeaveIfError(iChargerStatusProperty.Get(chargerState));
+		
+		TInt newChargerState=KErrUnknown;
+
+		if (iIndicatorInfo & RMobilePhone::KIndChargerConnected)
+			newChargerState=ESAChargerConnected;
+		else
+			newChargerState=ESAChargerDisconnected;
+	
+		if (newChargerState!=chargerState)
+			{
+			LOGINDICATOR2("IndicatorWatcher : New Charger State %d", newChargerState);
+			User::LeaveIfError(iChargerStatusProperty.Set(newChargerState));
+			}
+		}
+
+		// Update network available status if there has been a change
+		{
+		TInt networkState;
+		User::LeaveIfError(iNetworkStatusProperty.Get(networkState));		
+		TInt newNetworkState=KErrUnknown;
+
+		if (iIndicatorInfo & RMobilePhone::KIndNetworkAvailable)
+			newNetworkState=ESANetworkAvailable;
+		else
+			newNetworkState=ESANetworkUnAvailable;
+	
+		if (newNetworkState!=networkState)
+			{
+			LOGINDICATOR2("IndicatorWatcher : New Network State %d", newNetworkState);
+			User::LeaveIfError(iNetworkStatusProperty.Set(newNetworkState));		
+			}
+		}
+
+		// Update call-in-progress status if there has been a change
+		{
+		TInt callState;
+		User::LeaveIfError(iCurrentCallProperty.Get(callState));
+		TInt newCallState=KErrUnknown;
+
+		if ((iIndicatorInfo & RMobilePhone::KIndCallInProgress) && 
+			(callState <= ESACallNone))
+			{
+			newCallState=iCallStateWatcher->StartCallStateMonitor();
+			}
+		else if (!(iIndicatorInfo & RMobilePhone::KIndCallInProgress))
+			{
+			iCallStateWatcher->Cancel();
+			newCallState=ESACallNone;
+			}
+	
+		if (newCallState!=callState)
+			{
+			LOGINDICATOR2("IndicatorWatcher : New Call State %d", newCallState);
+			User::LeaveIfError(iCurrentCallProperty.Set(newCallState));
+			}
+		}
+
+		// Issue another request
+		Phone().NotifyIndicatorChange(iStatus, iIndicatorInfo);
+		SetActive();
+		}
+#endif
+	}
+
+//
+//
+//
+//
+
+CCallStateWatcher::CCallStateWatcher(RMobilePhone& aPhone, TInt aPriority)
+:	CActive(aPriority), iPhone(aPhone)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CCallStateWatcher::~CCallStateWatcher()
+	{
+	Cancel();
+	}
+
+TInt CCallStateWatcher::StartCallStateMonitor()
+	{
+	TInt state=KErrUnknown;
+	TInt lineCount = 0;
+
+	// Find the line and call to open permanently
+	TInt error = iPhone.EnumerateLines(lineCount);
+	if	(error)
+		return state;
+
+	for(TInt i = 0; i<lineCount; i++)
+		{
+		RPhone::TLineInfo lineInfo;
+		error = iPhone.GetLineInfo(i, lineInfo);
+		if (error)
+			break; // and return state unknown
+
+		error = iLine.Open(iPhone,lineInfo.iName);
+		if (error)
+			break; // and return state unknown
+		
+		TInt callCount=0;
+		error = iLine.EnumerateCall(callCount);
+		if (error)
+			{
+			iLine.Close();
+			break;
+			}
+
+// There may be more than one call - but this watcher only supports
+// monitoring first call found
+		RLine::TCallInfo callInfo;
+		TBool found=EFalse;
+		for(TInt i=0;i<callCount;i++)
+			{
+			error = iLine.GetCallInfo(i,callInfo);
+			if((error==KErrNone)&&
+			   (callInfo.iStatus!=RCall::EStatusIdle)&&
+			   (callInfo.iStatus!=RCall::EStatusUnknown))
+				{
+				found=ETrue;
+				break;
+				}
+			}
+
+		if(found)
+			{
+			error = iCall.OpenExistingCall(iLine, callInfo.iCallName);
+			if (error)
+				{
+				// Found the line to monitor but can't open call
+				iLine.Close();
+				return state;
+				}
+
+			state = GetCallState();
+
+			if (state!=KErrUnknown)
+				{
+				// Now monitor for further state changes
+				iCall.NotifyMobileCallStatusChange(iStatus,iCallState);
+				SetActive();
+				break;
+				}
+			else
+				{
+				iCall.Close();
+				iLine.Close();
+				return state;
+				}
+
+			} // end of if (callCount>0)
+		else
+			{
+			// Close this line and look at next one
+			iLine.Close();
+			}
+
+		} // end of for loop
+
+	return state;
+	}
+
+
+void CCallStateWatcher::RunL()
+	{
+	if (iStatus.Int() == KErrNone)
+		{
+		TInt callState;
+		User::LeaveIfError(RProperty::Get(KUidSystemCategory, KUidCurrentCall.iUid, callState));
+		
+		TInt newCallState=KErrUnknown;
+
+		newCallState=GetCallState();
+
+		if (newCallState!=callState)
+			User::LeaveIfError(RProperty::Set(KUidSystemCategory,KUidCurrentCall.iUid,newCallState));
+			
+		if (newCallState != KErrUnknown)
+			{
+			// Now monitor for further state changes
+			iCall.NotifyMobileCallStatusChange(iStatus,iCallState);
+			SetActive();
+			}
+		else
+			{
+			iCall.Close();
+			iLine.Close();
+			}
+		}
+	else
+		{
+		iCall.Close();
+		iLine.Close();
+		}
+	}
+
+
+void CCallStateWatcher::DoCancel()
+	{
+	iCall.CancelAsyncRequest(EMobileCallNotifyMobileCallStatusChange);
+	iCall.Close();
+	iLine.Close();
+	}
+
+TInt CCallStateWatcher::RunError(TInt /*aError*/)
+	{
+	// Release resources
+	iCall.Close();
+	iLine.Close();
+	return KErrNone;
+	}
+
+TInt CCallStateWatcher::GetCallState()
+	{
+	TInt state=KErrUnknown;
+
+	RMobileCall::TMobileCallInfoV1 info;
+	RMobileCall::TMobileCallInfoV1Pckg infoPckg(info);
+
+	TInt error = iCall.GetMobileCallInfo(infoPckg);
+	if	(error)
+		{
+		// Found the call to monitor but can't get information
+		return state;
+		}
+
+	switch (info.iStatus)
+		{
+	case RMobileCall::EStatusRinging:
+		state = ESACallRinging;
+		break;
+	case RMobileCall::EStatusDialling:
+		state = ESACallDialling;
+		break;
+	case RMobileCall::EStatusConnecting:
+		state = ESACallAlerting;
+		break;
+	case RMobileCall::EStatusAnswering:
+		state = ESACallAnswering;
+		break;
+	case RMobileCall::EStatusDisconnecting:
+	case RMobileCall::EStatusDisconnectingWithInband:
+		state = ESACallDisconnecting;
+		break;
+	case RMobileCall::EStatusConnected:
+	case RMobileCall::EStatusHold:
+	case RMobileCall::EStatusReconnectPending:
+		{
+		// Call is connected, so update with type of connected call
+		if((info.iValid & RMobileCall::KCallAlternating)&&
+		   (info.iAlternatingCall != RMobilePhone::EAlternatingModeSingle))
+			state = ESACallAlternating;
+		else
+			{
+			switch (info.iService)
+				{
+			case RMobilePhone::EVoiceService:
+			case RMobilePhone::EAuxVoiceService:
+				state = ESACallVoice;
+				break;
+			case RMobilePhone::ECircuitDataService:
+				state = ESACallData;
+				break;
+			case RMobilePhone::EFaxService:
+				state = ESACallFax;
+				break;
+			default:
+				// Not a valid call service
+				break;
+				}
+			}
+		}
+		break;
+	default:
+		// must be idle state - or special idle state
+		state = ESACallNone;
+		break;
+		}
+
+	return state;
+	}
+
+//
+//
+//
+
+//
+// Panic Function
+//
+void CIndicatorWatcher::IndicatorPanic(TWatcherPanic aPanicNumber)
+	{
+	_LIT(panicText,"Indicator Watcher");
+	User::Panic(panicText,aPanicNumber);
+	}
+
+
+
+
+
+
+