idlefw/plugins/devicestatus/src/ainetworkinfolistener.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 14 Sep 2010 21:55:16 +0300
branchRCL_3
changeset 31 8baec10861af
parent 30 a5a39a295112
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2005-2010 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:  Network info listener.
*
*/


#include <NetworkHandlingProxy.h>
#include <CNWSession.h>
#include "ainetworkinfolistener.h"
#include "ainetworkinfoobserver.h"
#include "debug.h"
#include <exterror.h>      // for KErrGsmMMNetworkFailure
#include <featmgr.h>       // for FeatureManager

const TInt KAiMessageCacheGranularity = 4;

// ======== MEMBER FUNCTIONS ========

CAiNetworkInfoListener::CAiNetworkInfoListener()
: iKeyProperties( 0, ECmpTInt )
    {
    }


void CAiNetworkInfoListener::ConstructL()
    {
	//Store pointer in TLS
    User::LeaveIfError( Dll::SetTls( this ) );

    //Create network handling engine session.
    iSession = CreateL( *this, iInfo );
    iShowOpInd = EFalse;
    //Create message cache
    iMessageCache = new( ELeave )CArrayFixFlat
        <MNWMessageObserver::TNWMessages>( KAiMessageCacheGranularity );
    }


CAiNetworkInfoListener* CAiNetworkInfoListener::InstanceL()
    {
    CAiNetworkInfoListener* self = static_cast<CAiNetworkInfoListener*>( Dll::Tls() );

    if( !self )
        {
		//If instance of network listener is not already constructed, create it
        self = new( ELeave ) CAiNetworkInfoListener;
        CleanupStack::PushL( self );
        self->ConstructL();
        CleanupStack::Pop( self );
        }

	//increase access count
    self->IncAccessCount();
    return self;
    }


void CAiNetworkInfoListener::Release()
    {
	//Decrease access count, if it goes to zero, delete object.
    if( !DecAccessCount() )
        {
        delete this;
        }
    }


CAiNetworkInfoListener::~CAiNetworkInfoListener()
    {
	//Remove object from TLS
    Dll::SetTls( NULL );
    iObservers.Reset();
    delete iSession;
    delete iMessageCache;
    }


TInt CAiNetworkInfoListener::IncAccessCount()
    {
    return iAccessCount++;
    }

TInt CAiNetworkInfoListener::DecAccessCount()
    {
    return --iAccessCount;
    }


void CAiNetworkInfoListener::AddObserverL( MAiNetworkInfoObserver& aObserver )
    {
    
    if ( iObservers.Find( &aObserver ) == KErrNotFound)
        {
        //Removing observer doesn't remove slots from array, removed observers are only
        //set to NULL. Reason for this is found out later on the code. Adding observer
        //first tries to find free slot, if it is not found, observer is appended to the
        //array.
        TInt freeSlot = iObservers.Find( NULL );
    
        if( freeSlot == KErrNotFound )
            {
            User::LeaveIfError( iObservers.Append( &aObserver ) );
            }
        else
            {
            User::LeaveIfError( iObservers.Insert( &aObserver, freeSlot ) );
            }
        }
   }

void CAiNetworkInfoListener::RemoveObserver( MAiNetworkInfoObserver& aObserver )
    {
    TInt slot = iObservers.Find( &aObserver );
    
    if (slot != KErrNotFound )
        {
        //Remove observer, removing is done by replacing it with NULL pointer.
        iObservers.Remove( slot );
        iObservers.Insert( NULL, slot );
        }
    }


const TNWInfo& CAiNetworkInfoListener::NetworkInfo() const
    {
    return iInfo;
    }

TBool CAiNetworkInfoListener::IsOperatorIndicatorAllowed() const
    {
    return iShowOpInd;
    }

TBool CAiNetworkInfoListener::MessageReceived( MNWMessageObserver::TNWMessages aMessage )
    {
	//check if the message is in message cache.
    TInt index( KErrNotFound );
    TBool found = ( iMessageCache->FindIsq( aMessage, iKeyProperties, index ) == 0 );
    return found;
    }


void CAiNetworkInfoListener::HandleNetworkMessage( const TNWMessages aMessage )
    {
    __PRINT(__DBG_FORMAT("XAI: CAiNetworkInfoListener > Handle NW message %d"), aMessage );
    
    __PRINT(__DBG_FORMAT("XAI: iInfo.iRegistrationStatus %d"), iInfo.iRegistrationStatus );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iStatus %d"), iInfo.iStatus );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iCountryCode %S"), &iInfo.iCountryCode );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iNetworkId %S"), &iInfo.iNetworkId );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iOperatorNameInfo.iType %d"), iInfo.iOperatorNameInfo.iType );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iOperatorNameInfo.iName %S"), &iInfo.iOperatorNameInfo.iName );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iDisplayTag %S"), &iInfo.iDisplayTag );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iShortName %S"), &iInfo.iShortName );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iLongName %S"), &iInfo.iLongName );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iSPName %S"), &iInfo.iSPName );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iServiceProviderNameDisplayReq %d"), iInfo.iServiceProviderNameDisplayReq );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iNPName %S"), &iInfo.iNPName );
    __PRINT(__DBG_FORMAT("XAI: iInfo.iPLMNField %S"), &iInfo.iPLMNField );
    
    //Insert message into the message cache. Only one messsage of one type.
    TRAPD( err, iMessageCache->InsertIsqL( aMessage, iKeyProperties ) );
    if( err == KErrAlreadyExists )
        {
        __PRINTS("XAI: message already exists in cache");
        err = KErrNone;
        }
    if( err != KErrNone )
        {
        __PRINTS("XAI: error inserting message to cache , return");
        return;
        }

    __PRINTS("XAI: check if allowed to display operator indicator");
	iShowOpInd 		= !NotAllowedToDisplayOperatorIndicator( aMessage );

	TBool hasNetInfoChanged = HasNetworkInfoChanged( aMessage );
	if ( !hasNetInfoChanged )
		{
	    __PRINTS("XAI: net info not changed, return");
		return;
		}

	__PRINT(__DBG_FORMAT("XAI: Show operator indicator %d, info changed %d"), iShowOpInd, hasNetInfoChanged );
    const TInt count( iObservers.Count() );


    for( TInt i( 0 ); i < count; i++ )
        {
		//Observer might be NULL. When HandleNetworkInfoChange is called, it may
		//cause deleting of the publisher which means that observer is removed from listener.
		//This is the reason why observer pointers are replaced by NULL when it is removed
		//from this listener. If the slot would be removed, it would easily cause index overflow
		//or missing HandleNetworkInfoChange calls.
		//For example lets assume that we have 5 observers, we are going in loop 3, so variable i
		//has value 2. When third call is done, it would cause two publishers to be deleted and
		//observers removed. Lets assume that these observers are in place 0 and 1. So now we have
		//only 3 observers and the count is still 2. So we miss a call to a observers in index 3 and 4.

        if( iObservers[i] )
            {
            iObservers[i]->HandleNetworkInfoChange( aMessage, iInfo, iShowOpInd );
            }
        }
    }


void CAiNetworkInfoListener::HandleNetworkError( const TNWOperation aOperation, TInt aErrorCode )
    {
    __PRINT(__DBG_FORMAT("XAI: CAiNetworkInfoListener > NetworkError code %d"), aErrorCode );

    TNWMessages errorCode = TNWMessages( KErrGeneral );

    switch ( aOperation )
        {
        case MNWMessageObserver::ENWGetNetworkProviderName:
            iReceivedMessageFlags |= ENetworkProviderNameReceived;
            iReceivedMessageFlags &= ~ENetworkProviderNameOk;
            iInfo.iNPName.Zero();
            __PRINTS("XAI: NPN error received");
            break;
        case MNWMessageObserver::ENWGetProgrammableOperatorName:
            iReceivedMessageFlags |= EProgrammableOperatorInfoReceived;
            iReceivedMessageFlags &= ~EProgrammableOperatorInfoReceivedOk;
            iInfo.iOperatorNameInfo.iName.Zero();
            __PRINTS("XAI: PON error received");
            break;
        case MNWMessageObserver::ENWGetServiceProviderName:
            iReceivedMessageFlags |= EServiceProviderNameReceived;
            iReceivedMessageFlags &= ~EServiceProviderNameOk;
            iInfo.iServiceProviderNameDisplayReq = RMobilePhone::KDisplaySPNNotRequired;
            iInfo.iSPName.Zero();
            iInfo.iPLMNField.Zero();
            __PRINTS("XAI: SPN error received");
            break;
        case MNWMessageObserver::ENWNotifyNetworkRegistrationStatusChange:
            if ( FeatureManager::FeatureSupported( KFeatureIdFfManualSelectionPopulatedPlmnList )
                 && ( KErrGsmMMNetworkFailure == aErrorCode ) )
                {
                errorCode = static_cast<TNWMessages>( aErrorCode );
                }
            __PRINTS("XAI: ENWNotifyNetworkRegistrationStatusChange error received");

        break;
        default:
            break;
        }

    HandleNetworkMessage( errorCode );
    }

TBool CAiNetworkInfoListener::NotAllowedToDisplayOperatorIndicator( const TNWMessages aMessage )
	{
	// Service provider name must have been fetched.
    // Network provider name must have been fetched.
    // Registration status and network information must have been received.
    // Operator name information must have been received.
    // Device must be camped to a network.
    // CS registration should be completed (only valid in AT&T NW)

	switch ( aMessage )
    	{
        case MNWMessageObserver::ENWMessageNetworkInfoChange:
            iReceivedMessageFlags |= ENetworkInfoChangeReceived;
            break;
        case MNWMessageObserver::ENWMessageNetworkRegistrationStatusChange:
            iReceivedMessageFlags |= ERegistrationStatusReceived;
            break;
        case MNWMessageObserver::ENWMessageNetworkProviderNameChange:
            iReceivedMessageFlags |= 
                ( ENetworkProviderNameReceived + ENetworkProviderNameOk );
            break;
        case MNWMessageObserver::ENWMessageServiceProviderNameChange:
            iReceivedMessageFlags |= 
                ( EServiceProviderNameReceived + EServiceProviderNameOk );
            break;
        case MNWMessageObserver::ENWMessageProgrammableOperatorInfoChange:
            iReceivedMessageFlags |= 
                ( EProgrammableOperatorInfoReceived + 
                  EProgrammableOperatorInfoReceivedOk );
            break;
        case MNWMessageObserver::ENWMessageNetworkProviderNameUpdating:
            iReceivedMessageFlags &= 
                ~( ENetworkProviderNameReceived + ENetworkProviderNameOk );
            break;
        case MNWMessageObserver::ENWMessageServiceProviderNameUpdating:
            iReceivedMessageFlags &= 
                ~( EServiceProviderNameReceived + EServiceProviderNameOk );
            break;
        case MNWMessageObserver::ENWMessageProgrammableOperatorInfoUpdating:
            iReceivedMessageFlags &= 
                ~( EProgrammableOperatorInfoReceived + 
                   EProgrammableOperatorInfoReceivedOk );
            break;
        case MNWMessageObserver::ENWMessageDynamicCapsChange:
            TRAPD(fmerr, FeatureManager::InitializeLibL());
            if ( fmerr == KErrNone )
                {
                if( FeatureManager::FeatureSupported( 
                    KFeatureIdFfDisplayNetworkNameAfterCsRegistration ))
                    {
                    // CS flag is EFalse, alpha tag should not be shown.
                    if ( !( RPacketService::KCapsRxCSCall & 
                            iInfo.iDynamicCapsFlags ) )
                        {
                        __PRINTS("XAI: CS registration failed");
                        iReceivedMessageFlags |= ECSRegistrationNotOk;
                        }
                    else
                        {
                        __PRINTS("XAI: CS registration ok");
                        iReceivedMessageFlags &= ~ECSRegistrationNotOk;
                        }
                    }
                FeatureManager::UnInitializeLib();
                }
            break;
        default:
            break;
        }
    
    TBool serviceProviderNameFetched( EServiceProviderNameReceived & iReceivedMessageFlags );
    TBool networkProviderNameFetched( ENetworkProviderNameReceived & iReceivedMessageFlags );
    TBool registrationStatusReceived( ERegistrationStatusReceived & iReceivedMessageFlags );
    TBool networkInformationReceived( ENetworkInfoChangeReceived & iReceivedMessageFlags );
    TBool operatorNameInformationReceived(
    	 EProgrammableOperatorInfoReceived & iReceivedMessageFlags );  
    TBool currentNetworkOk( 
    	( ENetworkInfoChangeReceived  & iReceivedMessageFlags ) && 
        ( ERegistrationStatusReceived & iReceivedMessageFlags ) &&
        ( iInfo.iStatus == ENWStatusCurrent ) );  
    TBool csAlphaFlag( ECSRegistrationNotOk & iReceivedMessageFlags );
      
  	return
        !serviceProviderNameFetched ||
        !networkProviderNameFetched ||
        !( registrationStatusReceived && networkInformationReceived 
        	&& operatorNameInformationReceived ) ||
        !currentNetworkOk || csAlphaFlag;
	}


TBool CAiNetworkInfoListener::HasNetworkInfoChanged( const TNWMessages aMessage )
    {
    TBool result = ETrue;
    
    // pass through
   	if ( aMessage == MNWMessageObserver::ENWMessageCurrentHomeZoneMessage 	||
   	 	 aMessage == MNWMessageObserver::ENWMessageNetworkConnectionFailure	||
   	 	 aMessage == MNWMessageObserver::ENWMessageCurrentCellInfoMessage ||
   	 	 aMessage == static_cast<TNWMessages>( KErrGsmMMNetworkFailure )
       )
   		{
   		return result;
   		}
    
    result = ( iReceivedMessageFlags != iOldReceivedMessageFlags );
    
    if ( !result )
        {
        // Check if contents of iInfo has changed. Most probable to the 
        // beginning of the expression.
        result = 
            iInfo.iRegistrationStatus != iOldInfo.iRegistrationStatus ||
            iInfo.iStatus != iOldInfo.iStatus ||
            iInfo.iCountryCode != iOldInfo.iCountryCode ||
            iInfo.iNetworkId != iOldInfo.iNetworkId ||
            iInfo.iOperatorNameInfo.iType != 
                iOldInfo.iOperatorNameInfo.iType ||
            iInfo.iOperatorNameInfo.iName != 
                iOldInfo.iOperatorNameInfo.iName ||
            iInfo.iDisplayTag != iOldInfo.iDisplayTag ||
            iInfo.iShortName != iOldInfo.iShortName ||
            iInfo.iLongName != iOldInfo.iLongName ||
            iInfo.iSPName != iOldInfo.iSPName ||
            iInfo.iServiceProviderNameDisplayReq != 
                iOldInfo.iServiceProviderNameDisplayReq ||
            iInfo.iNPName != iOldInfo.iNPName ||
            iInfo.iPLMNField != iOldInfo.iPLMNField;
        TRAPD(fmerr, FeatureManager::InitializeLibL());
        if ( fmerr == KErrNone )
            {
            if( FeatureManager::FeatureSupported( 
                KFeatureIdFfDisplayNetworkNameAfterCsRegistration ))
                {
                    result = result || 
                        iInfo.iDynamicCapsFlags != iOldInfo.iDynamicCapsFlags;
                }
            FeatureManager::UnInitializeLib();
            }
        }

    iOldReceivedMessageFlags = iReceivedMessageFlags;
    iOldInfo = iInfo;

    return result;
    }