|
1 /* |
|
2 * Copyright (c) 2007 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 #include <e32svr.h> |
|
20 #include <e32uid.h> |
|
21 #include <coemain.h> // CCoeEnv |
|
22 #include <apgtask.h> // TApaTaskList and friends |
|
23 #include <centralrepository.h> |
|
24 #include <AvkonInternalCRKeys.h> |
|
25 #include <pslninternalcrkeys.h> |
|
26 #include <AknCapServerDefs.h> |
|
27 #include <AknNotifierWrapperDefs.h> |
|
28 |
|
29 #include "akncompasrv.h" |
|
30 #include "akncompaserver.h" |
|
31 |
|
32 // Flags for KAknCompaModeEffects |
|
33 const TInt KAknCompaModeEffectsSaved = (1 << 31); |
|
34 const TInt KAknCompaModeEffectsDisabled = 0x7fffffff; |
|
35 |
|
36 // -------------------------------------------------------------------------- |
|
37 // |
|
38 // -------------------------------------------------------------------------- |
|
39 CAknCompaSrvWsEventHandler::CAknCompaSrvWsEventHandler(RWsSession& aWsSession) |
|
40 : CActive(CActive::EPriorityStandard), iWsSession(aWsSession) |
|
41 { |
|
42 CActiveScheduler::Add(this); |
|
43 IssueRequest(); |
|
44 } |
|
45 |
|
46 // -------------------------------------------------------------------------- |
|
47 // |
|
48 // -------------------------------------------------------------------------- |
|
49 CAknCompaSrvWsEventHandler::~CAknCompaSrvWsEventHandler() |
|
50 { |
|
51 Cancel(); |
|
52 } |
|
53 |
|
54 // -------------------------------------------------------------------------- |
|
55 // Issue request to read from wsrv event queue |
|
56 // -------------------------------------------------------------------------- |
|
57 void CAknCompaSrvWsEventHandler::IssueRequest() |
|
58 { |
|
59 iWsSession.EventReady(&iStatus); |
|
60 SetActive(); |
|
61 } |
|
62 |
|
63 // -------------------------------------------------------------------------- |
|
64 // Event ready in window server event queue |
|
65 // -------------------------------------------------------------------------- |
|
66 void CAknCompaSrvWsEventHandler::RunL() |
|
67 { |
|
68 // Window server event queue read to purge it in case wsrv sends |
|
69 // something. As we dont have window group created this is probably |
|
70 // unneccesary as there seem to be no events. |
|
71 TWsEvent wsEvent; |
|
72 iWsSession.GetEvent(wsEvent); |
|
73 IssueRequest(); |
|
74 } |
|
75 |
|
76 // -------------------------------------------------------------------------- |
|
77 // |
|
78 // -------------------------------------------------------------------------- |
|
79 void CAknCompaSrvWsEventHandler::DoCancel() |
|
80 { |
|
81 iWsSession.EventReadyCancel(); |
|
82 } |
|
83 |
|
84 // -------------------------------------------------------------------------- |
|
85 // |
|
86 // -------------------------------------------------------------------------- |
|
87 CAknCompaServer::CAknCompaServer() |
|
88 :CServer2(CActive::EPriorityStandard) |
|
89 { |
|
90 } |
|
91 |
|
92 // -------------------------------------------------------------------------- |
|
93 // |
|
94 // -------------------------------------------------------------------------- |
|
95 CAknCompaServer::~CAknCompaServer() |
|
96 { |
|
97 delete iThemesCenRep; |
|
98 delete iAvkonCenRep; |
|
99 |
|
100 delete iWsEventHandler; |
|
101 iWsSession.Close(); |
|
102 } |
|
103 |
|
104 // -------------------------------------------------------------------------- |
|
105 // |
|
106 // -------------------------------------------------------------------------- |
|
107 CServer2* CAknCompaServer::NewLC() |
|
108 { |
|
109 CAknCompaServer* self = new (ELeave) CAknCompaServer; |
|
110 CleanupStack::PushL(self); |
|
111 self->ConstructL(); |
|
112 return self; |
|
113 } |
|
114 |
|
115 // -------------------------------------------------------------------------- |
|
116 // |
|
117 // -------------------------------------------------------------------------- |
|
118 void CAknCompaServer::ConstructL() |
|
119 { |
|
120 User::LeaveIfError(iWsSession.Connect()); |
|
121 iThemesCenRep = CRepository::NewL(KCRUidThemes); |
|
122 iAvkonCenRep = CRepository::NewL(KCRUidAvkon); |
|
123 |
|
124 // Check if compa-mode has disabled effects in repository |
|
125 TInt savedEffects = KAknCompaModeEffectsDisabled; |
|
126 iAvkonCenRep->Get(KAknCompaModeEffects, savedEffects); |
|
127 iEffectsDisabled = (savedEffects & KAknCompaModeEffectsSaved) != 0; |
|
128 |
|
129 iWsEventHandler = new (ELeave) CAknCompaSrvWsEventHandler(iWsSession); |
|
130 StartL(KAknCompaSrvName); |
|
131 } |
|
132 |
|
133 // -------------------------------------------------------------------------- |
|
134 // New session added to server |
|
135 // -------------------------------------------------------------------------- |
|
136 void CAknCompaServer::AddSession() |
|
137 { |
|
138 iSessionCount++; |
|
139 } |
|
140 |
|
141 |
|
142 // -------------------------------------------------------------------------- |
|
143 // Session is closing |
|
144 // -------------------------------------------------------------------------- |
|
145 void CAknCompaServer::DropSession() |
|
146 { |
|
147 if (--iSessionCount == 0) |
|
148 { |
|
149 // Stops the active scheduler. As this server runs in its |
|
150 // own process this stop effectively kills the process |
|
151 CActiveScheduler::Stop(); |
|
152 } |
|
153 } |
|
154 |
|
155 // -------------------------------------------------------------------------- |
|
156 // Get window server session |
|
157 // -------------------------------------------------------------------------- |
|
158 RWsSession& CAknCompaServer::WsSession() |
|
159 { |
|
160 return iWsSession; |
|
161 } |
|
162 |
|
163 // -------------------------------------------------------------------------- |
|
164 // Create a new session |
|
165 // -------------------------------------------------------------------------- |
|
166 CSession2* CAknCompaServer::NewSessionL(const TVersion& aVersion, |
|
167 const RMessage2& /*aMessage*/) const |
|
168 { |
|
169 // Check that the version is OK |
|
170 TVersion v(KAknCompaSrvMajorVersionNumber, |
|
171 KAknCompaSrvMinorVersionNumber, KAknCompaSrvBuildVersionNumber); |
|
172 if (!User::QueryVersionSupported(v,aVersion)) |
|
173 { |
|
174 User::Leave(KErrNotSupported); |
|
175 } |
|
176 |
|
177 return new (ELeave) CAknCompaSrvSession; |
|
178 } |
|
179 |
|
180 // -------------------------------------------------------------------------- |
|
181 // Panic server |
|
182 // -------------------------------------------------------------------------- |
|
183 void CAknCompaServer::PanicServer(TAknCompaServerPanic aPanic) |
|
184 { |
|
185 User::Panic(KAknCompaSrvName, aPanic); |
|
186 } |
|
187 |
|
188 // -------------------------------------------------------------------------- |
|
189 // Panic client |
|
190 // -------------------------------------------------------------------------- |
|
191 void CAknCompaServer::PanicClient(const RMessage2& aMessage, |
|
192 TInt aPanic) |
|
193 { |
|
194 aMessage.Panic(KAknCompaSrvName, aPanic); |
|
195 } |
|
196 |
|
197 // -------------------------------------------------------------------------- |
|
198 // Check if process is a server that displays global |
|
199 // notes/notifications (Eikon server, Avkon notify and cap servers) |
|
200 // -------------------------------------------------------------------------- |
|
201 TBool CAknCompaServer::IsGlobalUiSrv(const RMessage2& aMessage) |
|
202 { |
|
203 const TUint32 KEikSrvUid = 0x10003a4a; |
|
204 return aMessage.SecureId().iId == KAknCapServerUid.iUid || |
|
205 aMessage.SecureId().iId == KCommonNotifierAppSrvUid.iUid || |
|
206 aMessage.SecureId().iId == KEikSrvUid; |
|
207 } |
|
208 |
|
209 // -------------------------------------------------------------------------- |
|
210 // Set thread priority to normal |
|
211 // -------------------------------------------------------------------------- |
|
212 void CAknCompaServer::SetThreadPriorityNormal(TAny* /*aUnused*/) |
|
213 { |
|
214 RThread thread; |
|
215 thread.SetPriority(EPriorityNormal); |
|
216 } |
|
217 |
|
218 // -------------------------------------------------------------------------- |
|
219 // Set thread priority higher than any non-signed application threads |
|
220 // -------------------------------------------------------------------------- |
|
221 void CAknCompaServer::SetThreadPriorityHigh() |
|
222 { |
|
223 RThread thread; |
|
224 thread.SetPriority(EPriorityAbsoluteRealTime1); |
|
225 } |
|
226 |
|
227 // -------------------------------------------------------------------------- |
|
228 // Disable transition effects |
|
229 // -------------------------------------------------------------------------- |
|
230 void CAknCompaServer::DisaTransEffectsL(const RMessage2& aMessage) |
|
231 { |
|
232 if (!iEffectsDisabled) |
|
233 { |
|
234 // Allow effects control only from global ui servers |
|
235 if (!IsGlobalUiSrv(aMessage)) |
|
236 { |
|
237 User::Leave(KErrPermissionDenied); |
|
238 } |
|
239 iEffectsDisabled = ETrue; |
|
240 // The only way to disable transition effects is through CenRep. The |
|
241 // same variable is also controlled by "Control Panel". If the device |
|
242 // is turned off while we have disabled effects, we need to enable |
|
243 // them when device is restarted. |
|
244 TInt savedEffects = KAknCompaModeEffectsDisabled; |
|
245 iAvkonCenRep->Get(KAknCompaModeEffects, savedEffects); |
|
246 |
|
247 if ((savedEffects & KAknCompaModeEffectsSaved) == 0) |
|
248 { |
|
249 TInt effects = 0; |
|
250 iThemesCenRep->Get(KThemesTransitionEffects, effects); |
|
251 if (effects != KAknCompaModeEffectsDisabled) |
|
252 { |
|
253 iAvkonCenRep->Set(KAknCompaModeEffects, |
|
254 effects | KAknCompaModeEffectsSaved); |
|
255 iThemesCenRep->Set(KThemesTransitionEffects, |
|
256 KAknCompaModeEffectsDisabled); |
|
257 } |
|
258 } |
|
259 } |
|
260 } |
|
261 |
|
262 // -------------------------------------------------------------------------- |
|
263 // Restore transition effects to a state before they were disabled |
|
264 // -------------------------------------------------------------------------- |
|
265 void CAknCompaServer::RestoreTransEffectsL(const RMessage2& aMessage) |
|
266 { |
|
267 if (iEffectsDisabled) |
|
268 { |
|
269 // Allow effects control only from global ui servers |
|
270 if (!IsGlobalUiSrv(aMessage)) |
|
271 { |
|
272 User::Leave(KErrPermissionDenied); |
|
273 } |
|
274 iEffectsDisabled = EFalse; |
|
275 |
|
276 // Read saved effects state from our CenRep |
|
277 TInt savedEffects = 0; |
|
278 iAvkonCenRep->Get(KAknCompaModeEffects, savedEffects); |
|
279 |
|
280 if (savedEffects & KAknCompaModeEffectsSaved) |
|
281 { |
|
282 savedEffects &= ~KAknCompaModeEffectsSaved; |
|
283 iThemesCenRep->Set(KThemesTransitionEffects, savedEffects); |
|
284 iAvkonCenRep->Set(KAknCompaModeEffects, savedEffects); |
|
285 } |
|
286 } |
|
287 } |
|
288 |
|
289 // -------------------------------------------------------------------------- |
|
290 // |
|
291 // -------------------------------------------------------------------------- |
|
292 CAknCompaServer& CAknCompaSrvSession::Server() |
|
293 { |
|
294 return *static_cast<CAknCompaServer*> |
|
295 (const_cast<CServer2*>(CSession2::Server())); |
|
296 } |
|
297 |
|
298 // -------------------------------------------------------------------------- |
|
299 // Create session |
|
300 // -------------------------------------------------------------------------- |
|
301 void CAknCompaSrvSession::CreateL() |
|
302 { |
|
303 // Allocate memory for keystate array to hold all possible keys. |
|
304 // This avoid possibility of memory allocation error when key is |
|
305 // added to key state array due to key press while application is |
|
306 // executing. |
|
307 iKeyState.Reserve(EKeyStateGranularity); |
|
308 |
|
309 Server().AddSession(); |
|
310 } |
|
311 |
|
312 // -------------------------------------------------------------------------- |
|
313 // |
|
314 // -------------------------------------------------------------------------- |
|
315 CAknCompaSrvSession::CAknCompaSrvSession(): |
|
316 iKeyState(EKeyStateGranularity) |
|
317 { |
|
318 // We allow only rocker keys, softkeys and numeric keypad keys to be |
|
319 // simulated. |
|
320 static const TUint8 ValidScanCodes[] = |
|
321 { |
|
322 EStdKeyDevice0, EStdKeyUpArrow, EStdKeyDevice1, EStdKeyLeftArrow, |
|
323 EStdKeyDevice3, EStdKeyRightArrow, EStdKeyRightShift, |
|
324 EStdKeyDownArrow, EStdKeyBackspace, EStdKeyNkpAsterisk, EStdKeyHash, |
|
325 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 |
|
326 }; |
|
327 iValidScanCodes.Set(ValidScanCodes, sizeof(ValidScanCodes)); |
|
328 } |
|
329 |
|
330 // -------------------------------------------------------------------------- |
|
331 // |
|
332 // -------------------------------------------------------------------------- |
|
333 CAknCompaSrvSession::~CAknCompaSrvSession() |
|
334 { |
|
335 TInt num = iKeyState.Count(); |
|
336 |
|
337 // When session closes, send key up events for all keys being in down |
|
338 // state. This ensures even if application crashes that no keys are left |
|
339 // down. |
|
340 for( TInt i=0; i < num; i++) |
|
341 { |
|
342 SimulateKeyEvent(iKeyState[i], EFalse); |
|
343 } |
|
344 Server().DropSession(); |
|
345 iKeyState.Close(); |
|
346 } |
|
347 |
|
348 |
|
349 // -------------------------------------------------------------------------- |
|
350 // |
|
351 // -------------------------------------------------------------------------- |
|
352 void CAknCompaSrvSession::ServiceL(const RMessage2& aMessage) |
|
353 { |
|
354 TRAPD(err, DispatchMessageL(aMessage)); |
|
355 aMessage.Complete(err); |
|
356 } |
|
357 |
|
358 // -------------------------------------------------------------------------- |
|
359 // |
|
360 // -------------------------------------------------------------------------- |
|
361 void CAknCompaSrvSession::DispatchMessageL(const RMessage2& aMessage) |
|
362 { |
|
363 switch(aMessage.Function()) |
|
364 { |
|
365 case ECompaSrvSimulateKeyEvent: |
|
366 SimulateKeyEventServiceL(aMessage); |
|
367 break; |
|
368 case ECompaSrvDisaTransEffects: |
|
369 Server().DisaTransEffectsL(aMessage); |
|
370 break; |
|
371 case ECompaSrvRestoreTransEffects: |
|
372 Server().RestoreTransEffectsL(aMessage); |
|
373 break; |
|
374 // Requests that we don't understand at all are a different matter. |
|
375 // This is considered a client programming error, so we panic the |
|
376 // client - this also completes the message. |
|
377 default: |
|
378 CAknCompaServer::PanicClient(aMessage, EBadRequest); |
|
379 } |
|
380 } |
|
381 |
|
382 // -------------------------------------------------------------------------- |
|
383 // Simulate key event for client application |
|
384 // -------------------------------------------------------------------------- |
|
385 void CAknCompaSrvSession::SimulateKeyEventServiceL(const RMessage2& aMessage) |
|
386 { |
|
387 TInt scancode = aMessage.Int0(); |
|
388 TBool keyDown = aMessage.Int1(); |
|
389 |
|
390 // Check that scan code is valid. Client request will fail with error |
|
391 // code KErrNotFound if the check fails. |
|
392 TChar ch(scancode); |
|
393 User::LeaveIfError(iValidScanCodes.Locate(ch)); |
|
394 |
|
395 if (keyDown) |
|
396 { |
|
397 // Set thread priority to very high. The purpose is to prevent |
|
398 // other threads to change foreground application in between |
|
399 // client foreground status check and SimulateRawEvent(). |
|
400 CAknCompaServer::SetThreadPriorityHigh(); |
|
401 CleanupStack::PushL( |
|
402 TCleanupItem(CAknCompaServer::SetThreadPriorityNormal, NULL)); |
|
403 // Check that client task is foreground |
|
404 CheckKeyDownPermissionL(aMessage); |
|
405 } |
|
406 |
|
407 // Keeps tracks which scancodes are in down state |
|
408 if (keyDown) |
|
409 { |
|
410 // There can be only one of each scancode in the list |
|
411 if (iKeyState.Find(scancode) == KErrNotFound) |
|
412 { |
|
413 iKeyState.AppendL(scancode); |
|
414 SimulateKeyEvent(scancode, keyDown); |
|
415 } |
|
416 CleanupStack::PopAndDestroy(); |
|
417 } |
|
418 else |
|
419 { |
|
420 TInt pos = iKeyState.Find(scancode); |
|
421 if (pos != KErrNotFound) |
|
422 { |
|
423 iKeyState.Remove(pos); |
|
424 iKeyState.GranularCompress(); |
|
425 SimulateKeyEvent(scancode, keyDown); |
|
426 } |
|
427 } |
|
428 } |
|
429 |
|
430 // -------------------------------------------------------------------------- |
|
431 // Simulate key event to window server |
|
432 // -------------------------------------------------------------------------- |
|
433 void CAknCompaSrvSession::SimulateKeyEvent(TInt aScancode, TBool aKeyDown) |
|
434 { |
|
435 TRawEvent event; |
|
436 event.Set( |
|
437 aKeyDown ? TRawEvent::EKeyDown : TRawEvent::EKeyUp, |
|
438 aScancode); |
|
439 |
|
440 RWsSession& wsSession = Server().WsSession(); |
|
441 // Simulate key event as it came from a keypad |
|
442 wsSession.SimulateRawEvent(event); |
|
443 wsSession.Flush(); |
|
444 } |
|
445 |
|
446 // -------------------------------------------------------------------------- |
|
447 // Check whether client key event request can be executed |
|
448 // -------------------------------------------------------------------------- |
|
449 void CAknCompaSrvSession::CheckKeyDownPermissionL(const RMessage2& aMessage) |
|
450 { |
|
451 // We try to increase security by allowing only foreground application |
|
452 // to set key down. As the simulated key events are sent to the |
|
453 // foreground application by window server, the application is |
|
454 // sending a key event to itself. |
|
455 |
|
456 // Granted if client has ECapabilitySwEvent or request is coming from |
|
457 // EikSrv. TApaTaskList won't report EikSrv in foreground though |
|
458 // it's displaying a note. |
|
459 if (!aMessage.HasCapability(ECapabilitySwEvent) && |
|
460 !CAknCompaServer::IsGlobalUiSrv(aMessage)) |
|
461 { |
|
462 // Allow key down only from a foreground task |
|
463 TApaTaskList tasklist(Server().WsSession()); |
|
464 TApaTask foregroundTask = tasklist.FindByPos(0); |
|
465 |
|
466 RThread thread; |
|
467 User::LeaveIfError(thread.Open(foregroundTask.ThreadId())); |
|
468 TSecurityPolicy securityPolicy(thread.SecureId()); |
|
469 thread.Close(); |
|
470 |
|
471 if (!securityPolicy.CheckPolicy(aMessage)) |
|
472 { |
|
473 User::Leave(KErrPermissionDenied); |
|
474 } |
|
475 } |
|
476 } |