homescreenapp/hsapplication/src/hsstatemachine.cpp
branchRCL_3
changeset 82 5f0182e07bfb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/homescreenapp/hsapplication/src/hsstatemachine.cpp	Tue Aug 31 15:06:34 2010 +0300
@@ -0,0 +1,504 @@
+/*
+* Copyright (c) 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:  Default implementation of the home state machine.
+*
+*/
+
+#include <QState>
+#include <QFinalState>
+#include <QHistoryState>
+#include <QSignalTransition>
+#include <QKeyEventTransition>
+#include <QKeyEvent>
+
+#include <qvaluespacepublisher.h>
+#include <qservicemanager.h>
+#include <qservicefilter.h>
+#include <qserviceinterfacedescriptor.h>
+
+#include <HbApplication>
+#include <HbActivityManager>
+#include <HbInstance>
+#include <HbIconAnimationManager>
+#include <HbIconAnimationDefinition>
+
+#include "hsmenueventfactory.h"
+#include "homescreendomainpskeys.h"
+#include "hsstatemachine.h"
+#include "hsdatabase.h"
+#include "hscontentservice.h"
+#include "hsshortcutservice.h"
+#include "hsmenueventtransition.h"
+#include "hswidgetpositioningonorientationchange.h"
+#include "hswidgetpositioningonwidgetadd.h"
+#include "hsconfiguration.h"
+#include "hstest_global.h"
+#include "hswidgetpositioningonwidgetmove.h"
+
+#ifdef Q_OS_SYMBIAN
+#include <xqappmgr.h>
+#include <xqcallinfo.h>
+#include <logsservices.h>
+#include <xqrequestinfo.h>
+#endif // Q_OS_SYMBIAN
+
+QTM_USE_NAMESPACE
+#define hbApp qobject_cast<HbApplication*>(qApp)
+
+namespace
+{
+    const char KHsRootStateInterface[] = "com.nokia.homescreen.state.HsRootState";
+    const char KHsLoadSceneStateInterface[] = "com.nokia.homescreen.state.HsLoadSceneState";
+    const char KHsIdleStateInterface[] = "com.nokia.homescreen.state.HsIdleState";
+    const char KHsAppLibraryStateInterface[] = "com.nokia.homescreen.state.HsAppLibraryState";
+    const char KHsMenuWorkerStateInterface[] = "com.nokia.homescreen.state.HsMenuWorkerState";
+    const char KHsBacupRestoreStateInterface[] = "com.nokia.homescreen.state.HsBackupRestoreState";
+}
+
+
+/*!
+    \class HsStateMachine
+    \ingroup group_hsstatemachine
+    \brief Default implementation of the home screen state machine.
+    Creates an execution context (EC) and populates it with
+    runtime services. States are loaded from state plugins.
+    Each state is given an access to the EC. States
+    are added to a state machine. Finally, the state machine
+    is started.
+*/
+
+/*!
+    Constructs state machine with \a parent as the parent object.
+*/
+HsStateMachine::HsStateMachine(QObject *parent)
+    : QStateMachine(parent),
+      mContentService(0),	  
+      mHomeScreenActive(false),
+      mIdleStateActive(false),
+      mEndKeyCaptured(false),
+      mSendKeyCaptured(false),
+      mPublisher(NULL)
+#ifdef Q_OS_SYMBIAN
+	  ,keyCapture()
+#endif
+{
+    HSTEST_FUNC_ENTRY("HS::HsStateMachine::HsStateMachine");
+
+    HsDatabase *db = new HsDatabase(QCoreApplication::instance());
+    db->setConnectionName("homescreen.dbc");
+#ifdef Q_OS_SYMBIAN
+    db->setDatabaseName("c:/private/20022f35/homescreen.db");
+#else
+    db->setDatabaseName("private/20022f35/homescreen.db");
+#endif    
+    db->open();
+    HsDatabase::setInstance(db);
+
+    HsConfiguration::setInstance(new HsConfiguration(QCoreApplication::instance()));
+    HsConfiguration::instance()->load();
+            
+    HsWidgetPositioningOnOrientationChange::setInstance(
+        new HsAdvancedWidgetPositioningOnOrientationChange);
+#ifdef HSWIDGETORGANIZER_ALGORITHM
+    HsWidgetPositioningOnWidgetAdd::setInstance(
+        new HsWidgetOrganizer);
+#else
+    HsWidgetPositioningOnWidgetAdd::setInstance(
+        new HsAnchorPointInBottomRight);
+#endif
+
+    HsWidgetPositioningOnWidgetMove::setInstance(
+        new HsSnapToLines);
+
+    registerAnimations();
+
+    createStatePublisher();
+    createContentServiceParts();
+    createStates();    
+
+    // create the instance so that singleton is accessible from elsewhere
+    HsShortcutService::instance(this);
+
+    QCoreApplication::instance()->installEventFilter(this);
+
+    if (hbApp) { // Qt test framework uses QApplication.
+        connect(hbApp->activityManager(), SIGNAL(activityRequested(QString)), 
+                this, SLOT(activityRequested(QString)));
+    }
+    HSTEST_FUNC_EXIT("HS::HsStateMachine::HsStateMachine");
+}
+
+/*!
+    Destructor.
+*/
+HsStateMachine::~HsStateMachine()
+{
+    HsWidgetPositioningOnOrientationChange::setInstance(0);
+    HsWidgetPositioningOnWidgetAdd::setInstance(0);
+    HsWidgetPositioningOnWidgetMove::setInstance(0);
+    delete mPublisher;
+}
+
+/*!
+    \fn void HsStateMachine::stopStateMachine()
+    Emission of this signal initiates a transition to the final state.
+*/
+
+/*!
+    \copydoc QObject::eventFilter(QObject *watched, QEvent *event)
+*/
+bool HsStateMachine::eventFilter(QObject *watched, QEvent *event)
+{
+    Q_UNUSED(watched);
+
+    switch (event->type()) {
+        case QEvent::ApplicationActivate:
+            qDebug() << "HsStateMachine::eventFilter: QEvent::ApplicationActivate";
+            mHomeScreenActive = true;
+            updatePSKeys();
+            break;
+        case QEvent::ApplicationDeactivate:
+            qDebug() << "HsStateMachine::eventFilter: QEvent::ApplicationDeactivate";
+            mHomeScreenActive = false;
+            updatePSKeys();
+            break;
+        default:
+            break;
+    }
+        
+    bool result =  QStateMachine::eventFilter(watched, event);    
+
+    if (event->type() == QEvent::KeyPress ) {
+        QKeyEvent* ke = static_cast<QKeyEvent *>(event);
+        int key = ke->key();
+
+        if (key == Qt::Key_Home ) {
+            result = true;
+        }
+        else if (key == Qt::Key_Yes ) {
+            result = true;
+            if (mSendKeyCaptured == false && mHomeScreenActive == true) {
+                mSendKeyCaptured = true;
+                startDialer();                
+            }
+        }
+    }
+    return result;
+}
+
+#ifdef COVERAGE_MEASUREMENT
+#pragma CTC SKIP
+#endif //COVERAGE_MEASUREMENT
+/*!
+    \fn void HsStateMachine::startDialer()
+    Starts Dialer application
+*/
+void HsStateMachine::startDialer()
+    {
+    // copy-paste code from dialer widget
+#ifdef Q_OS_SYMBIAN
+    qDebug("HsStateMachine::startDialer()");
+            
+    QList<CallInfo> calls;
+    QScopedPointer<XQCallInfo> callInfo(XQCallInfo::create());
+    callInfo->getCalls(calls);
+    QList<QVariant> args;
+    QString service;
+    QString interface;
+    QString operation;
+
+    if (0 < calls.count()) {
+        qDebug("HS: call ongoing, bring Telephone to foreground");
+        service = "phoneui";
+        interface = "com.nokia.symbian.IStart";
+        operation = "start(int)";
+        int openDialer(0);
+        args << openDialer;
+    } else {
+        qDebug("HS: no calls, open Dialer");
+        service = "logs";
+        interface = "com.nokia.symbian.ILogsView";
+        operation = "show(QVariantMap)";
+        QVariantMap map;
+        map.insert("view_index", QVariant(int(LogsServices::ViewAll)));
+        map.insert("show_dialpad", QVariant(true));
+        map.insert("dialpad_text", QVariant(QString()));
+        args.append(QVariant(map));
+    }
+
+    XQApplicationManager appManager;
+    QScopedPointer<XQAiwRequest> request(appManager.create(service, interface, operation, false));
+    if (request == NULL) {
+        return;
+    }
+    request->setArguments(args);
+    XQRequestInfo info;
+    info.setForeground(true);
+    request->setInfo(info);
+    bool ret = request->send();
+    qDebug("HS: request sent successfully:", ret);
+#endif
+}
+
+#ifdef COVERAGE_MEASUREMENT
+#pragma CTC ENDSKIP
+#endif //COVERAGE_MEASUREMENT
+
+/*!
+    Registers framework animations.
+*/
+void HsStateMachine::registerAnimations()
+{
+    HbIconAnimationManager *manager = HbIconAnimationManager::global();
+    manager->addDefinitionFile(QLatin1String("qtg_anim_loading.axml"));
+}
+
+/*!
+    Creates Home screen state publisher.
+*/
+void HsStateMachine::createStatePublisher()
+{
+    mPublisher = new QValueSpacePublisher(QValueSpace::PermanentLayer, HsStatePSKeyPath);
+
+    if (!mPublisher->isConnected()){
+    	// No permanent layer available
+    	mPublisher = new QValueSpacePublisher(HsStatePSKeyPath);
+    }
+
+    mPublisher->setValue(HsStatePSKeySubPath, EHomeScreenInactive);
+}
+
+/*!
+    Creates content service parts.
+*/
+void HsStateMachine::createContentServiceParts()
+{
+    HSTEST_FUNC_ENTRY("HS::HsStateMachine::createContentServiceParts");
+
+    mContentService = new HsContentService(this);
+
+    HSTEST_FUNC_EXIT("HS::HsStateMachine::createContentServiceParts");
+}
+
+/*!
+    Creates states.
+*/
+void HsStateMachine::createStates()
+{
+    HSTEST_FUNC_ENTRY("HS::HsStateMachine::createStates");
+
+    QFinalState *finalState = new QFinalState();
+    addState(finalState);
+
+    QState *guiRootState = new QState();
+    addState(guiRootState);
+
+    guiRootState->addTransition(this, SIGNAL(event_exit()), finalState);
+
+    QServiceManager manager;
+
+    
+    QObject *loadSceneStateObj = manager.loadInterface(KHsLoadSceneStateInterface);
+    QState *loadSceneState = qobject_cast<QState *>(loadSceneStateObj);
+    loadSceneState->setParent(guiRootState);
+    loadSceneState->setObjectName(KHsLoadSceneStateInterface);
+
+    QObject *rootStateObj = manager.loadInterface(KHsRootStateInterface);
+    QState *rootState = qobject_cast<QState *>(rootStateObj);   
+    rootState->setParent(guiRootState);
+    rootState->setObjectName(KHsRootStateInterface);       
+
+    QObject *idleStateObj = manager.loadInterface(KHsIdleStateInterface);
+    QState *idleState = qobject_cast<QState *>(idleStateObj);
+    idleState->setParent(rootState);
+    idleState->setObjectName(KHsIdleStateInterface);
+	connect(idleState, SIGNAL(entered()), SLOT(onIdleStateEntered()));
+	connect(idleState, SIGNAL(exited()), SLOT(onIdleStateExited()));
+
+
+    //menu state
+    QState *menuParallelState = new QState(
+            QState::ParallelStates, rootState);
+    QState *menuRootState = new QState(menuParallelState);
+
+    QObject *appLibraryStateObj = manager.loadInterface(KHsAppLibraryStateInterface);
+    QState *appLibraryState = qobject_cast<QState *>(appLibraryStateObj);
+    appLibraryState->setParent(menuRootState);
+    appLibraryState->setObjectName(KHsAppLibraryStateInterface);
+    menuRootState->setInitialState(appLibraryState);
+
+    QHistoryState *historyState = new QHistoryState(rootState);
+    historyState->setDefaultState(idleState);
+    
+    loadSceneState->addTransition(
+            loadSceneState, SIGNAL(event_history()), historyState);            
+
+    QObject *menuWorkerStateObj = manager.loadInterface(KHsMenuWorkerStateInterface);
+    QState *menuWorkerState = qobject_cast<QState *>(menuWorkerStateObj);
+    menuWorkerState->setParent(menuParallelState);
+    menuWorkerState->setObjectName(KHsMenuWorkerStateInterface);
+
+    connect(appLibraryState, SIGNAL(collectionEntered()), 
+            menuWorkerState, SIGNAL(reset()));
+
+    //Backup/Restore state
+    QObject *backupRestoreStateObj = manager.loadInterface(KHsBacupRestoreStateInterface);
+    QState *backupRestoreState = qobject_cast<QState *>(backupRestoreStateObj);   
+    backupRestoreState->setParent(guiRootState);
+    backupRestoreState->setObjectName(KHsBacupRestoreStateInterface);
+    backupRestoreState->addTransition(
+            backupRestoreState, SIGNAL(event_loadScene()), loadSceneState);
+
+    // root state transitions
+    idleState->addTransition(idleState, SIGNAL(event_applicationLibrary()), menuRootState);
+    appLibraryState->addTransition(
+            appLibraryState, SIGNAL(toHomescreenState()), idleState);
+    rootState->addTransition(rootState, SIGNAL(event_backupRestore()), backupRestoreState);
+    // opening shortcut to Application Library
+    HsMenuEventTransition *idleToAppLibTransition =
+        new HsMenuEventTransition(HsMenuEvent::OpenApplicationLibrary,
+                                  idleState, appLibraryState);
+    idleState->addTransition(idleToAppLibTransition);
+
+    HsMenuEventTransition *appLibToIdleTransition =
+        new HsMenuEventTransition(
+            HsMenuEvent::OpenHomeScreen, appLibraryState, idleState);
+    appLibraryState->addTransition(appLibToIdleTransition);
+
+    HbMainWindow *window = hbInstance->allMainWindows().first();
+
+#ifndef  Q_OS_SYMBIAN   
+    // key driven transition from idle to menu
+    QKeyEventTransition *idleToMenuRootTransition =
+        new QKeyEventTransition(
+                window, QEvent::KeyPress, Qt::Key_Home);
+    idleToMenuRootTransition->setTargetState(menuRootState);
+    idleState->addTransition(idleToMenuRootTransition);
+    // key driven transition from menu to idle
+    QKeyEventTransition *menuToIdleTransition =
+        new QKeyEventTransition(
+                window, QEvent::KeyPress, Qt::Key_Home);
+    menuToIdleTransition->setTargetState(idleState);
+    menuRootState->addTransition(menuToIdleTransition);
+#endif 
+    // key driven transition from menu to idle
+    QKeyEventTransition *menuToIdleTransitionNoKey =
+        new QKeyEventTransition(
+                window, QEvent::KeyPress, Qt::Key_No);
+    menuToIdleTransitionNoKey->setTargetState(idleState);
+    menuRootState->addTransition(menuToIdleTransitionNoKey);
+    
+    // add transition to switch to idle
+    menuRootState->addTransition( this, SIGNAL(event_toIdle()), idleState);    
+    // add transition to switch to applib 
+    idleState->addTransition( this, SIGNAL(event_toAppLib()), menuRootState);
+    
+    // transitions to child states
+    // opening shortcut to a colleciton
+    QList<QState *> collectionStates =
+        appLibraryState->
+            findChildren<QState *>
+                ("homescreen.nokia.com/state/applibrarystate/collectionstate");
+    qDebug(
+        "Found %d \"collectionstate\" children for Application Library State",
+            collectionStates.count());
+    if (collectionStates.count()) {
+        HsMenuEventTransition *idleToCollectionTransition =
+            new HsMenuEventTransition(HsMenuEvent::OpenCollection,
+                                      idleState, collectionStates[0]);
+        idleState->addTransition(idleToCollectionTransition);
+    }
+
+    guiRootState->setInitialState(loadSceneState);
+    setInitialState(guiRootState);
+    
+    HSTEST_FUNC_EXIT("HS::HsStateMachine::createStates");
+}
+
+
+/*!
+    Publishes Home screen states via Publish & Subscribe.
+*/
+void HsStateMachine::updatePSKeys()
+{	
+	if (!mPublisher){
+		createStatePublisher();
+	}
+
+	if (mHomeScreenActive && mIdleStateActive){
+    	qDebug() << "HsStateMachine::updatePSKeys: EHomeScreenIdleState";
+    	mPublisher->setValue(HsStatePSKeySubPath, EHomeScreenIdleState);
+    }
+    else{
+    	qDebug() << "HsStateMachine::updatePSKeys: EHomeScreenInactive";
+    	mPublisher->setValue(HsStatePSKeySubPath, EHomeScreenInactive);
+    }	
+    
+    if (mHomeScreenActive && !mIdleStateActive) {
+        captureEndKey(true);
+    } else {
+        captureEndKey(false);
+    }
+    mSendKeyCaptured = false;
+}
+
+/*!
+    capture End key 
+*/
+void HsStateMachine::captureEndKey(bool enable) 
+{
+#ifdef Q_OS_SYMBIAN
+    if (enable && !mEndKeyCaptured) {
+        mEndKeyCaptured = true;
+        keyCapture.captureKey(Qt::Key_No);        
+    } else if (mEndKeyCaptured) {
+        mEndKeyCaptured = false;
+        keyCapture.cancelCaptureKey(Qt::Key_No);
+    }
+#endif
+}
+
+/*!
+    Called when state machine is in Idle state.
+*/
+void HsStateMachine::onIdleStateEntered()
+{
+	mIdleStateActive = true;
+	updatePSKeys();
+}
+
+/*!
+    Called when state machine leaves the Idle state.
+*/
+void HsStateMachine::onIdleStateExited()
+{
+	mIdleStateActive = false;
+	updatePSKeys();
+}
+
+/*!
+    Activity requested by another client 
+*/
+void HsStateMachine::activityRequested(const QString &name) 
+{
+    if (name == Hs::groupAppLibRecentView) {
+        this->postEvent(
+            HsMenuEventFactory::createOpenCollectionEvent(0,
+            Hs::collectionDownloadedTypeName));
+    } else if (name == Hs::activityHsIdleView) {
+        emit event_toIdle();
+    } else if (name == Hs::activityAppLibMainView) {
+        emit event_toAppLib();
+    }
+}