|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Default implementation of the home state machine. |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <QState> |
|
19 #include <QFinalState> |
|
20 #include <QHistoryState> |
|
21 #include <QSignalTransition> |
|
22 #include <QKeyEventTransition> |
|
23 #include <QKeyEvent> |
|
24 |
|
25 #include <qvaluespacepublisher.h> |
|
26 #include <qservicemanager.h> |
|
27 #include <qservicefilter.h> |
|
28 #include <qserviceinterfacedescriptor.h> |
|
29 |
|
30 #include <HbApplication> |
|
31 #include <HbActivityManager> |
|
32 #include <HbInstance> |
|
33 #include <HbIconAnimationManager> |
|
34 #include <HbIconAnimationDefinition> |
|
35 |
|
36 #include "hsmenueventfactory.h" |
|
37 #include "homescreendomainpskeys.h" |
|
38 #include "hsstatemachine.h" |
|
39 #include "hsdatabase.h" |
|
40 #include "hscontentservice.h" |
|
41 #include "hsshortcutservice.h" |
|
42 #include "hsmenueventtransition.h" |
|
43 #include "hswidgetpositioningonorientationchange.h" |
|
44 #include "hswidgetpositioningonwidgetadd.h" |
|
45 #include "hsconfiguration.h" |
|
46 #include "hstest_global.h" |
|
47 #include "hswidgetpositioningonwidgetmove.h" |
|
48 |
|
49 QTM_USE_NAMESPACE |
|
50 #define hbApp qobject_cast<HbApplication*>(qApp) |
|
51 |
|
52 #ifdef Q_OS_SYMBIAN |
|
53 const static Qt::Key applicationKey = Qt::Key_Menu; |
|
54 #else |
|
55 const static Qt::Key applicationKey = Qt::Key_Home; |
|
56 #endif |
|
57 |
|
58 namespace |
|
59 { |
|
60 const char KHsRootStateInterface[] = "com.nokia.homescreen.state.HsRootState"; |
|
61 const char KHsLoadSceneStateInterface[] = "com.nokia.homescreen.state.HsLoadSceneState"; |
|
62 const char KHsIdleStateInterface[] = "com.nokia.homescreen.state.HsIdleState"; |
|
63 const char KHsAppLibraryStateInterface[] = "com.nokia.homescreen.state.HsAppLibraryState"; |
|
64 const char KHsMenuWorkerStateInterface[] = "com.nokia.homescreen.state.HsMenuWorkerState"; |
|
65 const char KHsBacupRestoreStateInterface[] = "com.nokia.homescreen.state.HsBackupRestoreState"; |
|
66 } |
|
67 |
|
68 |
|
69 /*! |
|
70 \class HsStateMachine |
|
71 \ingroup group_hsstatemachine |
|
72 \brief Default implementation of the home screen state machine. |
|
73 Creates an execution context (EC) and populates it with |
|
74 runtime services. States are loaded from state plugins. |
|
75 Each state is given an access to the EC. States |
|
76 are added to a state machine. Finally, the state machine |
|
77 is started. |
|
78 */ |
|
79 |
|
80 /*! |
|
81 Constructs state machine with \a parent as the parent object. |
|
82 */ |
|
83 HsStateMachine::HsStateMachine(QObject *parent) |
|
84 : QStateMachine(parent), |
|
85 mContentService(0), |
|
86 mHomeScreenActive(false), |
|
87 mIdleStateActive(false), |
|
88 mPublisher(NULL) |
|
89 #ifdef Q_OS_SYMBIAN |
|
90 ,keyCapture() |
|
91 #endif |
|
92 { |
|
93 HSTEST_FUNC_ENTRY("HS::HsStateMachine::HsStateMachine"); |
|
94 |
|
95 HsDatabase *db = new HsDatabase; |
|
96 db->setConnectionName("homescreen.dbc"); |
|
97 #ifdef Q_OS_SYMBIAN |
|
98 db->setDatabaseName("c:/private/20022f35/homescreen.db"); |
|
99 #else |
|
100 db->setDatabaseName("private/20022f35/homescreen.db"); |
|
101 #endif |
|
102 db->open(); |
|
103 HsDatabase::setInstance(db); |
|
104 |
|
105 HsConfiguration::setInstance(new HsConfiguration); |
|
106 HsConfiguration::instance()->load(); |
|
107 |
|
108 HsWidgetPositioningOnOrientationChange::setInstance( |
|
109 new HsAdvancedWidgetPositioningOnOrientationChange); |
|
110 |
|
111 HsWidgetPositioningOnWidgetAdd::setInstance( |
|
112 new HsAnchorPointInBottomRight); |
|
113 |
|
114 HsWidgetPositioningOnWidgetMove::setInstance( |
|
115 new HsSnapToLines); |
|
116 |
|
117 registerAnimations(); |
|
118 |
|
119 createStatePublisher(); |
|
120 createContentServiceParts(); |
|
121 createStates(); |
|
122 |
|
123 // create the instance so that singleton is accessible from elsewhere |
|
124 HsShortcutService::instance(this); |
|
125 |
|
126 QCoreApplication::instance()->installEventFilter(this); |
|
127 |
|
128 if (hbApp) { // Qt test framework uses QApplication. |
|
129 connect(hbApp->activityManager(), SIGNAL(activityRequested(QString)), |
|
130 this, SLOT(activityRequested(QString))); |
|
131 } |
|
132 HSTEST_FUNC_EXIT("HS::HsStateMachine::HsStateMachine"); |
|
133 } |
|
134 |
|
135 /*! |
|
136 Destructor. |
|
137 */ |
|
138 HsStateMachine::~HsStateMachine() |
|
139 { |
|
140 HsWidgetPositioningOnOrientationChange::setInstance(0); |
|
141 delete mPublisher; |
|
142 } |
|
143 |
|
144 /*! |
|
145 \fn void HsStateMachine::stopStateMachine() |
|
146 Emission of this signal initiates a transition to the final state. |
|
147 */ |
|
148 |
|
149 /*! |
|
150 \copydoc QObject::eventFilter(QObject *watched, QEvent *event) |
|
151 */ |
|
152 bool HsStateMachine::eventFilter(QObject *watched, QEvent *event) |
|
153 { |
|
154 Q_UNUSED(watched); |
|
155 |
|
156 switch (event->type()) { |
|
157 case QEvent::ApplicationActivate: |
|
158 qDebug() << "HsStateMachine::eventFilter: QEvent::ApplicationActivate"; |
|
159 #ifdef Q_OS_SYMBIAN |
|
160 keyCapture.captureKey(applicationKey); |
|
161 #endif |
|
162 mHomeScreenActive = true; |
|
163 updatePSKeys(); |
|
164 break; |
|
165 case QEvent::ApplicationDeactivate: |
|
166 qDebug() << "HsStateMachine::eventFilter: QEvent::ApplicationDeactivate"; |
|
167 #ifdef Q_OS_SYMBIAN |
|
168 keyCapture.cancelCaptureKey(applicationKey); |
|
169 #endif |
|
170 mHomeScreenActive = false; |
|
171 updatePSKeys(); |
|
172 break; |
|
173 default: |
|
174 break; |
|
175 } |
|
176 |
|
177 bool result = QStateMachine::eventFilter(watched, event); |
|
178 // temporary hack as we should not register twice for events |
|
179 if (event->type() == QEvent::KeyPress ) { |
|
180 QKeyEvent* ke = static_cast<QKeyEvent *>(event); |
|
181 // Key_Launch0 should be removed when QT starts to send Key_Menu |
|
182 result = (ke->key() == applicationKey) || ke->key() == Qt::Key_Launch0; |
|
183 } |
|
184 return result; |
|
185 } |
|
186 |
|
187 |
|
188 /*! |
|
189 Registers framework animations. |
|
190 */ |
|
191 void HsStateMachine::registerAnimations() |
|
192 { |
|
193 HbIconAnimationManager *manager = HbIconAnimationManager::global(); |
|
194 manager->addDefinitionFile(QLatin1String("qtg_anim_loading.axml")); |
|
195 } |
|
196 |
|
197 /*! |
|
198 Creates Home screen state publisher. |
|
199 */ |
|
200 void HsStateMachine::createStatePublisher() |
|
201 { |
|
202 mPublisher = new QValueSpacePublisher(QValueSpace::PermanentLayer, HsStatePSKeyPath); |
|
203 |
|
204 if (!mPublisher->isConnected()){ |
|
205 // No permanent layer available |
|
206 mPublisher = new QValueSpacePublisher(HsStatePSKeyPath); |
|
207 } |
|
208 |
|
209 mPublisher->setValue(HsStatePSKeySubPath, EHomeScreenInactive); |
|
210 } |
|
211 |
|
212 /*! |
|
213 Creates content service parts. |
|
214 */ |
|
215 void HsStateMachine::createContentServiceParts() |
|
216 { |
|
217 HSTEST_FUNC_ENTRY("HS::HsStateMachine::createContentServiceParts"); |
|
218 |
|
219 mContentService = new HsContentService(this); |
|
220 |
|
221 HSTEST_FUNC_EXIT("HS::HsStateMachine::createContentServiceParts"); |
|
222 } |
|
223 |
|
224 /*! |
|
225 Creates states. |
|
226 */ |
|
227 void HsStateMachine::createStates() |
|
228 { |
|
229 HSTEST_FUNC_ENTRY("HS::HsStateMachine::createStates"); |
|
230 |
|
231 QFinalState *finalState = new QFinalState(); |
|
232 addState(finalState); |
|
233 |
|
234 QState *guiRootState = new QState(); |
|
235 addState(guiRootState); |
|
236 |
|
237 guiRootState->addTransition(this, SIGNAL(event_exit()), finalState); |
|
238 |
|
239 QServiceManager manager; |
|
240 |
|
241 |
|
242 QObject *loadSceneStateObj = manager.loadInterface(KHsLoadSceneStateInterface); |
|
243 QState *loadSceneState = qobject_cast<QState *>(loadSceneStateObj); |
|
244 loadSceneState->setParent(guiRootState); |
|
245 loadSceneState->setObjectName(KHsLoadSceneStateInterface); |
|
246 |
|
247 QObject *rootStateObj = manager.loadInterface(KHsRootStateInterface); |
|
248 QState *rootState = qobject_cast<QState *>(rootStateObj); |
|
249 rootState->setParent(guiRootState); |
|
250 rootState->setObjectName(KHsRootStateInterface); |
|
251 |
|
252 QObject *idleStateObj = manager.loadInterface(KHsIdleStateInterface); |
|
253 QState *idleState = qobject_cast<QState *>(idleStateObj); |
|
254 idleState->setParent(rootState); |
|
255 idleState->setObjectName(KHsIdleStateInterface); |
|
256 connect(idleState, SIGNAL(entered()), SLOT(onIdleStateEntered())); |
|
257 connect(idleState, SIGNAL(exited()), SLOT(onIdleStateExited())); |
|
258 |
|
259 |
|
260 //menu state |
|
261 QState *menuParallelState = new QState( |
|
262 QState::ParallelStates, rootState); |
|
263 QState *menuRootState = new QState(menuParallelState); |
|
264 |
|
265 QObject *appLibraryStateObj = manager.loadInterface(KHsAppLibraryStateInterface); |
|
266 QState *appLibraryState = qobject_cast<QState *>(appLibraryStateObj); |
|
267 appLibraryState->setParent(menuRootState); |
|
268 appLibraryState->setObjectName(KHsAppLibraryStateInterface); |
|
269 menuRootState->setInitialState(appLibraryState); |
|
270 |
|
271 QHistoryState *historyState = new QHistoryState(rootState); |
|
272 historyState->setDefaultState(idleState); |
|
273 |
|
274 loadSceneState->addTransition( |
|
275 loadSceneState, SIGNAL(event_history()), historyState); |
|
276 |
|
277 QObject *menuWorkerStateObj = manager.loadInterface(KHsMenuWorkerStateInterface); |
|
278 QState *menuWorkerState = qobject_cast<QState *>(menuWorkerStateObj); |
|
279 menuWorkerState->setParent(menuParallelState); |
|
280 menuWorkerState->setObjectName(KHsMenuWorkerStateInterface); |
|
281 |
|
282 connect(appLibraryState, SIGNAL(collectionEntered()), |
|
283 menuWorkerState, SIGNAL(reset())); |
|
284 |
|
285 //Backup/Restore state |
|
286 QObject *backupRestoreStateObj = manager.loadInterface(KHsBacupRestoreStateInterface); |
|
287 QState *backupRestoreState = qobject_cast<QState *>(backupRestoreStateObj); |
|
288 backupRestoreState->setParent(guiRootState); |
|
289 backupRestoreState->setObjectName(KHsBacupRestoreStateInterface); |
|
290 backupRestoreState->addTransition( |
|
291 backupRestoreState, SIGNAL(event_loadScene()), loadSceneState); |
|
292 |
|
293 // root state transitions |
|
294 idleState->addTransition(idleState, SIGNAL(event_applicationLibrary()), menuRootState); |
|
295 appLibraryState->addTransition( |
|
296 appLibraryState, SIGNAL(toHomescreenState()), idleState); |
|
297 rootState->addTransition(rootState, SIGNAL(event_backupRestore()), backupRestoreState); |
|
298 // opening shortcut to Application Library |
|
299 HsMenuEventTransition *idleToAppLibTransition = |
|
300 new HsMenuEventTransition(HsMenuEvent::OpenApplicationLibrary, |
|
301 idleState, appLibraryState); |
|
302 idleState->addTransition(idleToAppLibTransition); |
|
303 |
|
304 HsMenuEventTransition *appLibToIdleTransition = |
|
305 new HsMenuEventTransition( |
|
306 HsMenuEvent::OpenHomeScreen, appLibraryState, idleState); |
|
307 appLibraryState->addTransition(appLibToIdleTransition); |
|
308 |
|
309 HbMainWindow *window = hbInstance->allMainWindows().first(); |
|
310 |
|
311 // key driven transition from idle to menu |
|
312 QKeyEventTransition *idleToMenuRootTransition = |
|
313 new QKeyEventTransition( |
|
314 window, QEvent::KeyPress, applicationKey); |
|
315 idleToMenuRootTransition->setTargetState(menuRootState); |
|
316 idleState->addTransition(idleToMenuRootTransition); |
|
317 // key driven transition from menu to idle |
|
318 QKeyEventTransition *menuToIdleTransition = |
|
319 new QKeyEventTransition( |
|
320 window, QEvent::KeyPress, applicationKey); |
|
321 menuToIdleTransition->setTargetState(idleState); |
|
322 menuRootState->addTransition(menuToIdleTransition); |
|
323 |
|
324 // transition for Key_Launch0 should be removed |
|
325 // when OT starts to send Key_Menu (maybe wk14) |
|
326 QKeyEventTransition *idleToMenuRootTransition2 = |
|
327 new QKeyEventTransition( |
|
328 window, QEvent::KeyPress, Qt::Key_Launch0); |
|
329 idleToMenuRootTransition2->setTargetState(menuRootState); |
|
330 idleState->addTransition(idleToMenuRootTransition2); |
|
331 // key driven transition from menu to idle |
|
332 QKeyEventTransition *menuToIdleTransition2 = |
|
333 new QKeyEventTransition( |
|
334 window, QEvent::KeyPress, Qt::Key_Launch0); |
|
335 menuToIdleTransition2->setTargetState(idleState); |
|
336 menuRootState->addTransition(menuToIdleTransition2); |
|
337 // add transition to switch to idle |
|
338 menuRootState->addTransition( this, SIGNAL(event_toIdle()), idleState); |
|
339 |
|
340 // transitions to child states |
|
341 // opening shortcut to a colleciton |
|
342 QList<QState *> collectionStates = |
|
343 appLibraryState-> |
|
344 findChildren<QState *> |
|
345 ("homescreen.nokia.com/state/applibrarystate/collectionstate"); |
|
346 qDebug( |
|
347 "Found %d \"collectionstate\" children for Application Library State", |
|
348 collectionStates.count()); |
|
349 if (collectionStates.count()) { |
|
350 HsMenuEventTransition *idleToCollectionTransition = |
|
351 new HsMenuEventTransition(HsMenuEvent::OpenCollection, |
|
352 idleState, collectionStates[0]); |
|
353 idleState->addTransition(idleToCollectionTransition); |
|
354 } |
|
355 |
|
356 guiRootState->setInitialState(loadSceneState); |
|
357 setInitialState(guiRootState); |
|
358 |
|
359 HSTEST_FUNC_EXIT("HS::HsStateMachine::createStates"); |
|
360 } |
|
361 |
|
362 |
|
363 /*! |
|
364 Publishes Home screen states via Publish & Subscribe. |
|
365 */ |
|
366 void HsStateMachine::updatePSKeys() |
|
367 { |
|
368 if (!mPublisher){ |
|
369 createStatePublisher(); |
|
370 } |
|
371 |
|
372 if (mHomeScreenActive && mIdleStateActive){ |
|
373 qDebug() << "HsStateMachine::updatePSKeys: EHomeScreenIdleState"; |
|
374 mPublisher->setValue(HsStatePSKeySubPath, EHomeScreenIdleState); |
|
375 } |
|
376 else{ |
|
377 qDebug() << "HsStateMachine::updatePSKeys: EHomeScreenInactive"; |
|
378 mPublisher->setValue(HsStatePSKeySubPath, EHomeScreenInactive); |
|
379 } |
|
380 } |
|
381 |
|
382 /*! |
|
383 Called when state machine is in Idle state. |
|
384 */ |
|
385 void HsStateMachine::onIdleStateEntered() |
|
386 { |
|
387 mIdleStateActive = true; |
|
388 updatePSKeys(); |
|
389 } |
|
390 |
|
391 /*! |
|
392 Called when state machine leaves the Idle state. |
|
393 */ |
|
394 void HsStateMachine::onIdleStateExited() |
|
395 { |
|
396 mIdleStateActive = false; |
|
397 updatePSKeys(); |
|
398 } |
|
399 |
|
400 /*! |
|
401 Activity requested by another client |
|
402 */ |
|
403 void HsStateMachine::activityRequested(const QString &name) |
|
404 { |
|
405 if (name == groupAppLibRecentView()) { |
|
406 this->postEvent( |
|
407 HsMenuEventFactory::createOpenCollectionEvent(0, |
|
408 collectionDownloadedTypeName())); |
|
409 } else if (name == activityHsIdleView()) { |
|
410 emit event_toIdle(); |
|
411 } |
|
412 } |