callcontinuity/vcchotrigger/src/vcchotrigger.cpp
changeset 0 a4daefaec16c
child 2 7b872347d83b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/callcontinuity/vcchotrigger/src/vcchotrigger.cpp	Mon Jan 18 20:12:36 2010 +0200
@@ -0,0 +1,689 @@
+/*
+* Copyright (c) 2007-2008 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:   Implementation of the handover trigger
+*
+*/
+
+
+
+#include <e32base.h>
+
+#include <vccsubscribekeys.h>
+#include "vccuipsproperty.h"
+#include "vcchotrigger.h"
+#include "vccsignallevelhandler.h"
+#include "vccwlansignallevelhandler.h"
+#include "vccgsmsignallevelhandler.h"
+#include "rubydebug.h"
+#include "vcchopolicyreader.h"
+#include "vcccchmonitor.h"
+#include "vccengpsproperty.h"
+#include "cvccperformer.h"
+
+// Min. signal strength.
+static const TInt32 KStrengthMin = 110;
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CVccHoTrigger* CVccHoTrigger::NewL()
+    {
+    RUBY_DEBUG_BLOCKL( "CVccHoTrigger::NewL" );
+
+    CVccHoTrigger* self = new ( ELeave ) CVccHoTrigger();
+
+    CleanupStack::PushL( self );
+
+    self->ConstructL();
+
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CVccHoTrigger::~CVccHoTrigger()
+    {
+    RUBY_DEBUG0( "CVccHoTrigger::~CVccHoTrigger() - ENTER" );
+
+    delete iProperty;
+    delete iWlanSignalLevelHandler;
+    delete iGsmSignalLevelHandler;
+    delete iHoPolicyReader;
+    delete iCchMonitor;
+    delete iEngPsProperty;
+    
+    RUBY_DEBUG0( "CVccHoTrigger::~CVccHoTrigger() - EXIT" );
+    }
+
+// -----------------------------------------------------------------------------
+// CVccHoTrigger::CVccHoTrigger()
+// C++ default constructor can NOT contain any code, that might leave.
+// -----------------------------------------------------------------------------
+//
+CVccHoTrigger::CVccHoTrigger() :         //: CActive( EPriorityStandard )
+    iGsmClass( ESignalClassUndefined ),
+    iWlanClass( ESignalClassUndefined ),
+    iManualHoDone( EFalse ),
+    iHoNotAllowed( EFalse ),
+    iHoAllowedIfCsOriginated( ETrue )
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::CVccHoTrigger" );
+    }
+// ---------------------------------------------------------------------------
+// 2nd phase constructor
+// ---------------------------------------------------------------------------
+//
+void CVccHoTrigger::ConstructL()
+    {
+    RUBY_DEBUG_BLOCKL( "CVccHoTrigger::ConstructL" );
+
+    iProperty = CVccUiPsProperty::NewL();
+    iHoPolicyReader = CVccHoPolicyReader::NewL();
+    iHoPolicyReader->ReadSettingsL();
+    
+    iEngPsProperty = CVccEngPsProperty::NewL();
+    iPolicy = iHoPolicyReader->HoPolicy();
+    TSignalLevelParams gsm = iHoPolicyReader->CsSignalLevelParams();
+    TSignalLevelParams wlan = iHoPolicyReader->PsSignalLevelParams();
+    
+
+    iWlanSignalLevelHandler =
+        CVccWlanSignalLevelHandler::NewL( *this, wlan, *iEngPsProperty );
+
+         
+    iGsmSignalLevelHandler =
+        CVccGsmSignalLevelHandler::NewL( *this, gsm );
+  
+    iHoAllowedIfCsOriginated = iPolicy.DtAllowedWhenCsOriginated();
+    // Previous signal level class must be undefined
+    iPreviousGsmClass = ESignalClassUndefined;
+    iPreviousWlanClass = ESignalClassUndefined;
+    // In the beginning the VoIP service is not available.
+    // This will be changed when the cch monitor calls us
+    // when the service is available.
+    iCchServiceStatus = EServiceUnavailable;
+    
+    // CS network has signal level zero if the service is not
+    // available.
+    iCsSignalLevel = KStrengthMin;
+
+    // We are not stared yet.
+    iStarted = EFalse;
+    
+    // Update P&S keys to tell if we can do ho or not.    
+    UpdatePsKeysL();
+    // Create the CCH monitor. We are the observer to be
+    // notified when the status changes.
+    iCchMonitor = CVccCchMonitor::NewL( *this );
+    }
+
+// -----------------------------------------------------------------------------
+// Stop monitoring
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::Stop()
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::Stop" );
+    Stop( *iWhoStartedMe );
+    }
+
+// -----------------------------------------------------------------------------
+// Stop monitoring
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::Stop( CVccPerformer& aStopper )
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::Stop" );
+    // If someone else that the one who started us tries
+    // to stop us, we do not allow it.
+    // There may be several performers that are in differnet state
+    // and in those state they do not need trigger and thus try
+    // to stop us.
+    if ( iWhoStartedMe == &aStopper )
+        {
+        iWhoStartedMe = NULL;
+        iStarted = EFalse;
+        TRAP_IGNORE( UpdatePsKeysL() );
+        TRAP_IGNORE( iProperty->NotifySubscriberL( EVccNoRequestOngoing ) );
+        iWlanSignalLevelHandler->Stop();
+        iGsmSignalLevelHandler->Stop();
+        
+        iGsmClass = ESignalClassUndefined;
+        iWlanClass = ESignalClassUndefined;        
+        
+        // Reset CS signal strength to min
+        iCsSignalLevel = KStrengthMin;
+        
+        // Disable (do not send notifications).
+        // The service is not actually disabled.
+        // It will be disabled (if needed) when the monitor
+        // is deleted.
+        iCchMonitor->DisableService();
+        RUBY_DEBUG0( " -Trigger stopped");
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Start monitoring
+// We must not leave.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::Start( CVccPerformer& aWhoStartedMe, 
+                                    TBool aCsOriginated )
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::Start" );
+    if( iHoAllowedIfCsOriginated == EFalse && aCsOriginated )
+        {
+        RUBY_DEBUG0( "HO not allowed for CS originated calls" );
+                
+        Stop();
+        return;
+        }
+    //anyone can start, but only the last one who started can stop the trigger
+    iWhoStartedMe = &aWhoStartedMe;
+    if( !iStarted )
+        {
+        
+        // Previous signal level class must be undefined
+        iPreviousGsmClass = ESignalClassUndefined;
+        iPreviousWlanClass = ESignalClassUndefined;
+    
+        // read signal high/low levels, timers etc.
+        TRAPD( err, iHoPolicyReader->ReadSettingsL() );
+        RUBY_DEBUG1( "reading ho settings, err = %d", err );
+        
+        if ( !err )
+        	{
+		    TSignalLevelParams gsm = iHoPolicyReader->CsSignalLevelParams();
+		    TSignalLevelParams wlan = iHoPolicyReader->PsSignalLevelParams();
+		    iPolicy = iHoPolicyReader->HoPolicy();
+		    
+		    iWlanSignalLevelHandler->SetParams( wlan );
+		    iGsmSignalLevelHandler->SetParams( gsm );
+		    
+		    TRAPD( err_wlan, iWlanSignalLevelHandler->StartL() );
+		    RUBY_DEBUG1( "starting wlan signal level handler, err = %d", err_wlan );
+		    TRAPD( err_gsm, iGsmSignalLevelHandler->StartL() );
+		    RUBY_DEBUG1( "starting gsm signal level handler, err = %d", err_gsm );
+		    
+		    if ( !err_wlan && !err_gsm )
+		    	{		    
+			    // Enable the VoIP service to be able to do VoIP calls.
+			    TRAPD( err_cch, iCchMonitor->EnableServiceL() );
+			    RUBY_DEBUG1( "enabling service, err = %d", err_cch );
+			    
+			    if ( !err_cch )
+			    	{
+			    	// Everything was started ok
+			    	iStarted = ETrue;
+			    	}
+		    	}
+		    else
+		    	{
+		    	// Stop the handlers just in case either one was started
+		    	iWlanSignalLevelHandler->Stop();
+		    	iGsmSignalLevelHandler->Stop();
+		    	}
+        	}
+        
+        TRAP_IGNORE( UpdatePsKeysL() );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Set the domain type of the current call
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::SetCurrentDomainType( TCallDomainType aDomainType )
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::SetCurrentDomainType" );
+    iDomainType = aDomainType;
+    }
+
+// -----------------------------------------------------------------------------
+// Set the preferred domain type
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::SetPreferredDomainType( 
+                                        TVccHoPolicyPreferredDomain aDomainType )
+    {
+    RUBY_DEBUG1( "CVccHoTrigger::SetPreferredDomainType(%d)", aDomainType );
+    iPolicy.SetPreferredDomain( aDomainType );
+    }
+
+// -----------------------------------------------------------------------------
+// Set Immediate Domain Transfer on/off
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::SetImmediateDomainTransfer( TBool aImmediateDT )
+    {
+    RUBY_DEBUG1( "CVccHoTrigger::SetImmediateDomainTransfer(%d)", aImmediateDT );
+    iPolicy.SetDoImmediateHo(  aImmediateDT );
+    }
+
+// -----------------------------------------------------------------------------
+// Handles wlan signal change notifications
+// -----------------------------------------------------------------------------
+//
+void CVccHoTrigger::WlanSignalChanged(
+        TInt32 /*aSignalStrength*/,
+        TSignalStrengthClass aClass )
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::WlanSignalChanged" );
+
+    //Store signal strength class to that we know later what is the strength
+    iWlanClass = aClass;
+    
+    RUBY_DEBUG1( " -iWlanClass=%x ", iWlanClass );
+    RUBY_DEBUG1( " -iDomainType=%x ", iDomainType );
+    RUBY_DEBUG1( " -iGsmClass=%x ", iGsmClass );
+    RUBY_DEBUG1( " -DoImmediateHO=%x ", iPolicy.DoImmediateHo() );
+    RUBY_DEBUG1( " -PreferredDomain=%x ", iPolicy.PreferredDomain() );
+    RUBY_DEBUG1( " -iGsmClass=%x ", iGsmClass );
+    RUBY_DEBUG1( " -DoHoInHeldWaitingCalls=%x ", iPolicy.DoHoInHeldWaitingCalls() );
+    RUBY_DEBUG0( "0 = GOOD, 1 = WEAK, 2 = UNDEFINED" );
+    
+    // If the previous class is the same as the new one
+    // - do nothing.
+    
+    if ( iPreviousWlanClass == iWlanClass )
+        {
+        RUBY_DEBUG0( "No change in WLAN signal class -> return" );
+    
+        return;
+        }
+    else
+        {
+        iPreviousWlanClass = iWlanClass;
+        }
+    
+    TriggerHo();
+     }
+
+// -----------------------------------------------------------------------------
+// Handles GSM singnal change notifications
+// -----------------------------------------------------------------------------
+//
+void CVccHoTrigger::GsmSignalChanged(
+        TInt32 aSignalStrength,
+        TSignalStrengthClass aClass )
+    {
+    RUBY_DEBUG_BLOCK( "VccHoTrigger::GsmSignalChanged" );
+    RUBY_DEBUG1( " -iCsSignalLevel=%d ", aSignalStrength );
+
+    //Store signal strength class to that we know later what is the strength
+    iGsmClass = aClass;
+    
+    // Save the signal strength as "status".
+    // Zero (0) means that the service is not available.
+    iCsSignalLevel = aSignalStrength;
+
+    // Update P&S keys to tell if we can do ho or not.
+    // If the signal level has gone to zero, we are unable to
+    // do hondover.
+    
+    TVccHoStatus hoStatus( EVccHoStateUnknown );
+    iEngPsProperty->GetCurrentHoStatus( hoStatus );
+    
+    if( hoStatus != EVccCsToPsHoStarted || hoStatus != EVccCsToPsHoInprogress )
+        {
+        RUBY_DEBUG0( "CS to PS HO in progress, not updating keys" );
+        TRAP_IGNORE( UpdatePsKeysL() );
+        }
+    
+    RUBY_DEBUG1( " -iWlanClass=%x ", iWlanClass );
+    RUBY_DEBUG1( " -iDomainType=%x ", iDomainType );
+    RUBY_DEBUG1( " -iGsmClass=%x ", iGsmClass );
+    RUBY_DEBUG1( " -DoImmediateHO=%x ", iPolicy.DoImmediateHo() );
+    RUBY_DEBUG1( " -PreferredDomain=%x ", iPolicy.PreferredDomain() );
+    RUBY_DEBUG1( " -DoHoInHeldWaitingCalls=%x ", iPolicy.DoHoInHeldWaitingCalls() );  
+    RUBY_DEBUG0( "0 = GOOD, 1 = WEAK, 2 = UNDEFINED" );
+    
+    // If the previous class is the same as the new one
+    // - do nothing.
+    
+    if ( iPreviousGsmClass == iGsmClass )
+        {
+        RUBY_DEBUG0( "No change in GSM signal class -> return" );
+    
+        return;
+        }
+    else
+        {
+        iPreviousGsmClass = iGsmClass;
+        }
+    
+    TriggerHo();
+    }
+
+// -----------------------------------------------------------------------------
+// Handles CCH monitor notifications
+// -----------------------------------------------------------------------------
+//
+void CVccHoTrigger::CchServiceStatusChanged( TServiceStatus aStatus )
+    {
+    RUBY_DEBUG_BLOCK( "VccHoTrigger::CchServiceStateChanged" );
+    RUBY_DEBUG1( " -Service status = %d", aStatus );
+    
+    // Save the status
+    iCchServiceStatus = aStatus;
+    
+    TRAP_IGNORE( UpdatePsKeysL() );
+    TriggerHo();
+    }
+
+// -----------------------------------------------------------------------------
+// Check if the CS or PS services are available or not
+// -----------------------------------------------------------------------------
+//
+TBool CVccHoTrigger::ServicesAvailable()
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::AreServicesAvailable" );
+    
+    TBool retVal( ETrue );
+    
+    // If PS service (VoIP service) is unavailable or
+    // the CS service == 0 (i.e. signal level),
+    // we cannot do handover.
+    
+    if ( iCchServiceStatus == EServiceUnavailable || 
+                    iCsSignalLevel == KStrengthMin )
+        {
+        RUBY_DEBUG0( " -VoIP/CS service(s) not available" );
+        retVal = EFalse;
+        }
+    
+    return retVal;
+    }
+
+// -----------------------------------------------------------------------------
+// Update (write) service status state to P&S.
+// -----------------------------------------------------------------------------
+//
+void CVccHoTrigger::UpdatePsKeysL()
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::UpdatePsKeysL" );
+    
+    // If we are started and both services are available,
+    // handover can be done.
+    // Services available in CS means that we have
+    // signal strength != KStrengthMin (which is 110, returned
+    // from the CS signal level monitor).
+    
+    RUBY_DEBUG1( " -iStarted = %d", iStarted );
+    RUBY_DEBUG1( " -iHoNotAllowed = %d", iHoNotAllowed );
+    RUBY_DEBUG1( " -Service status = %d (0=unavailable, 1=available)", iCchServiceStatus );
+    RUBY_DEBUG1( " -CS signal min level = 110, current level = %d", iCsSignalLevel );
+        
+    if ( iStarted &&
+            ( iCchServiceStatus == EServiceAvailable ) && 
+            ( iCsSignalLevel != KStrengthMin ) &&
+            ( !iHoNotAllowed ) )
+        {
+        RUBY_DEBUG0( " -We are started and both services are available" );
+        // Check HO direction restrictions
+        if ( ( iPolicy.AllowedDirection() & ECsToPsAllowed ) && 
+                ( iPolicy.AllowedDirection() & EPsToCsAllowed ) )
+            {
+            if( iPolicy.DoHoInHeldWaitingCalls() )
+                {
+                RUBY_DEBUG0( " -Services available and ho allowed to both \
+                             directions, also in multicall" );
+                iEngPsProperty->NotifySubscriberL( EVccHoStateIdle, KErrNone );
+                }
+            else
+                {
+                RUBY_DEBUG0( " -Services available and ho allowed to both \
+                             directions but not in multicall" );
+                iEngPsProperty->NotifySubscriberL( EVccHoStateIdleIfSingleCall, KErrNone );
+                }
+            }
+        else if ( !( iPolicy.AllowedDirection() & ECsToPsAllowed  ) &&
+                ( iPolicy.AllowedDirection() & EPsToCsAllowed ) )
+            {
+            if( iPolicy.DoHoInHeldWaitingCalls() )
+                {
+                RUBY_DEBUG0( " -HO allowed only to CS" );
+                iEngPsProperty->NotifySubscriberL( EVccCsToPsNotAllowed, KErrNone );
+                }
+            else
+                {
+                RUBY_DEBUG0( " -HO allowed only to CS, in single call situation" );
+                iEngPsProperty->NotifySubscriberL( EVccHoAllowedToCsIfSingleCall, KErrNone );
+                }
+            }
+        else if ( !( iPolicy.AllowedDirection() & EPsToCsAllowed ) &&  
+                    ( iPolicy.AllowedDirection() & ECsToPsAllowed ) )
+            {
+            if( iPolicy.DoHoInHeldWaitingCalls() )
+                {
+                RUBY_DEBUG0( " -HO allowed only to PS" );
+                iEngPsProperty->NotifySubscriberL( EVccPsToCsNotAllowed, KErrNone );
+                }
+            else
+                {
+                RUBY_DEBUG0( " -HO allowed only to PS, in single call situation" );
+                iEngPsProperty->NotifySubscriberL( EVccHoAllowedToPsIfSingleCall, KErrNone );
+                }
+            }
+        }
+    else
+        {
+        RUBY_DEBUG0( " -We are stopped or services are unavailable:" );
+        iEngPsProperty->NotifySubscriberL( EVccHoUnavailable, KErrNotReady );        
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// If manual HO is done, no automatic should be made.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::ManualHoCallStarted()
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::ManualHoCallStarted" );
+    iManualHoDone = ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// After manual HO call has been released automatic HOs can be made again.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::ManualHoCallReleased()
+    {
+    RUBY_DEBUG_BLOCK( "CVccHoTrigger::ManualHoCallReleased" );
+    iManualHoDone = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// During conference HO is not allowed
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::HoNotAllowedL()
+	{
+	RUBY_DEBUG_BLOCK( "CVccHoTrigger::HoNotAllowedL" );
+	iHoNotAllowed = ETrue;
+	UpdatePsKeysL();
+	}
+
+// -----------------------------------------------------------------------------
+// After conference HO is allowed again
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::HoAllowed()
+	{
+	RUBY_DEBUG_BLOCK( "CVccHoTrigger::HoAllowed" );
+	iHoNotAllowed = EFalse;
+	TRAP_IGNORE( UpdatePsKeysL() );
+	}
+
+// -----------------------------------------------------------------------------
+// Read settings
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVccHoTrigger::ReadHoAllowedWhenCsOriginatedSettingL()
+    {
+    iHoPolicyReader->ReadSettingsL();
+    iPolicy = iHoPolicyReader->HoPolicy();
+    iHoAllowedIfCsOriginated = iPolicy.DtAllowedWhenCsOriginated();
+    }
+    
+// -----------------------------------------------------------------------------
+// Initiate the actual ho when its ok
+// -----------------------------------------------------------------------------
+//
+void CVccHoTrigger::TriggerHo()
+	{
+	RUBY_DEBUG_BLOCK( "CVccHoTrigger::TriggerHo" );
+	//Check if manual ho is already made during this call and the 
+	//service availability.
+	if( iManualHoDone || !ServicesAvailable() || iHoNotAllowed )
+		{
+		return;
+		}
+	
+	//If immediate ho is "ON" do it first and then return.
+	if( iPolicy.DoImmediateHo() )
+		{
+		if ( DoImmediateHo() )
+		    {
+		    RUBY_DEBUG0( "VccHoTrigger::TriggerHo - immediate HO was initiated" );
+		    return;
+		    }
+		RUBY_DEBUG0( "VccHoTrigger::TriggerHo - no immediate HO" );
+		}
+	
+	if ( iWlanClass == ESignalClassWeak &&
+	     iGsmClass == ESignalClassNormal && 
+	     ( iPolicy.AllowedDirection() & EPsToCsAllowed  ))
+	    {
+	    RUBY_DEBUG0( "VccHoTrigger::WlanSignalChanged - NotifySubscriberL" );
+	        
+	    // First empty the key, so that director 
+	    // gets notified about all changes
+	        
+	    TRAP_IGNORE( iProperty->NotifySubscriberL( EVccNoRequestOngoing ) );
+	    // Check whether HO is allowed in multicall situation
+	    if( iPolicy.DoHoInHeldWaitingCalls() )
+	        {
+	        TRAP_IGNORE( iProperty->NotifySubscriberL(
+	                    EVccAutomaticStartPsToCsHoRequest ) );
+	        }
+	    else
+	        {
+	        TRAP_IGNORE( iProperty->NotifySubscriberL(
+	                    EVccAutomaticStartPsToCsHoRequestIfSingleCall ) );
+	        }
+	        
+	    }        
+	
+	else if ( iGsmClass == ESignalClassWeak &&
+            iWlanClass == ESignalClassNormal &&
+            ( iPolicy.AllowedDirection() & ECsToPsAllowed ))
+        {
+        RUBY_DEBUG0( "VccHoTrigger::GsmSignalChanged - NotifySubscriberL" );
+        
+        // First empty the key, so that director 
+        // gets notified about all changes
+        
+        TRAP_IGNORE( iProperty->NotifySubscriberL( EVccNoRequestOngoing ) );
+        // Check whether HO is allowed in multicall situation
+        if( iPolicy.DoHoInHeldWaitingCalls() )
+            {
+            TRAP_IGNORE( iProperty->NotifySubscriberL(
+                        EVccAutomaticStartCsToPsHoRequest ) );
+            }
+        else
+            {
+            TRAP_IGNORE( iProperty->NotifySubscriberL(
+                        EVccAutomaticStartCsToPsHoRequestIfSingleCall ) );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Initiate immediate ho
+// -----------------------------------------------------------------------------
+//
+TBool CVccHoTrigger::DoImmediateHo()
+	{
+	RUBY_DEBUG_BLOCK( "CVccHoTrigger::DoImmediateHo" );
+	TBool ret( EFalse );
+	if( ( iPolicy.PreferredDomain() == ECsPreferred ) &&
+	    iGsmClass ==  ESignalClassNormal &&
+        ( iPolicy.AllowedDirection() & EPsToCsAllowed ) )  
+		{
+		// Current call is PS, CS signal is ok, preferred domain is CS
+        // and immediate HO is requested -> HANDOVER to CS
+        
+        RUBY_DEBUG0( "VccHoTrigger::GsmSignalChanged - NotifySubscriberL ->\
+                      IMMEDIATE HO to CS" );
+        
+        // First empty the key, so that director gets
+        // notified about all changes
+        
+        TRAP_IGNORE( iProperty->NotifySubscriberL( EVccNoRequestOngoing ) );
+        
+        // Check whether HO is allowed in multicall situation
+        if( iPolicy.DoHoInHeldWaitingCalls() )
+            {
+            TRAP_IGNORE( iProperty->NotifySubscriberL(
+                        EVccAutomaticStartPsToCsHoRequest ) );
+            ret = ETrue;
+            }
+        else
+            {
+            TRAP_IGNORE( iProperty->NotifySubscriberL(
+                        EVccAutomaticStartPsToCsHoRequestIfSingleCall ) );
+            ret = ETrue;
+            }
+		}
+	
+	else if ( (iPolicy.PreferredDomain() == EPsPreferred)  &&
+	      iWlanClass == ESignalClassNormal &&
+	      ( iPolicy.AllowedDirection() & ECsToPsAllowed  ) )
+        {
+        // Current call is CS, PS signal is ok, preferred domain is PS and 
+	    // immediate HO is requested -> HANDOVER to PS
+
+        RUBY_DEBUG0( "VccHoTrigger::WlanSignalChanged - NotifySubscriberL ->\
+                      IMMEDIATE HO to PS" );
+	       
+	    // First empty the key, so that director gets 
+	    // notified about all changes
+	        
+	    TRAP_IGNORE( iProperty->NotifySubscriberL( EVccNoRequestOngoing ) );
+	        
+        // Check whether HO is allowed in multicall situation
+	    if( iPolicy.DoHoInHeldWaitingCalls() )
+            {
+	        TRAP_IGNORE( iProperty->NotifySubscriberL(
+	                    EVccAutomaticStartCsToPsHoRequest ) );
+	        ret = ETrue;
+	        }
+	    else
+	        {
+	        TRAP_IGNORE( iProperty->NotifySubscriberL(
+	                       EVccAutomaticStartCsToPsHoRequestIfSingleCall ) );
+	        ret = ETrue;
+	        }
+        }
+	return ret;
+	}