|
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: |
|
14 // |
|
15 |
|
16 #include "ASSrvTimer.h" |
|
17 |
|
18 // System includes |
|
19 #include <e32base.h> |
|
20 |
|
21 // User includes |
|
22 #include "ASSrvStaticUtils.h" |
|
23 #include "ASSrvAlarmQueue.h" |
|
24 #include "ASSrvTimerObserver.h" |
|
25 #include "ASSrvServerWideData.h" |
|
26 #include "ASSrvAnyEventManager.h" |
|
27 |
|
28 // |
|
29 // ----> CASSrvAlarmTimer (source) |
|
30 // |
|
31 |
|
32 //************************************************************************************* |
|
33 CASSrvAlarmTimer::CASSrvAlarmTimer(CASSrvServerWideData& aServerWideData) |
|
34 : CTimer(CActive::EPriorityStandard), iServerWideData(aServerWideData), iNextDueAlarmId(KNullAlarmId), |
|
35 iInvalidatedByInternalize(EFalse) |
|
36 { |
|
37 CActiveScheduler::Add(this); |
|
38 } |
|
39 |
|
40 |
|
41 //************************************************************************************* |
|
42 CASSrvAlarmTimer::~CASSrvAlarmTimer() |
|
43 { |
|
44 ServerData().Queue().NotificationPoolChangeCancel(*this); |
|
45 iNotificationList.Close(); |
|
46 } |
|
47 |
|
48 |
|
49 //************************************************************************************* |
|
50 void CASSrvAlarmTimer::ConstructL() |
|
51 { |
|
52 CTimer::ConstructL(); |
|
53 ServerData().Queue().NotificationPoolChangeL(*this); |
|
54 } |
|
55 |
|
56 |
|
57 //************************************************************************************* |
|
58 CASSrvAlarmTimer* CASSrvAlarmTimer::NewL(CASSrvServerWideData& aServerWideData) |
|
59 { |
|
60 CASSrvAlarmTimer* self = new(ELeave) CASSrvAlarmTimer(aServerWideData); |
|
61 CleanupStack::PushL(self); |
|
62 self->ConstructL(); |
|
63 CleanupStack::Pop(self); |
|
64 return self; |
|
65 } |
|
66 |
|
67 |
|
68 // |
|
69 // |
|
70 // |
|
71 |
|
72 |
|
73 //************************************************************************************* |
|
74 /** |
|
75 * Request notifications when an alarm expires |
|
76 */ |
|
77 void CASSrvAlarmTimer::NotifyAlarmExpiredL(MASSrvAlarmTimerObserver& aObserver) |
|
78 { |
|
79 User::LeaveIfError(iNotificationList.InsertInAddressOrder(&aObserver)); |
|
80 } |
|
81 |
|
82 |
|
83 //************************************************************************************* |
|
84 /** |
|
85 * Cancel a previous notification request |
|
86 */ |
|
87 void CASSrvAlarmTimer::NotifyAlarmExpiredCancel(MASSrvAlarmTimerObserver& aObserver) |
|
88 { |
|
89 TInt index = KErrNotFound; |
|
90 const TInt error = iNotificationList.FindInAddressOrder(&aObserver, index); |
|
91 if (error != KErrNotFound) |
|
92 iNotificationList.Remove(index); |
|
93 } |
|
94 |
|
95 |
|
96 // |
|
97 // |
|
98 // |
|
99 |
|
100 |
|
101 //************************************************************************************* |
|
102 /** |
|
103 * @see MASSrvAlarmQueueObserver |
|
104 */ |
|
105 void CASSrvAlarmTimer::MAlarmQueueObserverHandleEvent(TASSrvAlarmQueueEvent aEvent, TAlarmId aAlarmId) |
|
106 { |
|
107 const TAlarmId previousDueAlarmId = iNextDueAlarmId; |
|
108 |
|
109 /* There two interesting events that we should look for: |
|
110 * Alarm Queue Start Internalize - everything we know is now invalid |
|
111 * Alarm Queue Head Item Changed - stop what we are doing, and see if/when |
|
112 * the next alarm is due. |
|
113 */ |
|
114 switch (aEvent) |
|
115 { |
|
116 case EASSrvAlarmQueueEventAlarmStartInternalize: |
|
117 // stop processing alarm queue, (until a new head alarm appears) |
|
118 Cancel(); |
|
119 // RunL could have started already (it waits for an Access Token) |
|
120 // and would be processing an invalid head alarm! |
|
121 iInvalidatedByInternalize = ETrue; |
|
122 break; |
|
123 |
|
124 case EASSrvAlarmQueueEventHeadItemChanged: |
|
125 { |
|
126 // The next alarm has changed. |
|
127 Cancel(); |
|
128 |
|
129 // head alarm is valid |
|
130 iInvalidatedByInternalize = EFalse; |
|
131 |
|
132 // Set ourselves up for the next alarm, assuming there is one. |
|
133 CASSrvAlarmQueue& queue = ServerData().Queue(); |
|
134 const TASSrvAlarm* nextDueAlarm = queue.HeadAlarm(); |
|
135 if (nextDueAlarm && aAlarmId != KNullAlarmId) |
|
136 { |
|
137 __ASSERT_DEBUG(nextDueAlarm->Id() != KNullAlarmId, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicQueueAlarmIdNull)); |
|
138 |
|
139 // Convert alarm time to local time |
|
140 TTime dueTime = nextDueAlarm->NextDueTime(); |
|
141 |
|
142 // Get current time |
|
143 const TTime now(ASSrvStaticUtils::UtcTimeNow()); |
|
144 |
|
145 // Expire now (if the alarm is in the past), or when the alarm |
|
146 // is really due (if it's in the future). |
|
147 TTime t = dueTime > now? dueTime : now; |
|
148 |
|
149 |
|
150 AtUTC(t); |
|
151 |
|
152 // Update next due alarm id and original due time |
|
153 iOriginalExpiryTimeForAlarm = dueTime; |
|
154 iNextDueAlarmId = aAlarmId; |
|
155 } |
|
156 } |
|
157 break; |
|
158 |
|
159 default: // don't care about other events |
|
160 return; |
|
161 } |
|
162 |
|
163 // Notify change |
|
164 if (iNextDueAlarmId != previousDueAlarmId) |
|
165 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventHeadQueueItemChanged, iNextDueAlarmId); |
|
166 } |
|
167 |
|
168 |
|
169 // |
|
170 // |
|
171 // |
|
172 |
|
173 |
|
174 //************************************************************************************* |
|
175 /** |
|
176 * @see CActive |
|
177 */ |
|
178 void CASSrvAlarmTimer::RunL() |
|
179 { |
|
180 // Cache this, so that notifications can queue the next alarm with the |
|
181 // timer. |
|
182 const TAlarmId justExpiredAlarmId = iNextDueAlarmId; |
|
183 |
|
184 // Set this back to KNullAlarmId indicating that we don't (yet) have another |
|
185 // alarm to notify about. We must do this just in case there aren't any more |
|
186 // suitable alarms in the queue, otherwise we will always indicate that we |
|
187 // are notifying about an (already) notified alarm. |
|
188 iNextDueAlarmId = KNullAlarmId; |
|
189 |
|
190 // check that Internalize hasn't invalidated the head alarm |
|
191 if (!iInvalidatedByInternalize && (iNextDueAlarmId == KNullAlarmId)) |
|
192 { |
|
193 const TInt errorStatus = iStatus.Int(); |
|
194 switch(errorStatus) |
|
195 { |
|
196 // Time changed - RChangeNotifier for time changes only used if no alarm is set. |
|
197 case KErrAbort: |
|
198 NotifyEvent(MASSrvAlarmTimerObserver::EAlarmTimerEventTimeOrDateChanged, KNullAlarmId); |
|
199 break; |
|
200 |
|
201 // Ignore times set in the past |
|
202 case KErrUnderflow: |
|
203 case KErrNone: |
|
204 if (!iInvalidatedByInternalize) |
|
205 NotifyEvent(MASSrvAlarmTimerObserver::EAlarmTimerEventAlarmExpired, justExpiredAlarmId); |
|
206 break; |
|
207 |
|
208 // No timer reset if the date is close to the overflow range. |
|
209 // This means that agenda will not get notified of time changes |
|
210 case KErrOverflow: |
|
211 |
|
212 // Fall through to error handler |
|
213 default: |
|
214 HandleTimerError(justExpiredAlarmId, errorStatus); |
|
215 NotifyEvent(MASSrvAlarmTimerObserver::EAlarmTimerEventTimingError, justExpiredAlarmId); |
|
216 break; |
|
217 } |
|
218 |
|
219 // Notify change |
|
220 ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventTimerExpired, justExpiredAlarmId); |
|
221 } |
|
222 } |
|
223 |
|
224 |
|
225 //************************************************************************************* |
|
226 /** |
|
227 * @see CActive |
|
228 */ |
|
229 void CASSrvAlarmTimer::Cancel() |
|
230 { |
|
231 CTimer::Cancel(); |
|
232 // |
|
233 iNextDueAlarmId = KNullAlarmId; |
|
234 iOriginalExpiryTimeForAlarm = Time::NullTTime(); |
|
235 } |
|
236 |
|
237 |
|
238 //************************************************************************************* |
|
239 /** |
|
240 * @see CActive |
|
241 */ |
|
242 TInt CASSrvAlarmTimer::RunError(TInt /*aError*/) |
|
243 { |
|
244 // Ignore erorrs |
|
245 return KErrNone; |
|
246 } |
|
247 |
|
248 |
|
249 // |
|
250 // |
|
251 // |
|
252 |
|
253 |
|
254 //************************************************************************************* |
|
255 /** |
|
256 * Notify observers about the specified event |
|
257 */ |
|
258 void CASSrvAlarmTimer::NotifyEvent(MASSrvAlarmTimerObserver::TAlarmTimerEvent aEvent, TAlarmId aId) |
|
259 { |
|
260 for(TInt i=iNotificationList.Count(); i>0; --i) |
|
261 // Notify observers |
|
262 // TASSrvAlarm::MATimerHandleAlarmExpired() removes itself from the list |
|
263 iNotificationList[i-1]->MATimerHandleAlarmExpired(aEvent, aId); |
|
264 } |
|
265 |
|
266 |
|
267 //************************************************************************************* |
|
268 /** |
|
269 * Handle an error returned in CTimer::iStatus |
|
270 */ |
|
271 void CASSrvAlarmTimer::HandleTimerError(TAlarmId aIdOfJustExpiredAlarm, TInt aErrorCode) |
|
272 { |
|
273 CASSrvAlarmQueue& queue = ServerData().Queue(); |
|
274 TASSrvAlarm* expiredAlarm = queue.QueueAlarmById(aIdOfJustExpiredAlarm); |
|
275 expiredAlarm->HandleTimerError(aErrorCode); |
|
276 } |