contextframework/cfwplugins/ApplicationStateSourcePlugIn/src/ApplicationStateSourcePlugin.cpp
/*
* Copyright (c) 2002-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: ?Description
*
*/
// INCLUDE FILES
#include <cfcontextinterface.h>
#include <cfcontextsourcesetting.h>
#include <cfcontextsourcesettingarray.h>
#include <cfcontextsourcesettingparameter.h>
#include <cfkeyvaluepair.h>
#include <centralrepository.h>
#include <apgwgnam.h>
#include <applicationorientation.h>
#include <aknappui.h>
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <vwsdefpartner.h>
#endif
#include "ApplicationStateSourcePlugin.h"
#include "ApplicationStateSourceContextDef.h"
#include "ContextFrameworkPrivateCRKeys.h"
#include "trace.h"
// CONSTANTS
#ifdef _DEBUG
// Panic codes
enum TPanicCode
{
EInvalidUid,
EInvalidAttribute
};
#endif
_LIT( KDefaultApplicationName, "DefaultAppName" );
_LIT( KDefaultViewName, "DefaultViewName" );
_LIT( KAttributeAppUid, "AppUid" );
_LIT( KAttributeAppName, "AppName" );
_LIT( KTagView, "View" );
_LIT( KAttributeUid, "Uid" );
_LIT( KAttributeName, "Name" );
const TUint KLimit = 0xFFFFFFFF;
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::CApplicationStateSourcePlugIn
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CApplicationStateSourcePlugIn::CApplicationStateSourcePlugIn( TContextSourceInitParams* aParams ):
CCFContextSourcePlugIn( aParams ),
iDefStateSetManyTimes( 0 )
{
FUNC_LOG;
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::ConstructL
// Symbian second-phase constructor that may leave.
// -----------------------------------------------------------------------------
//
void CApplicationStateSourcePlugIn::ConstructL()
{
FUNC_LOG;
iDefaultAppName = KApplicationStateDefaultValue().AllocL();
iDefaultViewName = KApplicationStateDefaultValue().AllocL();
iContext = CCFContextObject::NewL();
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CApplicationStateSourcePlugIn* CApplicationStateSourcePlugIn::NewL(
TContextSourceInitParams* aParams )
{
FUNC_LOG;
CApplicationStateSourcePlugIn* self = CApplicationStateSourcePlugIn::NewLC(
aParams );
CleanupStack::Pop( self );
return self;
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CApplicationStateSourcePlugIn* CApplicationStateSourcePlugIn::NewLC(
TContextSourceInitParams* aParams )
{
FUNC_LOG;
CApplicationStateSourcePlugIn* self = new( ELeave ) CApplicationStateSourcePlugIn(
aParams );
CleanupStack::PushL( self );
self->ConstructL();
return self;
}
// Destructor
CApplicationStateSourcePlugIn::~CApplicationStateSourcePlugIn()
{
FUNC_LOG;
if( iCRAppOrientationListener )
{
iCRAppOrientationListener->StopListening();
delete iCRAppOrientationListener;
}
iUidOrientationList.Close();
delete iCRAppOrientation;
iApplicationSettings.ResetAndDestroy();
delete iSettings;
delete iVws;
delete iDefaultViewName;
delete iDefaultAppName;
delete iApplDefaultState;
delete iContext;
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::HandleSettingL
// -----------------------------------------------------------------------------
//
void CApplicationStateSourcePlugIn::HandleSettingL(
CCFContextSourceSettingArray* aSettingList )
{
FUNC_LOG;
// Take ownership from settings
iSettings = aSettingList;
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::DefineContextsL
// -----------------------------------------------------------------------------
//
void CApplicationStateSourcePlugIn::DefineContextsL()
{
FUNC_LOG;
// Define contexts here
_LIT_SECURITY_POLICY_C2(
appStatePolicy, ECapabilitySwEvent, ECapabilityUserEnvironment );
TInt err = iCF.DefineContext( KApplicationStateSource,
KApplicationStateForegroundApplicationType,
appStatePolicy );
User::LeaveIfError( err );
err = iCF.DefineContext( KApplicationStateSource,
KApplicationStateForegroundApplicationViewType,
appStatePolicy );
User::LeaveIfError( err );
err = iCF.DefineContext( KApplicationStateSource,
KApplicationStateBackgroundApplicationType,
appStatePolicy );
User::LeaveIfError( err );
err = iCF.DefineContext( KApplicationStateSource,
KFgApplicationOrientation,
KFgApplicationOrientationSec );
User::LeaveIfError( err );
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::InitializeL
// -----------------------------------------------------------------------------
//
void CApplicationStateSourcePlugIn::InitializeL()
{
FUNC_LOG;
iContext->SetSourceL( KApplicationStateSource );
// Get default app orientation
CRepository* cenRep = CRepository::NewL( KCRUidCFApplDefaultState );
TInt err = cenRep->Get( KApplDefaultState, iDefaultFgAppOrientation );
if( err != KErrNone )
{
ERROR( err, "Failed to get default fg app orientation" );
iDefaultFgAppOrientation = 0;
}
delete cenRep;
cenRep = NULL;
// Create KCRUidDefaultAppOrientation repository for default app orientation
iCRAppOrientation = CRepository::NewL( KCRUidDefaultAppOrientation );
// Create KCRUidDefaultAppOrientation repository listener
iCRAppOrientationListener = CCenRepNotifyHandler::NewL(
*this, *iCRAppOrientation );
iCRAppOrientationListener->StartListeningL();
if( iSettings )
{
InitializeApplicationsFromXMLL();
InitializeFgApplicationL();
// Free memory allocated for settings since we don't need them anymore
delete iSettings;
iSettings = NULL;
}
iVws = CVwsSessionWrapper::NewL( *this );
iVws->NotifyNextActivation();
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::InitializeApplicationsFromXMLL
// -----------------------------------------------------------------------------
//
void CApplicationStateSourcePlugIn::InitializeApplicationsFromXMLL()
{
FUNC_LOG;
for( TInt i = 0; i < iSettings->Count(); ++i )
{
// Check attributes
TBool defaultValueDefinitions = EFalse;
TPtrC appUid( KNullDesC );
TPtrC appName( KNullDesC );
const RKeyValueArray& attributes = iSettings->Item( i ).Attributes();
// Check application and view names (also default values)
for( TInt j = 0; j < attributes.Count(); ++j )
{
TPtrC key( attributes[ j ]->Key() );
TPtrC value( attributes[ j ]->Value() );
if( key.CompareF( KAttributeAppUid ) == KErrNone )
{
appUid.Set( value );
}
else if( key.CompareF( KAttributeAppName ) == KErrNone )
{
appName.Set( value );
}
else if( key.CompareF( KDefaultApplicationName ) == KErrNone )
{
delete iDefaultAppName;
iDefaultAppName = NULL;
iDefaultAppName = value.AllocL();
defaultValueDefinitions = ETrue;
}
else if( key.CompareF( KDefaultViewName ) == KErrNone )
{
delete iDefaultViewName;
iDefaultViewName = NULL;
iDefaultViewName = value.AllocL();
defaultValueDefinitions = ETrue;
}
}
if ( defaultValueDefinitions )
{
continue; // Default value definitions contain only attributes.
}
if ( appUid.Length() == 0 || appName.Length() == 0 )
{
ERROR_GEN( "Either AppUid or AppName tag (or both) not found, skipping" );
continue; // Skip this definition.
}
TUint32 uid = 0;
TInt err = ConvertToHex( appUid, uid );
if( err != KErrNone )
{
ERROR_1( err, "Invalid uid [%S] for an application, skipping", &appUid );
continue; // Skip this definition.
}
// below: CLEANUP<< appStateSettings
CCFApplicationStateSettings* appStateSettings
= CCFApplicationStateSettings::NewLC( TUid::Uid( uid ), appName );
// Check parameters
const RSettingParameterArray& parameters = iSettings->Item( i ).Parameters();
for( TInt j = 0; j < parameters.Count(); ++j )
{
if ( parameters[ j ]->Name() != KTagView )
{
continue; // At the moment, handle only view tags
}
TPtrC viewUid( KNullDesC );
TPtrC viewName( KNullDesC );
const RKeyValueArray& paramAttr = parameters[ j ]->Attributes();
for( TInt k = 0; k < paramAttr.Count(); ++k )
{
TPtrC key( paramAttr[ k ]->Key() );
TPtrC value( paramAttr[ k ]->Value() );
// Check view uid
if( key.CompareF( KAttributeUid ) == KErrNone )
{
viewUid.Set( value );
}
// Check view name
else if( key.CompareF( KAttributeName ) == KErrNone )
{
viewName.Set( value );
}
}
if ( viewUid.Length() == 0 || viewName.Length() == 0 )
{
ERROR_GEN( "Either View's Uid or Name tag (or both) not found, skipping" );
continue; // Skip this definition.
}
uid = 0;
TInt err = ConvertToHex( viewUid, uid );
if( err != KErrNone )
{
ERROR_1( err, "Invalid view uid [%S], skipping", &viewUid );
continue; // Skip this definition.
}
// below: CLEANUP<< viewUidName
CCFUidNamePair* viewUidName
= CCFUidNamePair::NewLC( TUid::Uid( uid ), viewName );
appStateSettings->AddViewSettingsL( viewUidName );
CleanupStack::Pop( viewUidName ); // CLEANUP>> viewUidName
}
iApplicationSettings.AppendL( appStateSettings );
CleanupStack::Pop( appStateSettings ); // CLEANUP>> appStateSettings
}
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::HandleViewEventL
// Maps view activations to contexts.
// -----------------------------------------------------------------------------
//
void CApplicationStateSourcePlugIn::HandleViewEventL(
const TVwsViewEvent& aEvent )
{
FUNC_LOG;
// Renew listening
iVws->NotifyNextActivation();
// Handle the view server event
DoHandleViewEventL( aEvent );
// Log event members!
INFO_1( "HandleViewEventL: eventType: [%d]", aEvent.iEventType );
INFO_2( "HandleViewEventL: viewOne [appUid:%S] [viewUid%S]",
&(const TDesC&)aEvent.iViewOneId.iAppUid.Name(),
&(const TDesC&)aEvent.iViewOneId.iViewUid.Name() );
INFO_2( "HandleViewEventL: viewTwo [appUid:%S] [viewUid%S]",
&(const TDesC&)aEvent.iViewTwoId.iAppUid.Name(),
&(const TDesC&)aEvent.iViewTwoId.iViewUid.Name() );
}
//------------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::HandleNotifyGeneric
//------------------------------------------------------------------------------
//
void CApplicationStateSourcePlugIn::HandleNotifyGeneric( TUint32 aId )
{
FUNC_LOG;
// Get the new value from cenrep
TInt val = 0;
TInt err = iCRAppOrientation->Get( aId, val );
if( err == KErrNone )
{
// New value found, check if the element is found from cache
TInt index = FindByUid( TUid::Uid( aId ) );
if( index != KErrNotFound )
{
// Update cache element
TUidOrientationPair& pair = iUidOrientationList[index];
pair.iOrientation = val;
INFO_2( "Updated cache uid: [0x%x] to orientation: [%d]", pair.iUid.iUid, val );
}
else
{
// Add new cache element
TUidOrientationPair pair( TUid::Uid( aId ), val );
err = iUidOrientationList.Append( pair );
if( err == KErrNone )
{
INFO_2( "Added cache uid: [0x%x], orientation: [%d]", pair.iUid.iUid, val );
}
else
{
ERROR_1( err, "Failed to add cache uid: [0x%x]", pair.iUid.iUid );
}
}
}
else
{
ERROR_1( err, "Failed to get new value from CR key: [0x%x]", aId );
}
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::DoHandleViewEventL
// Maps view activations to contexts.
// -----------------------------------------------------------------------------
//
void CApplicationStateSourcePlugIn::DoHandleViewEventL(
const TVwsViewEvent& aEvent )
{
FUNC_LOG;
TPtrC bgApp( *iDefaultAppName );
TPtrC fgApp( *iDefaultAppName );
TPtrC fgView( *iDefaultViewName );
TBool bgFound( EFalse );
TBool fgFound( EFalse );
if ( aEvent.iViewTwoId.iAppUid == TUid::Null() )
{
// Previous foreground application was closed, get the stored name for
// background application's name.
bgFound = ETrue;
bgApp.Set( iPreviousForegroundApplication );
}
for ( TInt i = 0; i < iApplicationSettings.Count(); ++i )
{
CCFApplicationStateSettings* appSettings = iApplicationSettings[ i ];
if ( !fgFound && aEvent.iViewOneId.iAppUid == appSettings->Uid() )
{
fgApp.Set( appSettings->Name() );
//Check for flag returned by GetViewName, don't directly set the Flag to ETrue
fgFound = appSettings->GetViewName( aEvent.iViewOneId.iViewUid, fgView );
}
if ( !bgFound && aEvent.iViewTwoId.iAppUid == appSettings->Uid() )
{
bgApp.Set( appSettings->Name() );
bgFound = ETrue;
}
if ( bgFound && fgFound )
{
break;
}
}
TBool publishFgApp( EFalse );
TBool publishFgView( EFalse );
TBool publishBgApp( EFalse );
if ( iPreviousForegroundApplication.Compare( fgApp ) != 0 )
{
publishFgApp = ETrue;
}
else if ( iPreviousForegroundView.Compare( fgView ) != 0 )
{
publishFgView = ETrue;
}
if ( bgApp != fgApp )
{
publishBgApp = ETrue;
}
iPreviousForegroundApplication.Set( fgApp ); // Store for next round
iPreviousForegroundView.Set( fgView );
// Publish foreground application and view contexts.
RThread thread;
if ( publishFgApp )
{
iContext->SetTypeL( KApplicationStateForegroundApplicationType );
iContext->SetValueL( fgApp );
iCF.PublishContext( *iContext, thread );
}
if ( publishFgApp || publishFgView )
{
iContext->SetTypeL( KApplicationStateForegroundApplicationViewType );
iContext->SetValueL( fgView );
iCF.PublishContext( *iContext, thread );
}
if ( publishBgApp )
{
iContext->SetTypeL( KApplicationStateBackgroundApplicationType );
iContext->SetValueL( bgApp );
iCF.PublishContext( *iContext, thread );
}
// Publish foreground application orientation context
TPtrC fgAppOrientation( ResolveFgAppOrientation( aEvent.iViewOneId.iAppUid ) );
if( fgAppOrientation.Length() )
{
// Fg app found
if( fgAppOrientation.Compare( iPreviousOrientation ) != KErrNone )
{
// Update for next round
iPreviousOrientation.Set( fgAppOrientation );
// Fg app orientation changed, publish new context
iContext->SetTypeL( KFgApplicationOrientation );
iContext->SetValueL( fgAppOrientation );
iCF.PublishContext( *iContext, thread );
}
}
thread.Close();
}
//------------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::ResolveFgAppOrientation
//------------------------------------------------------------------------------
//
TPtrC CApplicationStateSourcePlugIn::ResolveFgAppOrientation(
const TUid& aUid )
{
FUNC_LOG;
TPtrC fgAppOrientation( KNullDesC );
TInt val = 0;
// Check cache first
TInt index = FindByUid( aUid );
if( index != KErrNotFound )
{
// App found from cache
val = iUidOrientationList[index].iOrientation;
}
else
{
// Get the SID from cenrep and update cache
TInt err = iCRAppOrientation->Get( aUid.iUid, val );
if( err != KErrNone )
{
INFO_1( "Application uid: [0x%x] not found, using default orientation",
aUid.iUid );
val = iDefaultFgAppOrientation;
}
// Update cache
TUidOrientationPair pair( aUid, val );
err = iUidOrientationList.Append( pair );
if( err != KErrNone )
{
ERROR_2( err, "Failed to add uid: [0x%x], orientation: [%d] pair in cache",
aUid.iUid, val );
}
}
// Resolve context value
if( val == CAknAppUiBase::EAppOrientationPortrait )
{
// Portrait
fgAppOrientation.Set( TPtrC(
KFgApplicationOrientationVal[EFgApplicationOrientationPortrait] ) );
}
else if( val == CAknAppUiBase::EAppOrientationLandscape )
{
// Landscape
fgAppOrientation.Set( TPtrC(
KFgApplicationOrientationVal[EFgApplicationOrientationLandscape] ) );
}
else
{
// Automatic
fgAppOrientation.Set( TPtrC(
KFgApplicationOrientationVal[EFgApplicationOrientationAutomatic] ) );
}
return fgAppOrientation;
}
// -----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::InitializeFgApplicationL
// -----------------------------------------------------------------------------
//
void CApplicationStateSourcePlugIn::InitializeFgApplicationL()
{
FUNC_LOG;
RWsSession wsSession;
User::LeaveIfError( wsSession.Connect() );
CleanupClosePushL( wsSession );
TUid appUid( TUid::Null() );
TInt focScr( wsSession.GetFocusScreen() );
TInt focWndGrp( wsSession.GetFocusWindowGroup() );
TInt wndGrpPrio( wsSession.GetWindowGroupOrdinalPriority( focWndGrp ) );
INFO_1( "CApplicationStateSourcePlugIn::focScr = [%d]", focScr );
INFO_1( "CApplicationStateSourcePlugIn::focWndGrp = [%d]", focWndGrp );
INFO_1( "CApplicationStateSourcePlugIn::wndGrpPrio = [%d]", wndGrpPrio );
CApaWindowGroupName* wndGrpName = CApaWindowGroupName::NewL( wsSession );
CleanupStack::PushL( wndGrpName );
wndGrpName->ConstructFromWgIdL( focWndGrp );
TPtrC appCaption = wndGrpName->Caption();
TPtrC appName = wndGrpName->AppUid().Name();
// if focScr == 0 it's not CoverUi
// if focScr != 0 it's CoverUi
// if wndGrpPrio == 0 it's S60 application
if ( ( focScr != 0 ) || ( ( focScr == 0 ) && ( wndGrpPrio == 0 ) ) )
{
INFO( "CApplicationStateSourcePlugIn::It's CoverUi or S60 application" );
// It is CoverUi
// or
// It is Not CoverUi and it is S60 application
appUid = wndGrpName->AppUid();
INFO_1( "appUid = [0x%x]", appUid.iUid );
}
else
{
// Default values will still be published
TUid tmpAppUid( TUid::Null() );
tmpAppUid = wndGrpName->AppUid();
INFO( "CApplicationStateSourcePlugIn::It's neiher CoverUi nor S60 application" );
INFO_1( "appUid = [0x%x]", tmpAppUid.iUid );
}
INFO_1( "appCaption = [%S]", &appCaption );
INFO_1( "appName = [%S]", &appName );
CleanupStack::PopAndDestroy( wndGrpName );
CleanupStack::PopAndDestroy( &wsSession );
TPtrC bgApp( *iDefaultAppName );
TPtrC fgApp( *iDefaultAppName );
TPtrC fgView( *iDefaultViewName );
if ( appUid != TUid::Null() )
{
for ( TInt i = 0; i < iApplicationSettings.Count(); ++i )
{
CCFApplicationStateSettings* appSettings = iApplicationSettings[ i ];
if ( appUid == appSettings->Uid() )
{
fgApp.Set( appSettings->Name() );
break;
}
}
}
iPreviousForegroundApplication.Set( fgApp ); // Store for next round
iPreviousForegroundView.Set( fgView );
RThread thread;
// Publish foreground application
iContext->SetTypeL( KApplicationStateForegroundApplicationType );
iContext->SetValueL( fgApp );
iCF.PublishContext( *iContext, thread );
// Publish foreground view
iContext->SetTypeL( KApplicationStateForegroundApplicationViewType );
iContext->SetValueL( fgView );
iCF.PublishContext( *iContext, thread );
// Publish background application
iContext->SetTypeL( KApplicationStateBackgroundApplicationType );
iContext->SetValueL( bgApp );
iCF.PublishContext( *iContext, thread );
// Publish foreground application orientation
TPtrC fgAppOrientation( ResolveFgAppOrientation( appUid ) );
iContext->SetTypeL( KFgApplicationOrientation );
iContext->SetValueL( fgAppOrientation );
iCF.PublishContext( *iContext, thread );
// Store for next round
iPreviousOrientation.Set( fgAppOrientation );
thread.Close();
}
//-----------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::ConvertToHex
//-----------------------------------------------------------------------------
//
TInt CApplicationStateSourcePlugIn::ConvertToHex( const TDesC& aString,
TUint32& aValue )
{
FUNC_LOG;
TInt err = KErrNone;
TLex lex( aString );
// Get rid of '0x'
const TInt skip = 2;
lex.Inc( skip );
if( lex.BoundedVal( aValue, EHex, KLimit ) != KErrNone )
{
err = KErrNotFound;
}
return err;
}
//------------------------------------------------------------------------------
// CApplicationStateSourcePlugIn::FindByUid
//------------------------------------------------------------------------------
//
TInt CApplicationStateSourcePlugIn::FindByUid( const TUid& aUid ) const
{
FUNC_LOG;
TInt index = KErrNotFound;
for( TInt i = 0; i < iUidOrientationList.Count(); i++ )
{
if( iUidOrientationList[i].iUid == aUid )
{
index = i;
break;
}
}
return index;
}