--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commonappservices/alarmserver/Server/Source/ASSrvTimer.cpp Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,276 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "ASSrvTimer.h"
+
+// System includes
+#include <e32base.h>
+
+// User includes
+#include "ASSrvStaticUtils.h"
+#include "ASSrvAlarmQueue.h"
+#include "ASSrvTimerObserver.h"
+#include "ASSrvServerWideData.h"
+#include "ASSrvAnyEventManager.h"
+
+//
+// ----> CASSrvAlarmTimer (source)
+//
+
+//*************************************************************************************
+CASSrvAlarmTimer::CASSrvAlarmTimer(CASSrvServerWideData& aServerWideData)
+: CTimer(CActive::EPriorityStandard), iServerWideData(aServerWideData), iNextDueAlarmId(KNullAlarmId),
+ iInvalidatedByInternalize(EFalse)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+
+//*************************************************************************************
+CASSrvAlarmTimer::~CASSrvAlarmTimer()
+ {
+ ServerData().Queue().NotificationPoolChangeCancel(*this);
+ iNotificationList.Close();
+ }
+
+
+//*************************************************************************************
+void CASSrvAlarmTimer::ConstructL()
+ {
+ CTimer::ConstructL();
+ ServerData().Queue().NotificationPoolChangeL(*this);
+ }
+
+
+//*************************************************************************************
+CASSrvAlarmTimer* CASSrvAlarmTimer::NewL(CASSrvServerWideData& aServerWideData)
+ {
+ CASSrvAlarmTimer* self = new(ELeave) CASSrvAlarmTimer(aServerWideData);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+//
+//
+//
+
+
+//*************************************************************************************
+/**
+ * Request notifications when an alarm expires
+ */
+void CASSrvAlarmTimer::NotifyAlarmExpiredL(MASSrvAlarmTimerObserver& aObserver)
+ {
+ User::LeaveIfError(iNotificationList.InsertInAddressOrder(&aObserver));
+ }
+
+
+//*************************************************************************************
+/**
+ * Cancel a previous notification request
+ */
+void CASSrvAlarmTimer::NotifyAlarmExpiredCancel(MASSrvAlarmTimerObserver& aObserver)
+ {
+ TInt index = KErrNotFound;
+ const TInt error = iNotificationList.FindInAddressOrder(&aObserver, index);
+ if (error != KErrNotFound)
+ iNotificationList.Remove(index);
+ }
+
+
+//
+//
+//
+
+
+//*************************************************************************************
+/**
+ * @see MASSrvAlarmQueueObserver
+ */
+void CASSrvAlarmTimer::MAlarmQueueObserverHandleEvent(TASSrvAlarmQueueEvent aEvent, TAlarmId aAlarmId)
+ {
+ const TAlarmId previousDueAlarmId = iNextDueAlarmId;
+
+ /* There two interesting events that we should look for:
+ * Alarm Queue Start Internalize - everything we know is now invalid
+ * Alarm Queue Head Item Changed - stop what we are doing, and see if/when
+ * the next alarm is due.
+ */
+ switch (aEvent)
+ {
+ case EASSrvAlarmQueueEventAlarmStartInternalize:
+ // stop processing alarm queue, (until a new head alarm appears)
+ Cancel();
+ // RunL could have started already (it waits for an Access Token)
+ // and would be processing an invalid head alarm!
+ iInvalidatedByInternalize = ETrue;
+ break;
+
+ case EASSrvAlarmQueueEventHeadItemChanged:
+ {
+ // The next alarm has changed.
+ Cancel();
+
+ // head alarm is valid
+ iInvalidatedByInternalize = EFalse;
+
+ // Set ourselves up for the next alarm, assuming there is one.
+ CASSrvAlarmQueue& queue = ServerData().Queue();
+ const TASSrvAlarm* nextDueAlarm = queue.HeadAlarm();
+ if (nextDueAlarm && aAlarmId != KNullAlarmId)
+ {
+ __ASSERT_DEBUG(nextDueAlarm->Id() != KNullAlarmId, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicQueueAlarmIdNull));
+
+ // Convert alarm time to local time
+ TTime dueTime = nextDueAlarm->NextDueTime();
+
+ // Get current time
+ const TTime now(ASSrvStaticUtils::UtcTimeNow());
+
+ // Expire now (if the alarm is in the past), or when the alarm
+ // is really due (if it's in the future).
+ TTime t = dueTime > now? dueTime : now;
+
+
+ AtUTC(t);
+
+ // Update next due alarm id and original due time
+ iOriginalExpiryTimeForAlarm = dueTime;
+ iNextDueAlarmId = aAlarmId;
+ }
+ }
+ break;
+
+ default: // don't care about other events
+ return;
+ }
+
+ // Notify change
+ if (iNextDueAlarmId != previousDueAlarmId)
+ ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventHeadQueueItemChanged, iNextDueAlarmId);
+ }
+
+
+//
+//
+//
+
+
+//*************************************************************************************
+/**
+ * @see CActive
+ */
+void CASSrvAlarmTimer::RunL()
+ {
+ // Cache this, so that notifications can queue the next alarm with the
+ // timer.
+ const TAlarmId justExpiredAlarmId = iNextDueAlarmId;
+
+ // Set this back to KNullAlarmId indicating that we don't (yet) have another
+ // alarm to notify about. We must do this just in case there aren't any more
+ // suitable alarms in the queue, otherwise we will always indicate that we
+ // are notifying about an (already) notified alarm.
+ iNextDueAlarmId = KNullAlarmId;
+
+ // check that Internalize hasn't invalidated the head alarm
+ if (!iInvalidatedByInternalize && (iNextDueAlarmId == KNullAlarmId))
+ {
+ const TInt errorStatus = iStatus.Int();
+ switch(errorStatus)
+ {
+ // Time changed - RChangeNotifier for time changes only used if no alarm is set.
+ case KErrAbort:
+ NotifyEvent(MASSrvAlarmTimerObserver::EAlarmTimerEventTimeOrDateChanged, KNullAlarmId);
+ break;
+
+ // Ignore times set in the past
+ case KErrUnderflow:
+ case KErrNone:
+ if (!iInvalidatedByInternalize)
+ NotifyEvent(MASSrvAlarmTimerObserver::EAlarmTimerEventAlarmExpired, justExpiredAlarmId);
+ break;
+
+ // No timer reset if the date is close to the overflow range.
+ // This means that agenda will not get notified of time changes
+ case KErrOverflow:
+
+ // Fall through to error handler
+ default:
+ HandleTimerError(justExpiredAlarmId, errorStatus);
+ NotifyEvent(MASSrvAlarmTimerObserver::EAlarmTimerEventTimingError, justExpiredAlarmId);
+ break;
+ }
+
+ // Notify change
+ ServerData().AnyEventManager().MASAnyEventManagerObserverNotifyChanges(EAlarmChangeEventTimerExpired, justExpiredAlarmId);
+ }
+ }
+
+
+//*************************************************************************************
+/**
+ * @see CActive
+ */
+void CASSrvAlarmTimer::Cancel()
+ {
+ CTimer::Cancel();
+ //
+ iNextDueAlarmId = KNullAlarmId;
+ iOriginalExpiryTimeForAlarm = Time::NullTTime();
+ }
+
+
+//*************************************************************************************
+/**
+ * @see CActive
+ */
+TInt CASSrvAlarmTimer::RunError(TInt /*aError*/)
+ {
+ // Ignore erorrs
+ return KErrNone;
+ }
+
+
+//
+//
+//
+
+
+//*************************************************************************************
+/**
+ * Notify observers about the specified event
+ */
+void CASSrvAlarmTimer::NotifyEvent(MASSrvAlarmTimerObserver::TAlarmTimerEvent aEvent, TAlarmId aId)
+ {
+ for(TInt i=iNotificationList.Count(); i>0; --i)
+ // Notify observers
+ // TASSrvAlarm::MATimerHandleAlarmExpired() removes itself from the list
+ iNotificationList[i-1]->MATimerHandleAlarmExpired(aEvent, aId);
+ }
+
+
+//*************************************************************************************
+/**
+ * Handle an error returned in CTimer::iStatus
+ */
+void CASSrvAlarmTimer::HandleTimerError(TAlarmId aIdOfJustExpiredAlarm, TInt aErrorCode)
+ {
+ CASSrvAlarmQueue& queue = ServerData().Queue();
+ TASSrvAlarm* expiredAlarm = queue.QueueAlarmById(aIdOfJustExpiredAlarm);
+ expiredAlarm->HandleTimerError(aErrorCode);
+ }