|
1 /* |
|
2 * Copyright (c) 2006 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: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 #include "transitionmanager.h" |
|
21 #include <eikapp.h> |
|
22 #include <aknappui.h> |
|
23 #include <gfxtranseffect/gfxtranseffect.h> |
|
24 #include <akntranseffect.h> // for Transition effect enumerations |
|
25 #include <e32property.h> |
|
26 #include <UikonInternalPSKeys.h> |
|
27 #include <featmgr.h> |
|
28 #include <pslninternalcrkeys.h> |
|
29 #include <centralrepository.h> |
|
30 #include <apgwgnam.h> |
|
31 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
32 #include <vwsdefpartner.h> |
|
33 #endif |
|
34 |
|
35 //this class fix a memory leak: |
|
36 //there were cases when exit effect was not called in |
|
37 //preparetoexit (inproper parent class, thanks (mostly) to C++) |
|
38 //this class ensures that exit is called when enviroment statics are still alive |
|
39 //great integration point to keep in mind! |
|
40 NONSHARABLE_CLASS(CExitWatch) : public CCoeStatic |
|
41 { |
|
42 public: |
|
43 CExitWatch(MExit& aExit); |
|
44 ~CExitWatch(); |
|
45 private: |
|
46 MExit& iExit; |
|
47 }; |
|
48 |
|
49 |
|
50 const TUid KExitWatchStatic = |
|
51 { |
|
52 0x100056C6 //this is avkon uid.... propably a new uid should be allocated. |
|
53 }; |
|
54 |
|
55 CExitWatch::CExitWatch(MExit& aExit) : CCoeStatic(KExitWatchStatic, 0xFFFFFFF), //just any priority > 100 is enough as tfx uses that |
|
56 iExit(aExit) |
|
57 { |
|
58 } |
|
59 |
|
60 CExitWatch::~CExitWatch() |
|
61 { |
|
62 iExit.DoExit(); |
|
63 } |
|
64 |
|
65 |
|
66 NONSHARABLE_CLASS(CCenRepListen) : public CActive, public MKeyValue |
|
67 { |
|
68 public: |
|
69 static CCenRepListen* NewL(const TUid& aRep, const TUint32 aKey, MKeyListener& aListener); |
|
70 TInt Value() const; |
|
71 TUint32 Key() const; |
|
72 void Listen(); |
|
73 ~CCenRepListen(); |
|
74 private: |
|
75 CCenRepListen(const TUint32 aKey, MKeyListener& aListener); |
|
76 void ConstructL(const TUid& aRep); |
|
77 void DoCancel(); |
|
78 void RunL(); |
|
79 private: |
|
80 const TUint32 iKey; |
|
81 MKeyListener& iListener; |
|
82 TInt iValue; |
|
83 CRepository* iRepository; |
|
84 }; |
|
85 |
|
86 |
|
87 CCenRepListen* CCenRepListen::NewL(const TUid& aRep, const TUint32 aKey, MKeyListener& aListener) |
|
88 { |
|
89 CCenRepListen* l = new (ELeave) CCenRepListen(aKey, aListener); |
|
90 CleanupStack::PushL(l); |
|
91 l->ConstructL(aRep); |
|
92 CleanupStack::Pop(); |
|
93 return l; |
|
94 } |
|
95 |
|
96 TInt CCenRepListen::Value() const |
|
97 { |
|
98 return iValue; |
|
99 } |
|
100 |
|
101 TUint32 CCenRepListen::Key() const |
|
102 { |
|
103 return iKey; |
|
104 } |
|
105 |
|
106 void CCenRepListen::Listen() |
|
107 { |
|
108 Cancel(); |
|
109 SetActive(); |
|
110 iRepository->NotifyRequest(iKey, iStatus); |
|
111 } |
|
112 |
|
113 CCenRepListen::CCenRepListen(const TUint32 aKey, MKeyListener& aListener) : |
|
114 CActive(CActive::EPriorityStandard), iKey(aKey), iListener(aListener) |
|
115 { |
|
116 CActiveScheduler::Add(this); |
|
117 } |
|
118 |
|
119 void CCenRepListen::ConstructL(const TUid& aRep) |
|
120 { |
|
121 iRepository = CRepository::NewL(aRep); |
|
122 User::LeaveIfError(iRepository->Get(iKey, iValue)); |
|
123 } |
|
124 |
|
125 void CCenRepListen::DoCancel() |
|
126 { |
|
127 iRepository->NotifyCancelAll(); |
|
128 } |
|
129 |
|
130 void CCenRepListen::RunL() |
|
131 { |
|
132 User::LeaveIfError(iRepository->Get(iKey, iValue)); |
|
133 iListener.KeyChangedL(*this); |
|
134 } |
|
135 |
|
136 CCenRepListen::~CCenRepListen() |
|
137 { |
|
138 Cancel(); |
|
139 delete iRepository; |
|
140 } |
|
141 |
|
142 |
|
143 ////////////////////////////////////////////////////////////////////////// |
|
144 |
|
145 |
|
146 _LIT(KTfxServerName,"TfxServer"); |
|
147 const TInt KLimit(100); |
|
148 |
|
149 NONSHARABLE_CLASS(CServerWait) : public CTimer |
|
150 { |
|
151 public: |
|
152 static TBool WaitL(); |
|
153 private: |
|
154 CServerWait(); |
|
155 void RunL(); |
|
156 private: |
|
157 TInt iCount; |
|
158 }; |
|
159 |
|
160 |
|
161 |
|
162 CServerWait::CServerWait() : CTimer(CActive::EPriorityIdle) |
|
163 { |
|
164 CActiveScheduler::Add(this); |
|
165 } |
|
166 |
|
167 TBool CServerWait::WaitL() |
|
168 { |
|
169 CServerWait* wait = new (ELeave) CServerWait(); |
|
170 CleanupStack::PushL(wait); |
|
171 wait->ConstructL(); |
|
172 wait->After(1); |
|
173 CActiveScheduler::Start(); |
|
174 const TBool ok = wait->iCount <= KLimit; |
|
175 CleanupStack::PopAndDestroy(); //wait |
|
176 return ok; |
|
177 } |
|
178 |
|
179 void CServerWait::RunL() |
|
180 { |
|
181 TFullName fullName; |
|
182 TFindServer find(KTfxServerName); |
|
183 if(iCount > KLimit || KErrNone == find.Next(fullName)) |
|
184 { |
|
185 CActiveScheduler::Stop(); |
|
186 } |
|
187 else |
|
188 { |
|
189 ++iCount; |
|
190 After(10000); |
|
191 } |
|
192 } |
|
193 |
|
194 |
|
195 |
|
196 /////////////////////////////////////////////////////////////////////////// |
|
197 |
|
198 CTransitionManager* CTransitionManager::NewL(CEikonEnv& aEnv) |
|
199 { |
|
200 if(!FeatureManager::FeatureSupported(KFeatureIdUiTransitionEffects)) |
|
201 return NULL; //this is only place where flag was used since calling it is slow, after that this ptr indicates its presense |
|
202 CTransitionManager* tm = new (ELeave) CTransitionManager(aEnv); |
|
203 CleanupStack::PushL(tm); |
|
204 tm->ConstructL(); |
|
205 CleanupStack::Pop(); |
|
206 return tm; |
|
207 } |
|
208 |
|
209 |
|
210 CTransitionManager::CTransitionManager(CEikonEnv& aEnv) : iEikEnv(aEnv) |
|
211 { |
|
212 } |
|
213 |
|
214 |
|
215 void CTransitionManager::AppStartupComplete() |
|
216 { |
|
217 TRAP_IGNORE( iEikEnv.EikAppUi()->AddViewObserverL( this ) ); |
|
218 if(iFlags & EStarted) |
|
219 { |
|
220 iStartIdleState = ETransEffectWaitingForAppSwitch; |
|
221 iFlags |= EStartupStarted; |
|
222 } |
|
223 else |
|
224 { |
|
225 iFlags |= (EStarted | EStartupStarted | EStartupComplete); |
|
226 GfxTransEffect::AbortFullScreen(); |
|
227 } |
|
228 } |
|
229 |
|
230 |
|
231 void CTransitionManager::ConstructL() |
|
232 { |
|
233 iAppStartupIdle = CIdle::NewL( CActive::EPriorityIdle ); |
|
234 iCRListen = CCenRepListen::NewL(KCRUidThemes, KThemesTransitionEffects, *this); |
|
235 CheckEffectsL(EFalse); |
|
236 new (ELeave) CExitWatch(*this); //it is enviroment static, pointer to that is not needed |
|
237 } |
|
238 |
|
239 |
|
240 void CTransitionManager::DoExit() |
|
241 { |
|
242 if(iFlags & EStartupComplete && iAppUid != KNullUid) |
|
243 { |
|
244 RWsSession ses; |
|
245 if(KErrNone == ses.Connect()) |
|
246 { |
|
247 TThreadId focusThreadId; |
|
248 ses.GetWindowGroupClientThreadId(ses.GetFocusWindowGroup(), focusThreadId); |
|
249 RThread myThread; |
|
250 if(myThread.Id() == focusThreadId) |
|
251 { |
|
252 AppExit(AknTransEffect::EApplicationExit, iAppUid); |
|
253 } |
|
254 ses.Close(); |
|
255 } |
|
256 } |
|
257 } |
|
258 |
|
259 |
|
260 CTransitionManager::~CTransitionManager() |
|
261 { |
|
262 delete iCRListen; |
|
263 if(iAppStartupIdle != NULL) |
|
264 { |
|
265 iAppStartupIdle->Cancel(); |
|
266 } |
|
267 delete iAppStartupIdle; |
|
268 } |
|
269 |
|
270 |
|
271 TBool CTransitionManager::AppStartupCb(TAny* aThis) |
|
272 { |
|
273 static_cast<CTransitionManager*>(aThis)->Startup(); |
|
274 return EFalse; |
|
275 } |
|
276 |
|
277 // Implementation of MCoeViewActivationObserver MCoeViewObserver |
|
278 void CTransitionManager::HandleViewEventL( const TVwsViewEvent& aEvent ) |
|
279 { |
|
280 switch( aEvent.iEventType ) |
|
281 { |
|
282 case TVwsViewEvent::EVwsActivateView: |
|
283 // Appswitch has triggered flag so start idle callback |
|
284 if( iStartIdleState == ETransEffectWaitingForViewSwitch) |
|
285 { |
|
286 if( !iAppStartupIdle->IsActive() ) |
|
287 { |
|
288 iStartIdleState = ETransEffectWaitingForIdleCall; |
|
289 iAppStartupIdle->Start( TCallBack( AppStartupCb, this ) ); |
|
290 } |
|
291 } |
|
292 else if( iStartIdleState == ETransEffectIdle && Ready() ) |
|
293 // Wait for appswitch |
|
294 { |
|
295 iStartIdleState = ETransEffectWaitingForAppSwitch; |
|
296 } |
|
297 break; |
|
298 case TVwsViewEvent::EVwsDeactivateView: |
|
299 // Appswitch has triggered flag so start idle callback |
|
300 if( iStartIdleState == ETransEffectWaitingForViewSwitch) |
|
301 { |
|
302 if( !iAppStartupIdle->IsActive() ) |
|
303 { |
|
304 iStartIdleState = ETransEffectWaitingForIdleCall; |
|
305 iAppStartupIdle->Start( TCallBack( AppStartupCb, this ) ); |
|
306 } |
|
307 } |
|
308 break; |
|
309 default: |
|
310 // Reset state if viewdeactivate to other app |
|
311 if( aEvent.iViewOneId.iAppUid != aEvent.iViewTwoId.iAppUid ) |
|
312 { |
|
313 iStartIdleState = ETransEffectIdle; |
|
314 } |
|
315 break; |
|
316 } |
|
317 } |
|
318 |
|
319 void CTransitionManager::SetEmbedded() |
|
320 { |
|
321 iFlags |= EEmbedded; |
|
322 } |
|
323 |
|
324 void CTransitionManager::Startup() |
|
325 { |
|
326 if(!(iFlags & EStartupComplete)) |
|
327 { |
|
328 const TInt group = iEikEnv.RootWin().Identifier(); |
|
329 if(group != 0) |
|
330 { |
|
331 TWsEvent event; |
|
332 event.SetType(EEventNull); |
|
333 event.SetTimeNow(); |
|
334 iEikEnv.WsSession().SendEventToWindowGroup(group, event); |
|
335 } |
|
336 } |
|
337 if( ( iEikEnv.AppUi() != NULL ) && ( static_cast<CAknAppUi*>(iEikEnv.AppUi())->IsForeground() ) ) |
|
338 { |
|
339 iEikEnv.WsSession().Flush(); //ensure that all drawing commands will be in server |
|
340 GfxTransEffect::EndFullScreen(); |
|
341 } |
|
342 iFlags |= EStartupComplete; |
|
343 iStartIdleState = ETransEffectIdle; |
|
344 } |
|
345 |
|
346 |
|
347 TBool CTransitionManager::IsFullScreen() const |
|
348 { |
|
349 return (iEikEnv.AppUi() != NULL && static_cast<CAknAppUi*>(iEikEnv.AppUi())->IsFullScreenApp()); |
|
350 } |
|
351 |
|
352 void CTransitionManager::AppSwitch(TInt aContext/*, const TUid& aUid*/) |
|
353 { |
|
354 // Set the parent again as it might be cleared by another embedded instance |
|
355 // (with the same uid) on exit |
|
356 if ( iFlags & EEmbedded ) |
|
357 { |
|
358 const TInt focusWGroupId = iEikEnv.WsSession().GetFocusWindowGroup(); |
|
359 const TInt thisApplicationWgId = iEikEnv.RootWin().Identifier(); |
|
360 if ( focusWGroupId == thisApplicationWgId ) |
|
361 { |
|
362 SendAvkonInfo(); |
|
363 } |
|
364 } |
|
365 |
|
366 if(Ready()) |
|
367 { |
|
368 iEikEnv.WsSession().Flush(); |
|
369 |
|
370 |
|
371 if(aContext == AknTransEffect::EApplicationActivate && (iFlags & EStartupStarted)) |
|
372 { |
|
373 // If this is a plain switch without a previous appstart then just wait for view activate |
|
374 if( iStartIdleState == ETransEffectIdle ) |
|
375 { |
|
376 iStartIdleState = ETransEffectWaitingForViewSwitch; |
|
377 } |
|
378 else if( iStartIdleState == ETransEffectWaitingForAppSwitch ) |
|
379 { |
|
380 if( !iAppStartupIdle->IsActive() ) |
|
381 { |
|
382 iStartIdleState = ETransEffectWaitingForIdleCall; |
|
383 iAppStartupIdle->Start( TCallBack( AppStartupCb, this ) ); |
|
384 } |
|
385 } |
|
386 } |
|
387 } |
|
388 } |
|
389 |
|
390 void CTransitionManager::AppStartup(TInt aContext, const TUid& aUid) |
|
391 { |
|
392 ASSERT(!(iFlags & EStarted)); |
|
393 ASSERT(aUid != KNullUid); |
|
394 |
|
395 iAppUid = aUid; |
|
396 |
|
397 //reset instance data e.g. emedded and fullscreen as those params |
|
398 //may vary per instance |
|
399 TInt flags = AknTransEffect::TParameter::EResetServerStats; |
|
400 |
|
401 if(Ready()) |
|
402 { |
|
403 |
|
404 if( aContext == AknTransEffect::EAppStartupBackground ) |
|
405 { |
|
406 flags |= AknTransEffect::TParameter::ENoEffects; |
|
407 GfxTransEffect::BeginFullScreen(aContext, TRect(0,0,0,0), |
|
408 AknTransEffect::EParameterAvkonInternal, AknTransEffect::GfxTransParam(aUid, flags)); |
|
409 } |
|
410 else |
|
411 { |
|
412 GfxTransEffect::BeginFullScreen(aContext, TRect(0,0,0,0), |
|
413 AknTransEffect::EParameterType, AknTransEffect::GfxTransParam(aUid, flags)); |
|
414 } |
|
415 |
|
416 iFlags |= EStarted; |
|
417 } |
|
418 } |
|
419 |
|
420 |
|
421 void CTransitionManager::KeyChangedL(const MKeyValue& aValue) |
|
422 { |
|
423 ASSERT(aValue.Key() == KThemesTransitionEffects); |
|
424 aValue.Key(); // just for fixing warning |
|
425 ASSERT(!(iFlags & EffectsEnabled)); |
|
426 CheckEffectsL(ETrue); |
|
427 |
|
428 SendAvkonInfo(); |
|
429 CheckFlags(); |
|
430 } |
|
431 |
|
432 void CTransitionManager::CheckEffectsL(TBool aWait) |
|
433 { |
|
434 if(!(iFlags & EffectsEnabled)) |
|
435 { |
|
436 if(iCRListen->Value() & AknTransEffect::EFullScreenTransitionsOff) |
|
437 { |
|
438 iFlags &= ~EffectsEnabled; |
|
439 iCRListen->Listen(); |
|
440 } |
|
441 else if(!aWait || CServerWait::WaitL()) |
|
442 { |
|
443 iFlags |= EffectsEnabled; |
|
444 } |
|
445 } |
|
446 } |
|
447 |
|
448 |
|
449 void CTransitionManager::SetAvkon() |
|
450 { |
|
451 if(iAppUid != KNullUid && !(iFlags & EAvkonApp)) |
|
452 { |
|
453 iFlags |= EAvkonApp; |
|
454 SendAvkonInfo(); |
|
455 } |
|
456 } |
|
457 |
|
458 void CTransitionManager::GetRootAppL(TUid& aRootAppUid) |
|
459 { |
|
460 RWsSession& ws = iEikEnv.WsSession(); |
|
461 RWsSession::TWindowGroupChainInfo wgInfo = {0,0}; |
|
462 wgInfo.iId = iEikEnv.RootWin().Identifier(); |
|
463 TInt foundWgId = wgInfo.iId; |
|
464 |
|
465 RArray<RWsSession::TWindowGroupChainInfo> wgInfoArray; |
|
466 ws.WindowGroupList(&wgInfoArray); |
|
467 TInt index = wgInfoArray.Find(wgInfo); |
|
468 |
|
469 // Find the root window group |
|
470 while( index >= 0 ) |
|
471 { |
|
472 foundWgId = wgInfo.iId; |
|
473 wgInfo.iId = wgInfoArray[index].iParentId; |
|
474 index = wgInfoArray.Find(wgInfo); |
|
475 } |
|
476 wgInfoArray.Close(); |
|
477 |
|
478 CApaWindowGroupName* windowName = CApaWindowGroupName::NewLC(ws, foundWgId); |
|
479 aRootAppUid = windowName->AppUid(); |
|
480 CleanupStack::PopAndDestroy(); //windowName |
|
481 } |
|
482 |
|
483 void CTransitionManager::SendAvkonInfo() |
|
484 { |
|
485 if((iFlags & EffectsEnabled) && (iAppUid != KNullUid) && (iFlags & EAvkonApp)) |
|
486 { |
|
487 #ifdef TFX_USE_WCHANGE_EVENT |
|
488 TUid parentUid = KNullUid; |
|
489 |
|
490 if(iFlags & EEmbedded) |
|
491 { //set this app parent if emdded, thus server can go parent chain |
|
492 //and not to do switch effects between chain apps |
|
493 TRAP_IGNORE(GetRootAppL(parentUid)); |
|
494 } |
|
495 |
|
496 const TUint data[3] = {iAppUid.iUid, parentUid.iUid, iEikEnv.RootWin().Identifier()}; |
|
497 |
|
498 const TPckgC<TUint[3]> buffer(data); |
|
499 |
|
500 GfxTransEffect::BeginFullScreen(AknTransEffect::ENone, |
|
501 TRect(0,0,0,0), |
|
502 AknTransEffect::EParameterAvkonInternal, |
|
503 buffer); |
|
504 |
|
505 #else |
|
506 TInt flags = AknTransEffect::TParameter::EAvkonCheck; |
|
507 |
|
508 TUid parentUid = KNullUid; |
|
509 |
|
510 if(iFlags & EEmbedded) |
|
511 { //set this app parent if emdded, thus server can go parent chain |
|
512 //and not to do switch effects between chain apps |
|
513 flags |= AknTransEffect::TParameter::EParentUid; |
|
514 TRAP_IGNORE(GetRootAppL(parentUid)); |
|
515 } |
|
516 |
|
517 GfxTransEffect::BeginFullScreen(AknTransEffect::ENone, |
|
518 TRect(0,0,0,0), |
|
519 AknTransEffect::EParameterType, |
|
520 AknTransEffect::GfxTransParam(iAppUid, parentUid, flags)); |
|
521 #endif |
|
522 |
|
523 } |
|
524 } |
|
525 |
|
526 |
|
527 void CTransitionManager::SetDisableEffects(TBool aDisable) |
|
528 { |
|
529 if(iAppUid == KNullUid) |
|
530 return; |
|
531 const TInt flags = aDisable ? |
|
532 AknTransEffect::TParameter::ENoEffects : |
|
533 AknTransEffect::TParameter::EEnableEffects ; |
|
534 GfxTransEffect::BeginFullScreen(AknTransEffect::ENone, //not important |
|
535 TRect(0,0,0,0), |
|
536 AknTransEffect::EParameterType, |
|
537 AknTransEffect::GfxTransParam(iAppUid, flags)); |
|
538 } |
|
539 |
|
540 void CTransitionManager::CheckFlags() |
|
541 { |
|
542 if((iFlags & EffectsEnabled) && //some one hearing us |
|
543 ( !IsFullScreen())) //they were disabled (flag not equal with state) or not fullscreen |
|
544 { |
|
545 SetDisableEffects(ETrue); |
|
546 } |
|
547 } |
|
548 |
|
549 void CTransitionManager::AppExit(TInt /*aContext*/, const TUid& aUid) |
|
550 { |
|
551 if(aUid != KNullUid && Ready()) |
|
552 { |
|
553 const TInt flags = AknTransEffect::TParameter::EAvkonCheck;//EAvkonExit; |
|
554 const TInt context = |
|
555 (iFlags & EEmbedded) //if embedded |
|
556 ? |
|
557 AknTransEffect::EEmbeddedApplicationExit // just for no effect |
|
558 : AknTransEffect::EApplicationExit; // do a exit effect |
|
559 |
|
560 GfxTransEffect::BeginFullScreen(context, TRect(0,0,0,0), |
|
561 AknTransEffect::EParameterType, AknTransEffect::GfxTransParam(aUid, flags)); |
|
562 |
|
563 } |
|
564 iFlags |= EExitCompleted; |
|
565 } |
|
566 |
|
567 void CTransitionManager::CancelExit() |
|
568 { |
|
569 if(iFlags & EExitCompleted) |
|
570 { |
|
571 GfxTransEffect::AbortFullScreen(); |
|
572 iFlags &= ~EExitCompleted; |
|
573 } |
|
574 } |
|
575 |
|
576 TBool CTransitionManager::Ready() |
|
577 { |
|
578 if(iFlags & EExitCompleted) |
|
579 return EFalse; |
|
580 if(!(iFlags & EffectsEnabled)) |
|
581 return EFalse; |
|
582 if(!(iFlags & EEnviromentReady)) |
|
583 { |
|
584 TBool allowed; |
|
585 if(KErrNone == RProperty::Get(KPSUidUikon, KUikGlobalNotesAllowed, allowed) && allowed) |
|
586 { |
|
587 iFlags |= EEnviromentReady; |
|
588 } |
|
589 } |
|
590 return (iFlags & EEnviromentReady) != 0; |
|
591 } |
|
592 |