|
1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: Implementation of the class representing the Alarm Queue |
|
14 // |
|
15 |
|
16 #include <e32property.h> |
|
17 #include "ASSrvAlarmQueue.h" |
|
18 |
|
19 |
|
20 // User Includes |
|
21 #include "ASSrvTimer.h" |
|
22 #include "ASSrvStaticUtils.h" |
|
23 #include "ASSrvServerWideData.h" |
|
24 #include "ASSrvAnyEventManager.h" |
|
25 #include "ASSrvIteratorByState.h" |
|
26 #include "ASSrvIteratorByStatus.h" |
|
27 #ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS |
|
28 #include "ASSrvIteratorByCategory.h" |
|
29 #endif |
|
30 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT |
|
31 #include "ASSrvIteratorByWakeup.h" |
|
32 #endif |
|
33 #include "ASSrvEnvironmentChangeManager.h" |
|
34 #include "ASSrvSoundSettings.h" |
|
35 #include "ASSrvDataPool.h" |
|
36 #include "ASSrvDSTChange.h" |
|
37 |
|
38 |
|
39 // Constants |
|
40 const TInt KASSrvNumberOfDaysInOneWeek = 7; |
|
41 |
|
42 // Macro for security policy objects |
|
43 static _LIT_SECURITY_POLICY_PASS(KReadPolicy); |
|
44 static _LIT_SECURITY_POLICY_S0(KWritePolicy, 0x101f5027); |
|
45 |
|
46 // Enumerations |
|
47 #define DEBUG_PRINT_QUEUE(a){ RDebug::Print(_L(a)); \ |
|
48 for(TInt i=0; i<iAlarms.Count(); i++) \ |
|
49 { \ |
|
50 const TASSrvAlarm& alarm = QueueAlarmAt(i); \ |
|
51 RDebug::Print(_L("ALARMSERVER\t Alarm[%02d] \"%S\" (%d)"), i, &alarm.Message(), alarm.Id()); \ |
|
52 } \ |
|
53 RDebug::Print(_L("\n")); \ |
|
54 } |
|
55 |
|
56 // Uncomment the following define macro for getting logs in verbose mode |
|
57 // #define VERBOSE_DEBUG |
|
58 |
|
59 #if defined(VERBOSE_DEBUG) |
|
60 #define DEBUG_PRINT1(A) RDebug::Print(A) |
|
61 #define DEBUG_PRINT2(A,B) RDebug::Print(A,B) |
|
62 #else |
|
63 #define DEBUG_PRINT1(A) |
|
64 #define DEBUG_PRINT2(A,B) |
|
65 #endif |
|
66 |
|
67 |
|
68 CASSrvAlarmQueue::CASSrvAlarmQueue(CASSrvServerWideData& aServerWideData) |
|
69 :iServerWideData(aServerWideData) |
|
70 { |
|
71 } |
|
72 |
|
73 CASSrvAlarmQueue::~CASSrvAlarmQueue() |
|
74 { |
|
75 ServerData().EnvironmentChangeManager().RequestEnvironmentChangesCancel(*this); |
|
76 iAlarmObservers.Close(); |
|
77 iAlarms.ResetAndDestroy(); |
|
78 iAlarms.Close(); |
|
79 if (iInternalizeAlarmQueue.Count() != 0) |
|
80 { |
|
81 iInternalizeAlarmQueue.ResetAndDestroy(); |
|
82 } |
|
83 iInternalizeAlarmQueue.Close(); |
|
84 iNotificationList.Close(); |
|
85 delete iASSrvDSTChange; |
|
86 |
|
87 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT |
|
88 iSsmRtcAdaptation.Close(); |
|
89 #endif |
|
90 } |
|
91 |
|
92 void CASSrvAlarmQueue::ConstructL() |
|
93 { |
|
94 ServerData().EnvironmentChangeManager().RequestEnvironmentChangesL(*this); |
|
95 iPreviousUtcOffset = User::UTCOffset(); |
|
96 iASSrvDSTChange = CASSrvDSTChange::NewL(*this); |
|
97 |
|
98 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT |
|
99 iSsmRtcAdaptation.Connect(); |
|
100 // Notify the listeners of 'KWakeupAlarmPubSubKey' key that the alarm queue is yet to be internalized |
|
101 // by Alarm Server on its start-up at the device boot time. |
|
102 RProperty::Define(KAlarmServerPubSubCategory, KWakeupAlarmPubSubKey, RProperty::EInt, KReadPolicy, KWritePolicy); |
|
103 RProperty::Set( KAlarmServerPubSubCategory, KWakeupAlarmPubSubKey, EActiveWakeupAlarmUninitialized ); |
|
104 DEBUG_PRINT1(_L("Set the KWakeupAlarmPubSubKey to EActiveWakeupAlarmUninitialized (startup)")); |
|
105 #endif |
|
106 } |
|
107 |
|
108 CASSrvAlarmQueue* CASSrvAlarmQueue::NewL(CASSrvServerWideData& aServerWideData) |
|
109 { |
|
110 CASSrvAlarmQueue* self = new(ELeave) CASSrvAlarmQueue(aServerWideData); |
|
111 CleanupStack::PushL(self); |
|
112 self->ConstructL(); |
|
113 CleanupStack::Pop(self); |
|
114 return self; |
|
115 } |
|
116 |
|
117 /** |
|
118 * @see MASSrvEnvironmentChangeObserver |
|
119 */ |
|
120 void CASSrvAlarmQueue::MEnvChangeHandleEvent(TInt aChanges, TUint aWorkdays, TBool aWorkdaysChanged) |
|
121 { |
|
122 // Locale changes can be triggered by a lot of reasons, process locale |
|
123 // changes only due to utc offset change and workdays change. |
|
124 if ( (aChanges & EChangesSystemTime) || aWorkdaysChanged || (aChanges & EChangesLocale && (iPreviousUtcOffset != User::UTCOffset())) ) |
|
125 { |
|
126 #ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS |
|
127 TBool possibleHiddenFloatingAlarm(EFalse); |
|
128 // Store the time of the first calendar alarm, as it may have been skipped |
|
129 TTime firstSkippedAlarmLocalTime(0); |
|
130 |
|
131 const TAlarmId headCalendarAlarmId = HeadCalendarAlarmId(); |
|
132 if (headCalendarAlarmId != KNullAlarmId) |
|
133 { |
|
134 const TASSrvAlarm* headCalendarAlarm = QueueAlarmById(headCalendarAlarmId); |
|
135 firstSkippedAlarmLocalTime = headCalendarAlarm->NextDueTime(); |
|
136 |
|
137 // The calendar server adds a single alarm at a time. If this |
|
138 // alarm is fixed, a skipped alarm instances notification must be |
|
139 // sent, since the calendar server may have had other unqueued |
|
140 // alarms that were skipped. |
|
141 possibleHiddenFloatingAlarm = !headCalendarAlarm->IsFloating() && (headCalendarAlarm->NextDueTime() + iPreviousUtcOffset < ASSrvStaticUtils::LocalTimeNow()); |
|
142 } |
|
143 //Retrive the old local time before the time zone has been changed for the first skipped alarm. |
|
144 firstSkippedAlarmLocalTime = firstSkippedAlarmLocalTime + ServerData().CachedUtcOffset(); |
|
145 TBool skippedAgendaAlarm(EFalse); |
|
146 |
|
147 // Tell every alarm that the date/time has changed |
|
148 const TInt count = QueueAlarmCount(); |
|
149 |
|
150 TRAP_IGNORE( |
|
151 for (TInt i = count - 1; i >= 0; i--) |
|
152 { |
|
153 TASSrvAlarm& alarm = QueueAlarmAt(i); |
|
154 if (alarm.HandleDateTimeChangedL(aWorkdays, aWorkdaysChanged)) |
|
155 { |
|
156 skippedAgendaAlarm = ETrue; |
|
157 } |
|
158 } |
|
159 ) |
|
160 |
|
161 // If there was a skipped agenda alarm, publish the environment change and the details of the first |
|
162 // skipped alarm, otherwise, if there was a UTC offset change, only publish the environment change |
|
163 if (skippedAgendaAlarm) |
|
164 { |
|
165 PublishSkippedAlarm(ETrue); |
|
166 PublishAlarmedInstanceParams(firstSkippedAlarmLocalTime, aChanges & EChangesSystemTime); |
|
167 } |
|
168 else if (possibleHiddenFloatingAlarm) |
|
169 { |
|
170 PublishAlarmedInstanceParams(firstSkippedAlarmLocalTime, aChanges & EChangesSystemTime); |
|
171 } |
|
172 else if (iPreviousUtcOffset != User::UTCOffset()) |
|
173 { |
|
174 PublishSkippedAlarm(EFalse); |
|
175 } |
|
176 #else |
|
177 // Tell every alarm that the date/time has changed |
|
178 const TInt count = QueueAlarmCount(); |
|
179 |
|
180 TBool skippedAgendaAlarm = EFalse; |
|
181 TRAP_IGNORE( |
|
182 for (TInt i = count - 1; i >= 0; i--) |
|
183 { |
|
184 TASSrvAlarm& alarm = QueueAlarmAt(i); |
|
185 if (alarm.HandleDateTimeChangedL(aWorkdays, aWorkdaysChanged)) |
|
186 { |
|
187 skippedAgendaAlarm = ETrue; |
|
188 } |
|
189 } |
|
190 ) |
|
191 if (skippedAgendaAlarm || iPreviousUtcOffset != User::UTCOffset()) |
|
192 { |
|
193 PublishSkippedAlarm(skippedAgendaAlarm); |
|
194 } |
|
195 #endif |
|
196 |
|
197 //Re sort the alarms after the above date/time change |
|
198 TLinearOrder<TASSrvAlarm> order(ASSrvStaticUtils::CompareAlarms); |
|
199 iAlarms.Sort(order); |
|
200 |
|
201 // Update floating alarms' due times. |
|
202 UpdateFloatingDueTimes(); |
|
203 |
|
204 // When the date/time/locale changes we always simulate a change in the head item so that the timer will reset itself. |
|
205 const TAlarmId newHeadItemId = HeadAlarmId(); |
|
206 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventHeadItemChanged, newHeadItemId); |
|
207 |
|
208 // Global any event notification |
|
209 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventSystemDateTimeChanged, KNullAlarmId); |
|
210 |
|
211 // Remove the dead alarms |
|
212 RemoveDeadAlarms(); |
|
213 |
|
214 // And update the UTC offset |
|
215 iPreviousUtcOffset = User::UTCOffset(); |
|
216 } |
|
217 |
|
218 if (aChanges & EChangesMidnightCrossover) |
|
219 { |
|
220 //Tidy up alarm queue every midnight |
|
221 RemoveDeadAlarms(); |
|
222 } |
|
223 } |
|
224 |
|
225 /** |
|
226 * Request notification when the state or status of an alarm changes |
|
227 */ |
|
228 void CASSrvAlarmQueue::RequestAlarmObservationEventsL(MASSrvAlarmObserver& aObserver) |
|
229 { |
|
230 User::LeaveIfError(iAlarmObservers.Append(TASSrvAlarmObserverMapplet(aObserver))); |
|
231 } |
|
232 |
|
233 /** |
|
234 * Cancel a previous notification request |
|
235 */ |
|
236 void CASSrvAlarmQueue::RequestAlarmObservationEventsCancel(MASSrvAlarmObserver& aObserver) |
|
237 { |
|
238 const TInt count = iAlarmObservers.Count(); |
|
239 for(TInt i=0; i<count; i++) |
|
240 { |
|
241 TASSrvAlarmObserverMapplet& mapplet = iAlarmObservers[i]; |
|
242 if (&mapplet.Observer() == &aObserver) |
|
243 { |
|
244 iAlarmObservers.Remove(i); |
|
245 return; |
|
246 } |
|
247 } |
|
248 } |
|
249 |
|
250 /** |
|
251 * Temporarily enabled or disable notifications |
|
252 */ |
|
253 void CASSrvAlarmQueue::RequestAlarmObservationEventsEnabled(MASSrvAlarmObserver& aObserver, TBool aEnabled) |
|
254 { |
|
255 const TInt count = iAlarmObservers.Count(); |
|
256 for(TInt i=0; i<count; i++) |
|
257 { |
|
258 TASSrvAlarmObserverMapplet& mapplet = iAlarmObservers[i]; |
|
259 if (&mapplet.Observer() == &aObserver) |
|
260 { |
|
261 mapplet.SetEnabled(aEnabled); |
|
262 return; |
|
263 } |
|
264 } |
|
265 ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicNoMatchingObserver); |
|
266 } |
|
267 |
|
268 /** |
|
269 * Adds the specified alarm to the alarm queue. Updates the alarm object |
|
270 * so that it contains a uniquely allocated id, suitable for clients to identify |
|
271 * this alarm amongst all others. |
|
272 */ |
|
273 void CASSrvAlarmQueue::QueueAlarmAndAllocateIdL(TASSrvAlarm& aAlarm, TAlarmId aSpecificAlarmId) |
|
274 { |
|
275 // Get the head id so that we know if the queue has changed |
|
276 const TAlarmId headItemId = HeadAlarmId(); |
|
277 |
|
278 // Now allocate an id for the alarm. Doesn't matter if adding |
|
279 // the alarm fails (and therefore we orphan an Id - they can |
|
280 // be reused, as long as no current alarm shares the same id as |
|
281 // another). |
|
282 const TAlarmId newId = aSpecificAlarmId == KNullAlarmId? NextFreeAlarmId() : aSpecificAlarmId; |
|
283 aAlarm.Id()=newId; |
|
284 |
|
285 // Add the alarm |
|
286 TASSrvAlarm* alarm = new(ELeave) TASSrvAlarm(ServerData()); |
|
287 CleanupStack::PushL(alarm); |
|
288 *alarm = aAlarm; |
|
289 // |
|
290 TLinearOrder<TASSrvAlarm> order(ASSrvStaticUtils::CompareAlarms); |
|
291 User::LeaveIfError(iAlarms.InsertInOrderAllowRepeats(alarm, order)); |
|
292 CleanupStack::Pop(alarm); |
|
293 |
|
294 // Change the state to queued |
|
295 TASSrvAlarm* newAlarm = QueueAlarmById(newId); |
|
296 newAlarm->SetState(EAlarmStateQueued); |
|
297 |
|
298 // Notify we've added an alarm |
|
299 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventAlarmAdded, newAlarm->Id()); |
|
300 |
|
301 // Did the head item change? |
|
302 const TAlarmId newHeadItemId = HeadAlarmId(); |
|
303 if (newHeadItemId != headItemId) |
|
304 { |
|
305 // Head item has changed. The timer will pick up the change and requeue itself |
|
306 // for the new alarm. |
|
307 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventHeadItemChanged, newHeadItemId); |
|
308 } |
|
309 |
|
310 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventAlarmAddition, newId); |
|
311 } |
|
312 |
|
313 /** |
|
314 * Releases a previously allocated alarm. Removes it from the queue, and if this |
|
315 * alarm was at the head of the queue, a new alarm is promoted. |
|
316 */ |
|
317 void CASSrvAlarmQueue::DeQueueAlarm(const TASSrvAlarm& aAlarm) |
|
318 { |
|
319 const TAlarmId id = aAlarm.Id(); |
|
320 const TBool isHeadItem = (id == HeadAlarmId()); |
|
321 |
|
322 // Find index from alarm |
|
323 TIdentityRelation<TASSrvAlarm> identityRelation(ASSrvStaticUtils::CompareAlarmsExact); |
|
324 const TInt errorOrIndex = iAlarms.Find(&aAlarm, identityRelation); |
|
325 __ASSERT_ALWAYS(errorOrIndex != KErrNotFound, ASSrvStaticUtils::Fault(ASSrvStaticUtils::EASSrvFaultAlarmNotFound)); |
|
326 |
|
327 // Inform alarm it's being destroyed |
|
328 TASSrvAlarm* alarm = &QueueAlarmAt(errorOrIndex); |
|
329 __ASSERT_ALWAYS(alarm->Id() == aAlarm.Id(), ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicAttemptingToDequeWrongAlarm)); |
|
330 alarm->HandleDeQueue(); |
|
331 |
|
332 // DEBUG_PRINT_QUEUE("ALARMSERVER Before removing item") |
|
333 |
|
334 // Remove from queue |
|
335 #ifdef _DEBUG |
|
336 const TInt count = QueueAlarmCount(); |
|
337 #endif |
|
338 iAlarms.Remove(errorOrIndex); |
|
339 delete alarm; |
|
340 __ASSERT_DEBUG(iAlarms.Count() == count-1, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicAlarmNotDeQueued)); |
|
341 |
|
342 // DEBUG_PRINT_QUEUE("ALARMSERVER After removing item") |
|
343 |
|
344 // Notify we've deleted an alarm |
|
345 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventAlarmDeleted, id); |
|
346 |
|
347 // DEBUG_PRINT_QUEUE("ALARMSERVER After notifying event") |
|
348 |
|
349 // Notify change |
|
350 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventAlarmDeletion, id); |
|
351 |
|
352 // DEBUG_PRINT_QUEUE("ALARMSERVER After notifying any event") |
|
353 |
|
354 if (isHeadItem) |
|
355 { |
|
356 // Head item has changed. The timer will pick up the change and requeue itself |
|
357 // for the new alarm. |
|
358 const TAlarmId newHeadItem = HeadAlarmId(); |
|
359 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventHeadItemChanged, newHeadItem); |
|
360 |
|
361 // DEBUG_PRINT_QUEUE("ALARMSERVER After head item changed") |
|
362 } |
|
363 } |
|
364 |
|
365 /** |
|
366 * Returns the alarm at the head of the queue or NULL if there is none. |
|
367 */ |
|
368 const TASSrvAlarm* CASSrvAlarmQueue::HeadAlarm() const |
|
369 { |
|
370 // There is a head alarm if there is at least one alarm in the queue |
|
371 // and that alarm is not disabled. |
|
372 CASSrvAlarmQueue& self = const_cast<CASSrvAlarmQueue&>(*this); |
|
373 |
|
374 // Create & open primary iterator |
|
375 RASSrvIteratorByStatus primaryIterator(self, EAlarmStatusEnabled); |
|
376 primaryIterator.Open(); |
|
377 |
|
378 // Create and attach secondary iterator |
|
379 RASSrvIteratorByState secondaryIterator(self, EAlarmStateQueued, EAlarmStateSnoozed); |
|
380 primaryIterator.IteratorAttach(secondaryIterator); |
|
381 |
|
382 if (primaryIterator.NextAlarmAvailable()) |
|
383 { |
|
384 return QueueAlarmById(primaryIterator.NextAlarm().Id()); |
|
385 } |
|
386 else |
|
387 { |
|
388 return NULL; |
|
389 } |
|
390 } |
|
391 |
|
392 #ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS |
|
393 /** |
|
394 * Returns the calendar alarm at the head of the queue |
|
395 */ |
|
396 TAlarmId CASSrvAlarmQueue::HeadCalendarAlarmId() const |
|
397 { |
|
398 CASSrvAlarmQueue& self = const_cast<CASSrvAlarmQueue&>(*this); |
|
399 |
|
400 // Create & open primary iterator |
|
401 RASSrvIteratorByStatus primaryIterator(self, EAlarmStatusEnabled); |
|
402 primaryIterator.Open(); |
|
403 |
|
404 // Create and attach secondary iterator |
|
405 RASSrvIteratorByState secondaryIterator(self, EAlarmStateQueued, EAlarmStateSnoozed); |
|
406 primaryIterator.IteratorAttach(secondaryIterator); |
|
407 |
|
408 // The category for calendar alarms is defined in caalarm.h and is |
|
409 // reproduced here to avoid a dependency on the calendar server |
|
410 const TUid KUidAgendaModelAlarmCategory = { 0x101F4A70 }; |
|
411 |
|
412 // Create and attach tertiary iterator |
|
413 RASSrvIteratorByCategory tertiaryIterator(self, KUidAgendaModelAlarmCategory); |
|
414 primaryIterator.IteratorAttach(tertiaryIterator); |
|
415 |
|
416 TAlarmId returnAlarmId(KNullAlarmId); |
|
417 |
|
418 if (primaryIterator.NextAlarmAvailable()) |
|
419 { |
|
420 returnAlarmId = primaryIterator.NextAlarm().Id(); |
|
421 } |
|
422 |
|
423 return returnAlarmId; |
|
424 } |
|
425 #endif |
|
426 |
|
427 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT |
|
428 /** |
|
429 * Returns the alarm id of the head wakeup alarm of the queue |
|
430 */ |
|
431 TAlarmId CASSrvAlarmQueue::HeadWakeupAlarmId() const |
|
432 { |
|
433 // There is a head alarm if there is at least one alarm in the queue |
|
434 // and that alarm is not disabled. |
|
435 CASSrvAlarmQueue& self = const_cast<CASSrvAlarmQueue&>(*this); |
|
436 |
|
437 // Create & open primary iterator |
|
438 RASSrvIteratorByStatus primaryIterator(self, EAlarmStatusEnabled); |
|
439 primaryIterator.Open(); |
|
440 |
|
441 // Create and attach secondary iterator |
|
442 RASSrvIteratorByState secondaryIterator(self, EAlarmStateQueued, EAlarmStateSnoozed); |
|
443 primaryIterator.IteratorAttach(secondaryIterator); |
|
444 |
|
445 // Create and attach tertiary iterator |
|
446 RASSrvIteratorByWakeup tertiaryIterator(self); |
|
447 secondaryIterator.IteratorAttach(tertiaryIterator); |
|
448 |
|
449 TAlarmId returnAlarmId(KNullAlarmId); |
|
450 |
|
451 if (primaryIterator.NextAlarmAvailable()) |
|
452 { |
|
453 returnAlarmId = primaryIterator.NextAlarm().Id(); |
|
454 } |
|
455 |
|
456 return returnAlarmId; |
|
457 } |
|
458 #endif |
|
459 |
|
460 /** |
|
461 * Returns the id of the alarm at the head of the queue, or if there isn't a head alarm returns KNullAlarmId |
|
462 */ |
|
463 TAlarmId CASSrvAlarmQueue::HeadAlarmId() const |
|
464 { |
|
465 TAlarmId headItemId = KNullAlarmId; |
|
466 const TASSrvAlarm* headAlarm = HeadAlarm(); |
|
467 if (headAlarm) |
|
468 { |
|
469 headItemId = headAlarm->Id(); |
|
470 } |
|
471 return headItemId; |
|
472 } |
|
473 |
|
474 /** |
|
475 * Called whenever a session logs off. All session-specific alarm should be removed in this instance. |
|
476 */ |
|
477 void CASSrvAlarmQueue::RemoveAllSessionAlarmsBySessionId(TASSrvSessionId aSessionId) |
|
478 { |
|
479 const TInt count = QueueAlarmCount(); |
|
480 for(TInt i=count-1; i>=0; i--) |
|
481 { |
|
482 const TASSrvAlarm& alarm = QueueAlarmAt(i); |
|
483 if (alarm.OriginatingSessionId() == aSessionId && alarm.Characteristics().IsSet(EAlarmCharacteristicsSessionSpecific)) |
|
484 DeQueueAlarm(alarm); |
|
485 } |
|
486 } |
|
487 |
|
488 /** |
|
489 * Generates and returns the next valid alarm id. |
|
490 */ |
|
491 TAlarmId CASSrvAlarmQueue::NextFreeAlarmId() |
|
492 { |
|
493 if (iNextFreeAlarmId == KMaxTInt) |
|
494 { |
|
495 iNextFreeAlarmId = 1; // Zero is special - "No alarm id" |
|
496 } |
|
497 else |
|
498 { |
|
499 ++iNextFreeAlarmId; |
|
500 } |
|
501 |
|
502 // Generate a unique alarm Id. |
|
503 while(AlarmIdIsInUse(iNextFreeAlarmId)) |
|
504 { |
|
505 if (iNextFreeAlarmId == KMaxTInt) |
|
506 { |
|
507 iNextFreeAlarmId = 1; |
|
508 } |
|
509 else |
|
510 { |
|
511 ++iNextFreeAlarmId; |
|
512 } |
|
513 } |
|
514 |
|
515 return iNextFreeAlarmId; |
|
516 } |
|
517 |
|
518 /** |
|
519 * Specify type of Store (or Internalize) operation wanted: |
|
520 * 1. Externalize |
|
521 * - synchronous write of alarm queue and related information to file. |
|
522 * 2. Internalize after Startup or Restore |
|
523 * - synchronous read of alarm queue and related information from file. |
|
524 * 3. Backup |
|
525 */ |
|
526 TInt CASSrvAlarmQueue::StartAlarmStoreOperation(TStoreOperation aStoreOperation) |
|
527 { |
|
528 TInt error = KErrNone; |
|
529 |
|
530 switch (aStoreOperation) |
|
531 { |
|
532 case EStoreInternalizeStartup: |
|
533 { |
|
534 DEBUG_PRINT1(_L("> StartAlarmStoreOperation (InternalizeStartup)")); |
|
535 // Can't have two concurrent Store operations |
|
536 if (iStoreOperation != EStoreIdle) |
|
537 error = KErrLocked; |
|
538 break; |
|
539 } |
|
540 case EStoreInternalizeRestore: |
|
541 { |
|
542 DEBUG_PRINT1(_L("> StartAlarmStoreOperation (InternalizeRestore)")); |
|
543 // Check this is progression to Restore from Internalize |
|
544 if (iStoreOperation != EStoreRestore) |
|
545 error = KErrLocked; |
|
546 break; |
|
547 } |
|
548 case EStoreExternalize: |
|
549 { |
|
550 DEBUG_PRINT1(_L("> StartAlarmStoreOperation (Externalize)")); |
|
551 // Can't have two concurrent Store operations |
|
552 if (iStoreOperation != EStoreIdle) |
|
553 error = KErrLocked; |
|
554 break; |
|
555 } |
|
556 case EStoreBackup: |
|
557 { |
|
558 DEBUG_PRINT1(_L("> StartAlarmStoreOperation (Backup)")); |
|
559 // Can't have two concurrent Store operations |
|
560 if (iStoreOperation != EStoreIdle) |
|
561 error = KErrLocked; |
|
562 break; |
|
563 } |
|
564 case EStoreRestore: |
|
565 { |
|
566 DEBUG_PRINT1(_L("> StartAlarmStoreOperation (Restore)")); |
|
567 // Can't have two concurrent Store operations |
|
568 if (iStoreOperation != EStoreIdle) |
|
569 { |
|
570 error = KErrLocked; |
|
571 } |
|
572 else |
|
573 { |
|
574 // notify clients that Restore has started |
|
575 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventRestoreStarted, KNullAlarmId); |
|
576 } |
|
577 break; |
|
578 } |
|
579 case EStoreIdle: |
|
580 default: |
|
581 { |
|
582 DEBUG_PRINT1(_L("> StartAlarmStoreOperation (Idle or other invalid)")); |
|
583 error = KErrInUse; |
|
584 __ASSERT_DEBUG(EFalse, ASSrvStaticUtils::Fault(ASSrvStaticUtils::EASSrvFaultStartInvalidAlarmStoreOperation)); |
|
585 break; |
|
586 } |
|
587 } |
|
588 if (!error) |
|
589 { |
|
590 iStoreOperation = aStoreOperation; |
|
591 } |
|
592 |
|
593 DEBUG_PRINT2(_L("< StartAlarmStoreOperation result = %i"), error); |
|
594 return error; |
|
595 } |
|
596 |
|
597 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT |
|
598 /** |
|
599 * Handle a change to the next DST event |
|
600 */ |
|
601 void CASSrvAlarmQueue::HandleNextDSTChangeEventL() |
|
602 { |
|
603 UpdateRTC(); |
|
604 } |
|
605 |
|
606 /** |
|
607 * Find the head wakeup alarm and queue set it with the real-time-clock. |
|
608 */ |
|
609 void CASSrvAlarmQueue::UpdateRTC() |
|
610 { |
|
611 // We always call UnsetWakeupAlarm even if we are going to call SetWakeupAlarm later because the RTC |
|
612 // adaptation plug-in requires UnsetWakeupAlarm to be called before any call to SetWakeupAlarm. |
|
613 TRequestStatus status; |
|
614 iSsmRtcAdaptation.UnsetWakeupAlarm(status); |
|
615 User::WaitForRequest(status); |
|
616 |
|
617 // loop through the alarm queue until the first wakeup alarm is found |
|
618 TAlarmId headWakeupAlarmId = HeadWakeupAlarmId(); |
|
619 |
|
620 DEBUG_PRINT2(_L("CASSrvAlarmQueue::UpdateRTC alarm count = %d"),QueueAlarmCount()); |
|
621 |
|
622 if (headWakeupAlarmId != KNullAlarmId) |
|
623 { |
|
624 // There is a wakeup alarm |
|
625 const TASSrvAlarm* headWakeupAlarm = QueueAlarmById(headWakeupAlarmId); |
|
626 TTime wakeupAlarmTime(headWakeupAlarm->NextDueTime()); |
|
627 |
|
628 if (headWakeupAlarm->IsFloating()) |
|
629 { |
|
630 TTime nextDSTChangeUTC = iASSrvDSTChange->NextDSTChangeUTC(); |
|
631 |
|
632 if (nextDSTChangeUTC != Time::NullTTime() && nextDSTChangeUTC < wakeupAlarmTime) |
|
633 { |
|
634 // The alarm is set to expire after a DST event so adjust the UTC time |
|
635 // of the alarm to what it will be after the DST rollover |
|
636 wakeupAlarmTime += iPreviousUtcOffset; |
|
637 wakeupAlarmTime -= iASSrvDSTChange->NextUTCOffset(); |
|
638 } |
|
639 } |
|
640 |
|
641 // Set the key value to 'EWakeupAlarmSet' so that listeners are notified of the presence of an active wakeup alarm. |
|
642 RProperty::Set(KAlarmServerPubSubCategory, KWakeupAlarmPubSubKey, EActiveWakeupAlarmSet ); |
|
643 DEBUG_PRINT1(_L("Set the KWakeupAlarmPubSubKey to EActiveWakeupAlarmSet")); |
|
644 |
|
645 // Set the Real Time Clock in UTC |
|
646 TRequestStatus status; |
|
647 TPckgC<TTime> wakeupAlarmTimePckg(wakeupAlarmTime); |
|
648 iSsmRtcAdaptation.SetWakeupAlarm(wakeupAlarmTimePckg, status); |
|
649 User::WaitForRequest(status); |
|
650 } |
|
651 else |
|
652 { |
|
653 // Notify the listeners that there is no head wake alarm present in the alarm queue |
|
654 RProperty::Set(KAlarmServerPubSubCategory, KWakeupAlarmPubSubKey, EActiveNoWakeupAlarmsSet ); |
|
655 DEBUG_PRINT1(_L("Set the KWakeupAlarmPubSubKey to EActiveNoWakeupAlarmsSet")); |
|
656 } |
|
657 |
|
658 } |
|
659 #endif |
|
660 |
|
661 /** |
|
662 * End an Alarm Store Operation (Internalize, Externalize, Backup or Restore). |
|
663 * Various tidying up including: |
|
664 * Finalise an Internalise, or throw it away. (depending on aError) |
|
665 * Process queued change events. |
|
666 * Release the Access Token. |
|
667 */ |
|
668 void CASSrvAlarmQueue::EndAlarmStoreOperation(TInt aError) |
|
669 { |
|
670 switch (iStoreOperation) |
|
671 { |
|
672 case EStoreIdle: |
|
673 default: |
|
674 { |
|
675 DEBUG_PRINT1(_L("> EndAlarmStoreOperation (EStoreIdle or invalid)")); |
|
676 __ASSERT_DEBUG(EFalse, ASSrvStaticUtils::Fault(ASSrvStaticUtils::EASSrvFaultEndInvalidAlarmStoreOperation)); |
|
677 break; |
|
678 } |
|
679 case EStoreInternalizeStartup: |
|
680 case EStoreInternalizeRestore: |
|
681 { |
|
682 DEBUG_PRINT2(_L("> EndAlarmStoreOperation (InternalizeXXX, aError = %i)"), aError); |
|
683 |
|
684 if (!aError) |
|
685 { |
|
686 // Alarm Queue is about to change |
|
687 // (stops Alarm Timer, currently notifying alarm, etc...) |
|
688 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventAlarmStartInternalize, KNullAlarmId); |
|
689 |
|
690 // Apply Internalize buffers for Alarm Queue, Alarm Data & Sound Intervals |
|
691 // Alarm Queue |
|
692 ApplyInternalizedData(ETrue); |
|
693 // Alarm Data Pool |
|
694 ServerData().DataPool().ApplyInternalizedData(ETrue); |
|
695 // Sound Settings |
|
696 ServerData().SoundSettings().ApplyInternalizedData(ETrue); |
|
697 |
|
698 // Notify observers about new queue |
|
699 const TAlarmId newHeadItemId = HeadAlarmId(); |
|
700 if (newHeadItemId != KNullAlarmId) |
|
701 { |
|
702 // Head item has changed. The timer will pick up the change and requeue itself |
|
703 // for the new alarm. |
|
704 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventHeadItemChanged, newHeadItemId); |
|
705 } |
|
706 |
|
707 // notify clients that Restore has completed |
|
708 if (iStoreOperation == EStoreInternalizeRestore) |
|
709 { |
|
710 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventRestoreCompleted, KNullAlarmId); |
|
711 } |
|
712 |
|
713 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT |
|
714 |
|
715 else if (iStoreOperation == EStoreInternalizeStartup) |
|
716 { |
|
717 // When internalize happens on alarm server start-up publish the information |
|
718 // whether we have an active alarm set or not |
|
719 DEBUG_PRINT1(_L("CASSrvAlarmQueue::EndAlarmStoreOperation Calls UpdateRTC after internalizing the queue on alarm server startup")); |
|
720 UpdateRTC(); |
|
721 } |
|
722 |
|
723 #endif |
|
724 } // end of if block |
|
725 else |
|
726 { |
|
727 // Discard Internalize buffers for Alarm Queue, Alarm Data & Sound Intervals |
|
728 // Alarm Queue |
|
729 ApplyInternalizedData(EFalse); |
|
730 // Alarm Data Pool |
|
731 ServerData().DataPool().ApplyInternalizedData(EFalse); |
|
732 // Sound Settings |
|
733 ServerData().SoundSettings().ApplyInternalizedData(EFalse); |
|
734 |
|
735 // notify clients that Restore has failed |
|
736 if (iStoreOperation == EStoreInternalizeRestore) |
|
737 { |
|
738 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventRestoreFailed, KNullAlarmId); |
|
739 } |
|
740 } |
|
741 break; |
|
742 } |
|
743 case EStoreExternalize: |
|
744 { |
|
745 DEBUG_PRINT1(_L("> EndAlarmStoreOperation (Externalize)")); |
|
746 |
|
747 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT |
|
748 TRAP_IGNORE(UpdateRTC()); |
|
749 #endif |
|
750 break; |
|
751 } |
|
752 case EStoreBackup: |
|
753 { |
|
754 DEBUG_PRINT1(_L("> EndAlarmStoreOperation (Backup)")); |
|
755 break; |
|
756 } |
|
757 case EStoreRestore: |
|
758 { |
|
759 DEBUG_PRINT1(_L("> EndAlarmStoreOperation (Restore)")); |
|
760 // notify clients that Restore has failed |
|
761 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventRestoreFailed, KNullAlarmId); |
|
762 break; |
|
763 } |
|
764 } // end of switch-case block |
|
765 |
|
766 #ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS |
|
767 |
|
768 // Republish the last alarmed instance parameters after internalizing on startup |
|
769 if (iStoreOperation == EStoreInternalizeStartup) |
|
770 { |
|
771 PublishAlarmedInstanceParams(iLastAlarmedInstanceParams); |
|
772 } |
|
773 |
|
774 #endif |
|
775 |
|
776 iStoreOperation = EStoreIdle; |
|
777 DEBUG_PRINT1(_L("< EndAlarmStoreOperation completed")); |
|
778 return; |
|
779 } |
|
780 |
|
781 /** |
|
782 * Check that Alarm and Alarm Data is writable. |
|
783 * Policy is to leave with KErrLocked if Restore is in progress. |
|
784 */ |
|
785 void CASSrvAlarmQueue::CheckAlarmQueueWritableL() |
|
786 { |
|
787 if (iStoreOperation == EStoreRestore |
|
788 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT |
|
789 || iServerWideData.ServerIsReadOnly() |
|
790 #endif |
|
791 ) |
|
792 { |
|
793 User::Leave(KErrLocked); |
|
794 } |
|
795 } |
|
796 |
|
797 /** |
|
798 * Restore the queue from the specified stream. |
|
799 */ |
|
800 void CASSrvAlarmQueue::InternalizeL(RReadStream& aStream) |
|
801 { |
|
802 // First read the leading count which indicates how many alarms there |
|
803 // are. |
|
804 const TInt count = aStream.ReadInt32L(); |
|
805 |
|
806 // Read in the stream |
|
807 TLinearOrder<TASSrvAlarm> order(ASSrvStaticUtils::CompareAlarms); |
|
808 |
|
809 if (iInternalizeAlarmQueue.Count() != 0) |
|
810 { |
|
811 iInternalizeAlarmQueue.ResetAndDestroy(); |
|
812 } |
|
813 |
|
814 TTimeIntervalSeconds alarmExpireWindow = 0; |
|
815 |
|
816 // what type of Internalize are we doing? |
|
817 switch (iStoreOperation) |
|
818 { |
|
819 case EStoreInternalizeStartup: // system startup |
|
820 { |
|
821 // 59s window for alarms in the past |
|
822 alarmExpireWindow = KAlarmServerStartupExpireWindowInSeconds; |
|
823 break; |
|
824 } |
|
825 case EStoreInternalizeRestore: // after a backup restore |
|
826 { |
|
827 // 0 window for alarms in the past |
|
828 // NB Notified Alarms stay Notified, |
|
829 // but Notifying Alarms become Notified |
|
830 // This is reasonable as a Restore of alarms is a dramatic thing to do. |
|
831 alarmExpireWindow = 0; |
|
832 break; |
|
833 } |
|
834 default: |
|
835 { |
|
836 __ASSERT_ALWAYS(EFalse, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicInternalizeTypeInvalid)); |
|
837 break; |
|
838 } |
|
839 } |
|
840 |
|
841 RPointerArray<TASSrvAlarm> alarmArray; |
|
842 CleanupResetAndDestroyPushL(alarmArray); |
|
843 |
|
844 for(TInt j=0; j<count; j++) |
|
845 { |
|
846 TASSrvAlarm* alarm = new(ELeave) TASSrvAlarm(ServerData()); |
|
847 CleanupStack::PushL(alarm); |
|
848 aStream >> *alarm; |
|
849 alarmArray.AppendL(alarm); |
|
850 CleanupStack::Pop(); |
|
851 } |
|
852 |
|
853 // Read in the next valid id |
|
854 iInternalizeNextFreeAlarmId = aStream.ReadInt32L(); |
|
855 |
|
856 // Internalize the UTC offset the last time the queue was run. |
|
857 TInt32 tempInt; |
|
858 aStream >> tempInt; |
|
859 TTimeIntervalSeconds currentOffset = User::UTCOffset(); |
|
860 TTimeIntervalSeconds cachedOffset(tempInt); |
|
861 |
|
862 TTime previousDSTChangeUTC = iASSrvDSTChange->PreviousDSTChangeUTC(); |
|
863 TTimeIntervalMinutes previousUTCOffset = iASSrvDSTChange->PreviousUTCOffset(); |
|
864 TTime localTimeBeforeDSTChange = previousDSTChangeUTC + previousUTCOffset; |
|
865 TTime localTimeAfterDSTChange = previousDSTChangeUTC + currentOffset; |
|
866 |
|
867 for(TInt i=0; i<count; i++) |
|
868 { |
|
869 // Internalize the alarm (replacing any previous details) |
|
870 TASSrvAlarm* alarm ; |
|
871 alarm = alarmArray[i]; |
|
872 // Set id to KNullAlarmId to prevent notifications when |
|
873 // the alarm is enabled |
|
874 const TAlarmId originalId = alarm->Id(); |
|
875 alarm->Id()=KNullAlarmId; |
|
876 |
|
877 // Validate the alarm, retaining the alarm status (enabled or disabled) |
|
878 // - we only add valid alarms to the queue. |
|
879 const TBool KAllowBlanketInThePastOnceOnlyAlarms = EFalse; // Default value |
|
880 const TBool KEnableAlarm = alarm->Status()==EAlarmStatusEnabled; |
|
881 //An alarm set to 'repeat next 24 hour' can be missed while the alarm server is inactive. |
|
882 //Therefore it should be changed to 'repeat once' before it is restored to the alarm queue |
|
883 //so that it is not incorrectly resheduled to notify in the next 24 hours |
|
884 if(alarm->RepeatDefinition() == EAlarmRepeatDefintionRepeatNext24Hours) |
|
885 { |
|
886 alarm->RepeatDefinition() = EAlarmRepeatDefintionRepeatOnce; |
|
887 } |
|
888 |
|
889 TTime previousAlarmLocalTime = alarm->NextDueTime() + previousUTCOffset; |
|
890 TBool alarmInDSTChangeGap = (previousDSTChangeUTC != Time::NullTTime() // make sure DST change info has been published |
|
891 && (previousAlarmLocalTime >= localTimeBeforeDSTChange && previousAlarmLocalTime < localTimeAfterDSTChange ) ); |
|
892 |
|
893 TTimeIntervalSeconds missingTime; |
|
894 localTimeAfterDSTChange.SecondsFrom(localTimeBeforeDSTChange, missingTime); |
|
895 |
|
896 // Increase the allowable window if this alarm was due to go off in the DST change gap |
|
897 TTimeIntervalSeconds thisAlarmsExpireWindow = alarmInDSTChangeGap ? alarmExpireWindow.Int() + missingTime.Int() : alarmExpireWindow; |
|
898 |
|
899 // Update the due time of floating alarms during a DST event. This will ensure that alarms |
|
900 // are not invalidated by ValidateAndEnable(). |
|
901 TTimeIntervalSeconds offsetDifference; |
|
902 |
|
903 if(alarm->IsFloating()) |
|
904 { |
|
905 if (cachedOffset != currentOffset) |
|
906 { |
|
907 // Calculate the change in the offset. |
|
908 offsetDifference = (currentOffset.Int() - cachedOffset.Int()); |
|
909 alarm->NextDueTime() -= offsetDifference; |
|
910 alarm->OriginalExpiryTime() -= offsetDifference; |
|
911 } |
|
912 } |
|
913 |
|
914 const TInt error = alarm->ValidateAndEnable(thisAlarmsExpireWindow, KAllowBlanketInThePastOnceOnlyAlarms, KEnableAlarm); |
|
915 |
|
916 if (alarmInDSTChangeGap) |
|
917 { |
|
918 // The local alarm time was set during the missing DST changeover gap |
|
919 // this repeat should actually appear an hour later than |
|
920 alarm->NextDueTime() += missingTime; |
|
921 } |
|
922 |
|
923 if (error != KErrArgument) |
|
924 { |
|
925 // Alarm is okay, so insert it into the queue in the |
|
926 // right position |
|
927 alarm->Id()=originalId; |
|
928 const TInt error = iInternalizeAlarmQueue.InsertInOrderAllowRepeats(alarm, order); |
|
929 User::LeaveIfError(error); |
|
930 alarmArray[i] = NULL; |
|
931 } |
|
932 else |
|
933 { |
|
934 delete alarmArray[i]; |
|
935 alarmArray[i] = NULL; |
|
936 } |
|
937 } |
|
938 CleanupStack::PopAndDestroy(); //alarmArray |
|
939 ServerData().CachedUtcOffset() = currentOffset; |
|
940 } |
|
941 |
|
942 /** |
|
943 * Whether to use the Internalize buffer, or throw it away |
|
944 */ |
|
945 void CASSrvAlarmQueue::ApplyInternalizedData(TBool aUseNewData) |
|
946 { |
|
947 DEBUG_PRINT2(_L("** ApplyInternalizedData(%u)"), aUseNewData); |
|
948 |
|
949 if (aUseNewData) |
|
950 { |
|
951 // Internalize Success |
|
952 |
|
953 // Replace all alarms with those from the stream |
|
954 // Assign new queue to replace old one |
|
955 ReplaceQueueWithInternalizedQueue(); |
|
956 |
|
957 iNextFreeAlarmId = iInternalizeNextFreeAlarmId; |
|
958 |
|
959 // Remove any which are too old |
|
960 RemoveDeadAlarms(); |
|
961 // Check whether the UTC offset has changed since the last time the Alarm Server |
|
962 // was running, and update floating alarm due times if it has. |
|
963 UpdateFloatingDueTimes(); |
|
964 } |
|
965 else |
|
966 { |
|
967 // Internalize Failure |
|
968 iInternalizeAlarmQueue.ResetAndDestroy(); |
|
969 |
|
970 // Set the previous UTC offset to the current UTC offset, since there was no |
|
971 // previous offset internalised. |
|
972 ServerData().CachedUtcOffset() = User::UTCOffset(); |
|
973 } |
|
974 } |
|
975 |
|
976 /** |
|
977 * Update the due times of floating alarms due to a locale or DST change. |
|
978 * |
|
979 * @internalComponent |
|
980 */ |
|
981 void CASSrvAlarmQueue::UpdateFloatingDueTimes() |
|
982 { |
|
983 // Has the UTC offset changed due to a Locale change? |
|
984 TTimeIntervalSeconds offset = User::UTCOffset(); |
|
985 |
|
986 if (ServerData().CachedUtcOffset() != offset) |
|
987 { |
|
988 // Update the locally set alarm due times because the UTC offset has changed. |
|
989 |
|
990 // Calculate the change in the offset. |
|
991 TTimeIntervalSeconds offsetDifference(offset.Int() - ServerData().CachedUtcOffset().Int()); |
|
992 |
|
993 // Get the head id so that we know if the queue has changed |
|
994 const TAlarmId headItemId = HeadAlarmId(); |
|
995 |
|
996 // Cycle through all alarms. |
|
997 TInt count = QueueAlarmCount(); |
|
998 TBool orderChanged = EFalse; |
|
999 |
|
1000 for (TInt i = 0; i < count; i++) |
|
1001 { |
|
1002 TASSrvAlarm& alarm = QueueAlarmAt(i); |
|
1003 |
|
1004 // Check whether the alarm is floating. |
|
1005 if (alarm.IsFloating()) |
|
1006 { |
|
1007 // Update the due time of the alarm, since it is floating. |
|
1008 TTime oldDueTime = alarm.NextDueTime(); |
|
1009 |
|
1010 // Subtract the change in offset from the due time to get the new due time. |
|
1011 TTime newDueTime = oldDueTime - offsetDifference; |
|
1012 |
|
1013 // Set the new due time of the alarm. |
|
1014 alarm.NextDueTime()=newDueTime; |
|
1015 |
|
1016 // Also, shift the original expiry time, to ensure that repeating |
|
1017 // alarms repeat correctly. |
|
1018 newDueTime = alarm.OriginalExpiryTime() - offsetDifference; |
|
1019 |
|
1020 // Shift the original ExpiryTime. |
|
1021 alarm.OriginalExpiryTime()=newDueTime; |
|
1022 orderChanged = ETrue; |
|
1023 } |
|
1024 } |
|
1025 |
|
1026 // Check whether the order of the alarm queue may have changed. |
|
1027 if (orderChanged) |
|
1028 { |
|
1029 // Re-order the alarm queue. |
|
1030 TLinearOrder<TASSrvAlarm> order(ASSrvStaticUtils::CompareAlarms); |
|
1031 iAlarms.Sort(order); |
|
1032 |
|
1033 // Did the head item change? |
|
1034 const TAlarmId newHeadItemId = HeadAlarmId(); |
|
1035 |
|
1036 if (newHeadItemId != headItemId) |
|
1037 { |
|
1038 // Head item has changed. The timer will pick up the change and requeue itself |
|
1039 // for the new alarm. |
|
1040 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventHeadItemChanged, newHeadItemId); |
|
1041 } |
|
1042 } |
|
1043 |
|
1044 // Set the previous UTC offset to the current UTC offset. |
|
1045 ServerData().CachedUtcOffset() = offset; |
|
1046 } |
|
1047 } |
|
1048 |
|
1049 /** |
|
1050 * Publish skipped alarm data. |
|
1051 * |
|
1052 * @internalComponent |
|
1053 */ |
|
1054 void CASSrvAlarmQueue::PublishSkippedAlarm(TBool aSkippedCalAlarm) |
|
1055 { |
|
1056 // Define the property before use |
|
1057 TInt err = RProperty::Define(KAlarmServerPubSubCategory, KMissingAlarmPubSubKey, RProperty::EByteArray, KReadPolicy, KWritePolicy); |
|
1058 |
|
1059 // If the define completed successfully, create the data and publish |
|
1060 if (err == KErrNone || err == KErrAlreadyExists) |
|
1061 { |
|
1062 TMissedAlarmPubSubData pubSubData; |
|
1063 pubSubData.iTimeOfChangeUtc.UniversalTime(); |
|
1064 if(aSkippedCalAlarm) |
|
1065 { |
|
1066 // There are skipped alarms after a system time or time zone change |
|
1067 pubSubData.iValue = 2; |
|
1068 } |
|
1069 else |
|
1070 { |
|
1071 // There was a time zone change, but no alarms were skipped |
|
1072 pubSubData.iValue = 1; |
|
1073 } |
|
1074 |
|
1075 TPckgBuf<TMissedAlarmPubSubData> pubSubBuf(pubSubData); |
|
1076 RProperty::Set(KAlarmServerPubSubCategory, KMissingAlarmPubSubKey, pubSubBuf); |
|
1077 } |
|
1078 } |
|
1079 |
|
1080 #ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS |
|
1081 |
|
1082 /** |
|
1083 * Publish data about the skipped alarm. |
|
1084 * |
|
1085 * @internalComponent |
|
1086 */ |
|
1087 void CASSrvAlarmQueue::PublishAlarmedInstanceParams(const TTime& aFirstSkippedAlarmLocalTime, TBool aSystemTimeChange) |
|
1088 { |
|
1089 // Create the data structure before publishing |
|
1090 TASShdAlarmedInstanceParams alarmedInstanceParams; |
|
1091 alarmedInstanceParams.iLocalStartTime = aFirstSkippedAlarmLocalTime; |
|
1092 alarmedInstanceParams.iLocalEndTime = ASSrvStaticUtils::LocalTimeNow(); |
|
1093 alarmedInstanceParams.iTimeType = aSystemTimeChange ? EFloatingOrFixed : EFloating; |
|
1094 |
|
1095 PublishAlarmedInstanceParams(alarmedInstanceParams); |
|
1096 } |
|
1097 |
|
1098 /** |
|
1099 * Publish data about the skipped alarm. |
|
1100 * |
|
1101 * @internalComponent |
|
1102 */ |
|
1103 void CASSrvAlarmQueue::PublishAlarmedInstanceParams(const TASShdAlarmedInstanceParams& aAlarmedInstanceParams) |
|
1104 { |
|
1105 // Define the property before use |
|
1106 TInt err = RProperty::Define(KAlarmServerPubSubCategory, KSkippedAlarmInstancesPubSubKey, RProperty::EByteArray, KReadPolicy, KWritePolicy); |
|
1107 |
|
1108 // If the define completed successfully, publish |
|
1109 if (err == KErrNone || err == KErrAlreadyExists) |
|
1110 { |
|
1111 TPckgBuf<TASShdAlarmedInstanceParams> pubSubBuf(aAlarmedInstanceParams); |
|
1112 RProperty::Set(KAlarmServerPubSubCategory, KSkippedAlarmInstancesPubSubKey, pubSubBuf); |
|
1113 iLastAlarmedInstanceParams = aAlarmedInstanceParams; |
|
1114 } |
|
1115 } |
|
1116 #endif |
|
1117 |
|
1118 /** |
|
1119 * Store the queue to the specified stream. |
|
1120 */ |
|
1121 void CASSrvAlarmQueue::ExternalizeL(RWriteStream& aStream) const |
|
1122 { |
|
1123 const TInt count = QueueAlarmCount(); |
|
1124 aStream.WriteInt32L(count); |
|
1125 // |
|
1126 for(TInt i=0; i<count; i++) |
|
1127 { |
|
1128 const TASSrvAlarm& alarm = QueueAlarmAt(i); |
|
1129 aStream << alarm; |
|
1130 } |
|
1131 aStream.WriteInt32L(iNextFreeAlarmId); |
|
1132 |
|
1133 // Externalize the UTC offset. |
|
1134 TInt32 tempInt = ServerData().CachedUtcOffset().Int(); |
|
1135 aStream << tempInt; |
|
1136 } |
|
1137 |
|
1138 #ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS |
|
1139 /** |
|
1140 * Externalize the last skipped agenda alarm data |
|
1141 */ |
|
1142 void CASSrvAlarmQueue::ExternalizeLastAlarmedInstanceParamsL(RWriteStream& aStream) const |
|
1143 { |
|
1144 TPckgBuf<TASShdAlarmedInstanceParams> paramsBuf(iLastAlarmedInstanceParams); |
|
1145 aStream << paramsBuf; |
|
1146 |
|
1147 // Write two words reserved for future use |
|
1148 aStream.WriteInt32L(0); |
|
1149 aStream.WriteInt32L(0); |
|
1150 } |
|
1151 |
|
1152 /** |
|
1153 * Internalize the last published skipped agenda alarm data |
|
1154 */ |
|
1155 void CASSrvAlarmQueue::InternalizeLastAlarmedInstanceParamsL(RReadStream& aStream) |
|
1156 { |
|
1157 TPckgBuf<TASShdAlarmedInstanceParams> paramsBuf; |
|
1158 aStream >> paramsBuf; |
|
1159 iLastAlarmedInstanceParams = paramsBuf(); |
|
1160 |
|
1161 // Read two words reserved for future use |
|
1162 aStream.ReadInt32L(); |
|
1163 aStream.ReadInt32L(); |
|
1164 } |
|
1165 #endif |
|
1166 |
|
1167 /** |
|
1168 * Called when the status of one or more alarms changes |
|
1169 */ |
|
1170 void CASSrvAlarmQueue::HandleAlarmStatusChanged(TAlarmId aAlarmThatChangedStatus, TAlarmStatus aOldStatus) |
|
1171 { |
|
1172 // Resort the queue. We need to do this for alarms which may, for example, |
|
1173 // have a repeat definition and was disabled and has been re-enabled but the |
|
1174 // original expiry time has since passed. The alarm's next due time has |
|
1175 // been updated but the queue does not yet reflect this. |
|
1176 TLinearOrder<TASSrvAlarm> order(ASSrvStaticUtils::CompareAlarms); |
|
1177 iAlarms.Sort(order); |
|
1178 |
|
1179 // Called whenever an alarm changes state. We need to update the alarm timer. |
|
1180 const TASSrvAlarm* alarm = QueueAlarmById(aAlarmThatChangedStatus); |
|
1181 // |
|
1182 const TAlarmId newHeadAlarmId = HeadAlarmId(); |
|
1183 const TAlarmId timerAlarmId = ServerData().Timer().NextDueAlarmId(); |
|
1184 // |
|
1185 if (timerAlarmId != newHeadAlarmId || aAlarmThatChangedStatus == timerAlarmId) |
|
1186 { |
|
1187 // The head item has changed. |
|
1188 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventHeadItemChanged, newHeadAlarmId); |
|
1189 } |
|
1190 |
|
1191 // Notify observers |
|
1192 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventAlarmChanged, aAlarmThatChangedStatus); |
|
1193 NotifyAlarmObserverEvent(MASSrvAlarmObserver::EAlarmObserverStatusChanged, *alarm, static_cast<TInt>(aOldStatus)); |
|
1194 |
|
1195 // Notify change |
|
1196 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventStatus, aAlarmThatChangedStatus); |
|
1197 } |
|
1198 |
|
1199 /** |
|
1200 * Called when the state of one or more alarms changes |
|
1201 */ |
|
1202 void CASSrvAlarmQueue::HandleAlarmStateChanged(TAlarmId aAlarmThatChangedState, TAlarmState aOldState) |
|
1203 { |
|
1204 // Resort the queue. We need to do this for alarms which have now become snoozed or |
|
1205 // alarms which were notified but are now re-queued because of their repeat definitions. |
|
1206 TLinearOrder<TASSrvAlarm> order(ASSrvStaticUtils::CompareAlarms); |
|
1207 iAlarms.Sort(order); |
|
1208 |
|
1209 // We need to update the alarm timer if the head alarm is different to |
|
1210 // the old one. |
|
1211 CASSrvAlarmTimer& timer = ServerData().Timer(); |
|
1212 // |
|
1213 const TAlarmId newHeadAlarmId = HeadAlarmId(); |
|
1214 const TAlarmId timerAlarmId = timer.NextDueAlarmId(); |
|
1215 // |
|
1216 if (timerAlarmId != newHeadAlarmId) |
|
1217 { |
|
1218 // The head item has changed. |
|
1219 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventHeadItemChanged, newHeadAlarmId); |
|
1220 } |
|
1221 else if (newHeadAlarmId != KNullAlarmId) |
|
1222 { |
|
1223 // It is possible for the head alarm to change it's due time. |
|
1224 // In this case, the head alarm id is the same, but the times |
|
1225 // are different. |
|
1226 const TASSrvAlarm* newHeadAlarm = QueueAlarmById(newHeadAlarmId); |
|
1227 const TTime& timerDueTime = timer.NextDueAlarmOriginalExpiryTime(); |
|
1228 if (timerAlarmId == newHeadAlarmId && timerDueTime != newHeadAlarm->NextDueTime()) |
|
1229 { |
|
1230 // Alarm id hasn't changed, but the due time has |
|
1231 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventHeadItemChanged, newHeadAlarmId); |
|
1232 } |
|
1233 } |
|
1234 |
|
1235 // Notify observers |
|
1236 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventAlarmChanged, aAlarmThatChangedState); |
|
1237 NotifyAlarmObserverEvent(MASSrvAlarmObserver::EAlarmObserverStateChanged, *QueueAlarmById(aAlarmThatChangedState), static_cast<TInt>(aOldState)); |
|
1238 |
|
1239 // Notify change |
|
1240 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventState, aAlarmThatChangedState); |
|
1241 } |
|
1242 |
|
1243 /** |
|
1244 * Called when the state of one or more alarms changes |
|
1245 */ |
|
1246 void CASSrvAlarmQueue::HandleAlarmCharacteristicsChanged(TAlarmId aAlarmThatChangedCharacteristics, TAlarmCharacteristicsFlags /*aOldCharacteristics*/) |
|
1247 { |
|
1248 // Notify observers |
|
1249 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventAlarmChanged, aAlarmThatChangedCharacteristics); |
|
1250 /** |
|
1251 * Alarm Observers don't currently need to know about this change. |
|
1252 * If this changes this is the place to do something like: |
|
1253 * NotifyAlarmObserverEvent(MASSrvAlarmObserver::EAlarmObserverCharacteristicsChanged, |
|
1254 * QueueAlarmById(aAlarmThatChangedCharacteristics), |
|
1255 * static_cast<TInt>(aOldCharacteristics.Value())); |
|
1256 */ |
|
1257 |
|
1258 // Notify change |
|
1259 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventCharacteristics, aAlarmThatChangedCharacteristics); |
|
1260 } |
|
1261 |
|
1262 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT |
|
1263 void CASSrvAlarmQueue::HandleWakeupChanged(TAlarmId aAlarmThatChangedWakeup) |
|
1264 { |
|
1265 // Notify observers |
|
1266 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventAlarmChanged, aAlarmThatChangedWakeup); |
|
1267 } |
|
1268 #endif |
|
1269 |
|
1270 #ifdef SYMBIAN_ALARM_REPEAT_EXTENSIONS |
|
1271 void CASSrvAlarmQueue::HandleAlarmDaysChanged(TAlarmId aAlarmThatChangedDays) |
|
1272 { |
|
1273 // Check that the alarm has been queued (which we infer by the alarm having an id). |
|
1274 if (aAlarmThatChangedDays == KNullAlarmId) |
|
1275 { |
|
1276 return; |
|
1277 } |
|
1278 |
|
1279 // Resort the queue. |
|
1280 TLinearOrder<TASSrvAlarm> order(ASSrvStaticUtils::CompareAlarms); |
|
1281 iAlarms.Sort(order); |
|
1282 |
|
1283 // Get the id of the head alarm. |
|
1284 const TAlarmId headAlarmId = HeadAlarmId(); |
|
1285 |
|
1286 // Get the id of the alarm associated with the alarm timer. |
|
1287 CASSrvAlarmTimer& timer = ServerData().Timer(); |
|
1288 const TAlarmId timerAlarmId = timer.NextDueAlarmId(); |
|
1289 |
|
1290 // Assume the head item will not change. |
|
1291 TBool headItemChanged = EFalse; |
|
1292 |
|
1293 if (headAlarmId != timerAlarmId) |
|
1294 { |
|
1295 headItemChanged = ETrue; |
|
1296 } |
|
1297 else |
|
1298 { |
|
1299 if (headAlarmId != KNullAlarmId) |
|
1300 { |
|
1301 const TASSrvAlarm* headAlarm = QueueAlarmById(headAlarmId); |
|
1302 const TTime& timerDueTime = timer.NextDueAlarmOriginalExpiryTime(); |
|
1303 |
|
1304 // It is possible for the head alarm to change its due time. In |
|
1305 // this case the alarm timer will no longer be correct. |
|
1306 if (headAlarm->NextDueTime() != timerDueTime) |
|
1307 { |
|
1308 headItemChanged = ETrue; |
|
1309 } |
|
1310 } |
|
1311 } |
|
1312 |
|
1313 if (headItemChanged) |
|
1314 { |
|
1315 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventHeadItemChanged, headAlarmId); |
|
1316 } |
|
1317 } |
|
1318 #endif |
|
1319 |
|
1320 void CASSrvAlarmQueue::HandleAlarmDataChanged(TAlarmId aAlarmThatChangedData) |
|
1321 { |
|
1322 // Notify observers |
|
1323 NotifyEvent(MASSrvAlarmQueueObserver::EASSrvAlarmQueueEventAlarmChanged, aAlarmThatChangedData); |
|
1324 } |
|
1325 |
|
1326 /** |
|
1327 * Returns a boolean indicating whether or not the specified alarm id |
|
1328 * is currently being used by another alarm. |
|
1329 */ |
|
1330 TBool CASSrvAlarmQueue::AlarmIdIsInUse(TAlarmId aAlarmId) const |
|
1331 { |
|
1332 const TInt count = QueueAlarmCount(); |
|
1333 for(TInt i=0; i<count; i++) |
|
1334 { |
|
1335 if (QueueAlarmAt(i).Id() == aAlarmId) |
|
1336 return ETrue; |
|
1337 } |
|
1338 return EFalse; |
|
1339 } |
|
1340 |
|
1341 /** |
|
1342 * Remove any alarms from the queue that have notified already. Anything over 7 days old should be removed. |
|
1343 */ |
|
1344 void CASSrvAlarmQueue::RemoveDeadAlarms() |
|
1345 { |
|
1346 const TInt count = QueueAlarmCount(); |
|
1347 const TTime timeNow(ASSrvStaticUtils::UtcTimeNow()); |
|
1348 for(TInt i=count-1; i>=0; i--) |
|
1349 { |
|
1350 TASSrvAlarm& alarm = QueueAlarmAt(i); |
|
1351 const TTimeIntervalDays daysSinceLastExpired(alarm.NextDueTime().DaysFrom(timeNow)); |
|
1352 if (alarm.State() == EAlarmStateNotified && Abs(daysSinceLastExpired.Int()) >= KASSrvNumberOfDaysInOneWeek) |
|
1353 alarm.DeQueue(); |
|
1354 } |
|
1355 } |
|
1356 |
|
1357 /** |
|
1358 * Notify all alarm observers about the specified event. |
|
1359 */ |
|
1360 void CASSrvAlarmQueue::NotifyAlarmObserverEvent(MASSrvAlarmObserver::TObserverEvent aEvent, const TASSrvAlarm& aAlarm, TInt aEventSpecificData) |
|
1361 { |
|
1362 const TInt count = iAlarmObservers.Count(); |
|
1363 for(TInt i=0; i<count; i++) |
|
1364 { |
|
1365 TASSrvAlarmObserverMapplet& mapplet = iAlarmObservers[i]; |
|
1366 if (mapplet.IsEnabled()) |
|
1367 mapplet.Observer().MASSrvAlarmObsHandleEvent(aEvent, aAlarm, aEventSpecificData); |
|
1368 } |
|
1369 } |
|
1370 |
|
1371 /** |
|
1372 * @see MASSrvAlarmInfoProvider |
|
1373 */ |
|
1374 TInt CASSrvAlarmQueue::ASSrvAlarmInfoCount() const |
|
1375 { |
|
1376 return QueueAlarmCount(); |
|
1377 } |
|
1378 |
|
1379 /** |
|
1380 * @see MASSrvAlarmInfoProvider |
|
1381 */ |
|
1382 void CASSrvAlarmQueue::ASSrvAlarmInfoAt(TInt aIndex, TASSrvAlarm& aAlarm) const |
|
1383 { |
|
1384 aAlarm = QueueAlarmAt(aIndex); |
|
1385 } |
|
1386 |
|
1387 /** |
|
1388 * Register for notifications when the alarm queue order changes |
|
1389 */ |
|
1390 void CASSrvAlarmQueue::NotificationPoolChangeL(MASSrvAlarmQueueObserver& aObserver) |
|
1391 { |
|
1392 User::LeaveIfError(iNotificationList.InsertInAddressOrder(&aObserver)); |
|
1393 } |
|
1394 |
|
1395 /** |
|
1396 * Deregister for notifications when the alarm queue order changes |
|
1397 */ |
|
1398 void CASSrvAlarmQueue::NotificationPoolChangeCancel(MASSrvAlarmQueueObserver& aObserver) |
|
1399 { |
|
1400 TInt index = KErrNotFound; |
|
1401 const TInt error = iNotificationList.FindInAddressOrder(&aObserver, index); |
|
1402 if (error != KErrNotFound) |
|
1403 iNotificationList.Remove(index); |
|
1404 } |
|
1405 |
|
1406 /** |
|
1407 * Return the number of alarms currently maintained within the alarm pool |
|
1408 */ |
|
1409 TInt CASSrvAlarmQueue::QueueAlarmCount() const |
|
1410 { |
|
1411 return iAlarms.Count(); |
|
1412 } |
|
1413 |
|
1414 /** |
|
1415 * Return a reference to the alarm at the specified reference |
|
1416 */ |
|
1417 TASSrvAlarm& CASSrvAlarmQueue::QueueAlarmAt(TInt aIndex) |
|
1418 { |
|
1419 return *iAlarms[aIndex]; |
|
1420 } |
|
1421 |
|
1422 /** |
|
1423 * Return a constant reference to the alarm at the specified index |
|
1424 */ |
|
1425 const TASSrvAlarm& CASSrvAlarmQueue::QueueAlarmAt(TInt aIndex) const |
|
1426 { |
|
1427 return *iAlarms[aIndex]; |
|
1428 } |
|
1429 |
|
1430 /** |
|
1431 * Return a copy of an alarm. |
|
1432 */ |
|
1433 TInt CASSrvAlarmQueue::QueueAlarmById(TAlarmId aId, TASSrvAlarm& aAlarm) const |
|
1434 { |
|
1435 const TInt count = iAlarms.Count(); |
|
1436 for(TInt i=0; i<count; i++) |
|
1437 { |
|
1438 const TASSrvAlarm& alarm = QueueAlarmAt(i); |
|
1439 if (alarm.Id() == aId) |
|
1440 { |
|
1441 aAlarm = alarm; |
|
1442 return KErrNone; |
|
1443 } |
|
1444 } |
|
1445 |
|
1446 // No alarm available |
|
1447 return KErrNotFound; |
|
1448 } |
|
1449 |
|
1450 /** |
|
1451 * Returns a reference to a real alarm with the specified id. |
|
1452 */ |
|
1453 TASSrvAlarm* CASSrvAlarmQueue::QueueAlarmById(TAlarmId aId) |
|
1454 { |
|
1455 const TInt count = iAlarms.Count(); |
|
1456 for(TInt i=0; i<count; i++) |
|
1457 { |
|
1458 if (iAlarms[i]->Id() == aId) |
|
1459 return iAlarms[i]; |
|
1460 } |
|
1461 |
|
1462 return NULL; |
|
1463 } |
|
1464 |
|
1465 /** |
|
1466 * Returns a constant reference to a real alarm with the specified id. |
|
1467 */ |
|
1468 const TASSrvAlarm* CASSrvAlarmQueue::QueueAlarmById(TAlarmId aId) const |
|
1469 { |
|
1470 const TInt count = iAlarms.Count(); |
|
1471 for(TInt i=0; i<count; i++) |
|
1472 { |
|
1473 if (iAlarms[i]->Id() == aId) |
|
1474 return iAlarms[i]; |
|
1475 } |
|
1476 |
|
1477 return NULL; |
|
1478 } |
|
1479 |
|
1480 /** |
|
1481 * Returns a reference to a real alarm with the specified id. |
|
1482 */ |
|
1483 TASSrvAlarm& CASSrvAlarmQueue::QueueAlarmByIdL(TAlarmId aId) |
|
1484 { |
|
1485 TASSrvAlarm* alarm = QueueAlarmById(aId); |
|
1486 if (!alarm) |
|
1487 { |
|
1488 User::Leave(KErrNotFound); |
|
1489 } |
|
1490 return *alarm; |
|
1491 } |
|
1492 |
|
1493 /** |
|
1494 * Returns a constant reference to a real alarm with the specified id. |
|
1495 */ |
|
1496 const TASSrvAlarm& CASSrvAlarmQueue::QueueAlarmByIdL(TAlarmId aId) const |
|
1497 { |
|
1498 const TASSrvAlarm* alarm = QueueAlarmById(aId); |
|
1499 if (!alarm) |
|
1500 { |
|
1501 User::Leave(KErrNotFound); |
|
1502 } |
|
1503 return *alarm; |
|
1504 } |
|
1505 |
|
1506 /** |
|
1507 * Notify observers about an event |
|
1508 */ |
|
1509 void CASSrvAlarmQueue::NotifyEvent(MASSrvAlarmQueueObserver::TASSrvAlarmQueueEvent aEvent, TAlarmId aAlarmId) |
|
1510 { |
|
1511 const TInt count = iNotificationList.Count(); |
|
1512 for(TInt i=0; i<count; i++) |
|
1513 { |
|
1514 iNotificationList[i]->MAlarmQueueObserverHandleEvent(aEvent, aAlarmId); |
|
1515 } |
|
1516 } |
|
1517 |
|
1518 /** |
|
1519 * Replace one queue with another |
|
1520 */ |
|
1521 void CASSrvAlarmQueue::ReplaceQueueWithInternalizedQueue() |
|
1522 { |
|
1523 const TInt count = iAlarms.Count(); |
|
1524 for(TInt i=0; i<count; i++) |
|
1525 { |
|
1526 // If there was a notification request then we complete it |
|
1527 iAlarms[i]->CancelSessionAlarm(); |
|
1528 } |
|
1529 |
|
1530 // free memory used by old queue |
|
1531 iAlarms.ResetAndDestroy(); |
|
1532 |
|
1533 // assign from new buffer |
|
1534 iAlarms = iInternalizeAlarmQueue; |
|
1535 |
|
1536 // re-initialise source pointer array, by re-running its constructor |
|
1537 new(&iInternalizeAlarmQueue) RPointerArray<TASSrvAlarm>; |
|
1538 } |
|
1539 |
|
1540 /** |
|
1541 * Returns ETrue if there is at least one alarm in the "waiting to notify |
|
1542 * state" |
|
1543 */ |
|
1544 TBool CASSrvAlarmQueue::HaveAdditionalAlarmsToNotify() |
|
1545 { |
|
1546 // Create & open primary iterator |
|
1547 RASSrvIteratorByState primaryIterator(*this, EAlarmStateWaitingToNotify); |
|
1548 primaryIterator.Open(); |
|
1549 |
|
1550 // Create and attach secondary iterator |
|
1551 RASSrvIteratorByStatus secondaryIterator(*this, EAlarmStatusEnabled); |
|
1552 primaryIterator.IteratorAttach(secondaryIterator); |
|
1553 |
|
1554 return primaryIterator.NextAlarmAvailable(); |
|
1555 } |
|
1556 |
|
1557 /** |
|
1558 * Returns the number of alarms which are enabled and in the "waiting to |
|
1559 * notify state" |
|
1560 */ |
|
1561 TInt CASSrvAlarmQueue::NumberOfAlarmsPendingNotification() |
|
1562 { |
|
1563 // Create & open primary iterator |
|
1564 RASSrvIteratorByState primaryIterator(*this, EAlarmStateWaitingToNotify); |
|
1565 primaryIterator.Open(); |
|
1566 |
|
1567 // Create and attach secondary iterator |
|
1568 RASSrvIteratorByStatus secondaryIterator(*this, EAlarmStatusEnabled); |
|
1569 primaryIterator.IteratorAttach(secondaryIterator); |
|
1570 |
|
1571 TInt count = 0; |
|
1572 while(primaryIterator.NextAlarmAvailable()) |
|
1573 { |
|
1574 primaryIterator.NextAlarm(); |
|
1575 ++count; |
|
1576 } |
|
1577 |
|
1578 return count; |
|
1579 } |
|
1580 |
|
1581 /** |
|
1582 * Return a reference to the alarm which is next awaiting notification |
|
1583 */ |
|
1584 TASSrvAlarm& CASSrvAlarmQueue::NextAlarmWaitingForNotification() |
|
1585 { |
|
1586 // Create & open primary iterator |
|
1587 RASSrvIteratorByState primaryIterator(*this, EAlarmStateWaitingToNotify); |
|
1588 primaryIterator.Open(); |
|
1589 |
|
1590 // Create and attach secondary iterator |
|
1591 RASSrvIteratorByStatus secondaryIterator(*this, EAlarmStatusEnabled); |
|
1592 primaryIterator.IteratorAttach(secondaryIterator); |
|
1593 |
|
1594 // The most recent alarm is at the head of the queue. |
|
1595 // This will be the next one awaiting notification. |
|
1596 TAlarmId idOfFirstAlarm = KNullAlarmId; |
|
1597 if(primaryIterator.NextAlarmAvailable()) |
|
1598 { |
|
1599 idOfFirstAlarm = primaryIterator.NextAlarm().Id(); |
|
1600 } |
|
1601 |
|
1602 __ASSERT_ALWAYS(idOfFirstAlarm != KNullAlarmId, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicIteratorAlarmIdNull)); |
|
1603 return *QueueAlarmById(idOfFirstAlarm); |
|
1604 } |