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