--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendar/server/src/agsalarm.cpp Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,806 @@
+// Copyright (c) 1997-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 "agsalarm.h"
+#include "agmutil.h"
+#include "agssortinstance.h"
+#include "agmentry.h"
+#include "agsentrymodel.h"
+#include "agmtlsproxy.h"
+#include "agmdebug.h"
+#include "agsfilemanager.h"
+#include "agsmain.h"
+#include <centralrepository.h>
+#include <f32file.h>
+#include <txtetext.h>
+#include <tz.h>
+
+// This is used when the system time is put forward. All alarms within KSystemTimeChangeMaxDaysOld of
+// the new/present time will be queued. If set to 1, and the time is put forward by 7 days then only
+// alarms within 1 day of the new time will be queued.
+// (Note: This may need to be changed to a TTime in the future if greater granularity is required.)
+const TInt KSystemTimeChangeMaxDaysOld = 1;
+
+// Maximum number of event alarms to be scheduled when the system time/date changes. Ideally there
+// shouldn't be a maximum but the existing API FindAndQueueNextFewAlarmsL takes has a
+// maximum parameter. This should be set to MAX_INT.
+// (Note: This is the same default value used in the method CAgnAlarm::FindAndQueueNextFewAlarmsL)
+const TInt KSystemTimeChangeMaxAlarmsQueued = 0xffff;
+
+
+// Central Repository Uid
+const TUid KUidCentralRepositoryAgenda = { 0x10003a5b };
+
+//Used for configuration of whether or not to notify missing alarms
+const TUint KKeyQueueMissingAlarm = 100;
+CAgnAlarm::CAgnAlarm(RASCliSession& aRASCliSession)
+ :iAlarmServer(aRASCliSession)
+ {
+ }
+CAgnAlarm* CAgnAlarm::NewL(CAgnEntryModel* aModel,MAgnAlarmServerTerminationCallBack* aCallBack)
+/** Allocates and constructs a CAgnAlarm object and makes a connection to
+the alarm server.
+
+@internalAll
+@param aModel Pointer to the agenda model which the alarm server connection
+is being set up for.
+@param aCallBack An optional alarm server termination callback provider. May be NULL.
+@return Pointer to the newly created alarm server interface object. */
+ {
+ CAgnAlarm* self = new (ELeave) CAgnAlarm(aModel->AgnServFile().Server().AlarmServer());
+
+ CleanupStack::PushL(self);
+ self->ConstructL(aModel,aCallBack);
+ CleanupStack::Pop();
+
+ return (self);
+ }
+
+void CAgnAlarm::DeleteAllAlarms()
+ {
+ // ignore any errors returned from this
+ TParsePtrC parser(iAlarm->AgnServFile().FileName());
+ TFileName fileName = parser.Drive();
+ fileName.Append(parser.NameAndExt());
+ iAlarmServer.AlarmDeleteByCalendarFile(fileName, EFuture|EExpired);
+ }
+
+void CAgnAlarm::ConstructL(CAgnEntryModel* aModel,MAgnAlarmServerTerminationCallBack* aCallBack)
+//
+// Construct CAgnAlarm
+//
+ {
+ iAlarm = CAgnAlarmActive::NewL(aModel,iAlarmServer);
+ iChangeObserver = CAgnAlarmServerChangeObserver::NewL(aCallBack,this);
+
+ iQueueAlarmsInPast = 1;
+ CRepository* repository = NULL;
+ TRAPD(err, repository = CRepository::NewL(KUidCentralRepositoryAgenda));
+ if (err == KErrNone && repository)
+ {
+ CleanupStack::PushL(repository);
+ User::LeaveIfError(repository->Get(KKeyQueueMissingAlarm, iQueueAlarmsInPast));
+ CleanupStack::PopAndDestroy(repository);
+ }
+
+ iAlarm->SetQueueAlarmsInPast(iQueueAlarmsInPast);
+ }
+
+TBool CAgnAlarm::QueueAlarmsInPast()
+ {
+ return iQueueAlarmsInPast;
+ }
+
+ CAgnAlarm::~CAgnAlarm()
+/** Frees all resources owned by the object, prior to its destruction,
+and ends the session with the alarm server.
+@internalAll
+*/
+ {
+ delete iAlarm;
+ delete iChangeObserver;
+ }
+
+void CAgnAlarm::OrphanAlarm()
+/** Orphans the session alarm.
+
+This allows the alarm to be serviced after the session is closed. This
+function should be called by the user of the model before closing an
+agenda file.
+
+@internalAll
+*/
+ {
+ iAlarm->OrphanAlarm();
+ }
+
+/** Finds the agenda model's next due alarm.
+
+If a due alarm is found, it is set as the session alarm and queued
+with the alarm server.
+
+This function should be called by the client immediately after the CAgnAlarm object is created.
+
+@internalAll
+@capability WriteUserData
+*/
+void CAgnAlarm::FindAndQueueNextAlarmL(TBool aSysTimeHasChanged)
+ {
+ iAlarm->FindAndQueueNextAlarmL(aSysTimeHasChanged);
+ }
+
+void CAgnAlarm::QueueNextAlarmL(CArrayFixFlat<TAgnSortInstance>*aAlarmedIds)
+ {
+ iAlarm->QueueNextAlarmL(aAlarmedIds);
+ }
+
+void CAgnAlarm::FindAndQueueNextFewAlarmsL(const TInt aMaxNumberOfAlarms,const TInt aMaxNumberOfDays)
+/** Finds the agenda model's next few alarms.
+
+If one or more due alarms are found, they are set as session alarms
+and queued with the alarm server.
+
+This method is no longer required by the client because the alarms are now queued
+by the agenda server once the last session is disconnected to it.
+
+@internalAll
+@param aMaxNumberOfAlarms The maximum number of alarms to be queued. The default
+value is 10.
+@param aMaxNumberOfDays The maximum number of days to be scanned for alarms.
+The default value is 31. */
+ {
+ iAlarm->FindAndQueueNextFewAlarmsL(aMaxNumberOfAlarms, aMaxNumberOfDays);
+ }
+
+
+void CAgnAlarm::FindAndQueueNextFewAlarmsL(const TTime& startTime,const TTime& endTime,const TInt aMaxNumberOfAlarms)
+/* Finds the agenda model's next few alarms.
+
+If one or more due alarms are found, they are set as session alarms
+and queued with the alarm server.
+
+(Note: This method was added to handle system date/time changes. It is not currently exported, however
+ the less general version which takes aMaxNumberOfDays can be used for most purposes. */
+ {
+ iAlarm->FindAndQueueNextFewAlarmsL(startTime,endTime,aMaxNumberOfAlarms);
+ }
+
+/* Gets the TAgnAlarmEntry struct
+
+*/
+const TAgnAlarmEntry* CAgnAlarm::AlarmEntry() const
+ {
+ return ( iAlarm->CurrentAlarmEntry() );
+ }
+
+void CAgnAlarm::DeleteEntriesAlarmL(const TAgnEntryId& aEntryId)
+ //Removes all of an entry's alarms from the alarm server.
+ //First, obtain a list of alarms from the alarmserver.
+ //Compare aEntryInstanceId to the TAgnEntryId of the alarm in the queue.
+ //if they are the same then the alarm server is asked to remove the alarm from the queue.
+ {
+ RArray<TAlarmId> snoozedAlarmIds;
+ CleanupClosePushL(snoozedAlarmIds);
+
+ iAlarmServer.GetAlarmIdListForCategoryL(KUidAgendaModelAlarmCategory, snoozedAlarmIds);
+
+ if( snoozedAlarmIds.Count() > 0 )
+ {
+ for( TInt i = 0; i < snoozedAlarmIds.Count(); ++i )
+ {
+ //get the info for this alarm id
+ TBuf8<sizeof(TAgnAlarmInfo)> alarmInfoBuf;
+
+ iAlarmServer.GetAlarmData(snoozedAlarmIds[i],alarmInfoBuf);
+
+ const TAgnAlarmInfo* alarmInfo = reinterpret_cast<const TAgnAlarmInfo*>(alarmInfoBuf.Ptr());
+ if ( alarmInfo->iEntryId == aEntryId )
+ {
+ iAlarmServer.AlarmNotificationCancelAndDequeue(snoozedAlarmIds[i]);
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(&snoozedAlarmIds);
+ }
+#ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
+void CAgnAlarm::DeleteAlarmsAndRequeueSessionAlarmL()
+ {
+ iAlarmServer.AlarmDeleteByCategory(KUidAgendaModelAlarmCategory, EFuture|EExpired);
+ FindAndQueueNextAlarmL(EFalse);
+ }
+#endif
+
+const CAgnServFile& CAgnAlarm::AgnServFile()
+ {
+ return iAlarm->AgnServFile();
+ }
+
+CAgnAlarmServerChangeObserver& CAgnAlarm::ChangeObserver()
+ {
+ return *iChangeObserver;
+ }
+
+CAgnAlarmActive* CAgnAlarmActive::NewL(CAgnEntryModel* aModel,RASCliSession& aAlarmServer)
+//
+// Create a CAgnAlarmActive object and connect to the alarm server.
+//
+ {
+
+ CAgnAlarmActive* self=new(ELeave)CAgnAlarmActive(EPriority,aAlarmServer);
+
+ CleanupStack::PushL(self);
+ self->iAlarmList=new(ELeave)CArrayFixFlat<TAgnAlarmEntry>(EGranularity);
+ CleanupStack::Pop();
+
+ self->iModel = aModel;
+ CActiveScheduler::Add(self);
+
+ return ( self );
+ }
+
+CAgnAlarmActive::CAgnAlarmActive(TInt aPriority,RASCliSession& aAlarmServer)
+//
+// Constructor
+//
+ : CActive(aPriority), iAlarmServer(aAlarmServer)
+ {
+ }
+
+
+void CAgnAlarmActive::OrphanAlarm()
+//
+// If there's currently an alarm queued with the alarm server then orphan it.
+//
+ {
+
+ if ( IsActive() )
+ {
+ // Changing the characteristics of the alarm from SessionSpecific to
+ // non-session specific means the alarm ownership is transferred from
+ // this session to the alarm server.
+ //
+ // Calling this completes the pending request with KErrCancel
+ TAlarmCharacteristicsFlags alarmCharacteristicsFlags;
+ iAlarmServer.GetAlarmCharacteristics(iAlarm.Id(), alarmCharacteristicsFlags);
+ alarmCharacteristicsFlags.Clear(EAlarmCharacteristicsSessionSpecific);
+ iAlarmServer.SetAlarmCharacteristics(iAlarm.Id(), alarmCharacteristicsFlags);
+ }
+
+ Cancel();
+ }
+
+
+CAgnAlarmActive::~CAgnAlarmActive()
+//
+// If active then an alarm must be outstanding so create an orphan from it then cancel it.
+//
+ {
+ OrphanAlarm();
+ delete iAlarmList;
+ }
+
+
+void CAgnAlarmActive::RunL()
+//
+// The alarm server signals iRequestStatus in the following situations:
+// - KErrNone when the alarm has expired
+// - KErrCancel when the alarm has been canceled
+//
+ {
+
+ if ( iStatus == KErrNone ) // an alarm has expired
+ {
+ __ASSERT_DEBUG(iAlarmList->Count()>0, Panic(EAgmNoAlarmsInList)); // the alarm which has just gone off should be in the alarm list
+
+ if ( ++iAlarmListIndex < iAlarmList->Count() )
+ // if there is another entry with the same alarm time as the one which has just gone off then
+ // queue it with the alarm server (its time will now be in the past so it'll go off immediately)
+ {
+ const TAgnAlarmEntry& alarmEntry = (*iAlarmList)[iAlarmListIndex];
+
+ // Create and queue an alarm with the Alarm Server
+ InitialiseAlarmL(iAlarm,alarmEntry,ETrue);
+ TAgnAlarmInfo alarmInfo;
+ GetAlarmInfoL(alarmEntry.iInstanceId, alarmInfo);
+
+ _DBGLOG_ALARM(AgmDebug::DebugLog("Alarm expired/cancelled. Queueing next alarm:");)
+ _DBGLOG_ALARM(AgmDebug::DebugLogAlarmL(alarmEntry);)
+
+ TPkgCAgnAlarmInfo pkgAgendaRef(alarmInfo);
+ SetActive();
+ iAlarmServer.AlarmAddWithNotification(iStatus, iAlarm, pkgAgendaRef);
+
+ if ( iAlarm.Id() == KNullAlarmId )
+ {
+ User::Leave(KErrGeneral);
+ }
+ }
+ else
+ {
+ FindAndQueueNextAlarmL(EFalse);
+ }
+ }
+ else if( iStatus == KErrCancel )
+ {
+ DoCancel();
+ }
+ }
+
+
+TBool CAgnAlarmActive::AssignToL(TAgnAlarmEntry& aAlarmEntry, const TAgnSortInstance& aSortInstance)
+// assign data to the passed alarm entry
+// Used by QueueNextAlarmL and FindAndQueueNextFewAlarmsL
+
+ {
+ aAlarmEntry.iDueDateTimeLocal = aSortInstance.iStartTimeLocal;
+
+ //to get text in this entry
+ CAgnEntry* entry = iModel->FetchEntryL(aSortInstance.SimpleEntry().EntryId());
+ if (! entry)
+ {
+ return EFalse;
+ }
+
+ CleanupStack::PushL(entry);
+
+ if ( entry->RptDef() && !entry->RptDef()->IsAnUnexceptedInstanceL(aSortInstance.InstanceDate()) )
+ {
+ // the entry should be not excepted
+ _DBGLOG_ALARM(AgmDebug::DebugLog("Alarm: PANIC - Invalid Instance: The entry should be not excepted"));
+ _DBGLOG_ALARM(AgmDebug::DebugLogEntryL(*entry, EDumpEntryAll);)
+ DBG_PANIC(EAgmErrInvalidInstance);
+ User::Leave(KErrNotFound);
+ }
+
+ TAgnCalendarTime instanceDate;
+ if (entry->TimeMode() == MAgnCalendarTimeMode::EFloating)
+ {
+ aAlarmEntry.iAlarmTime.SetFloatingL(aSortInstance.InstanceAlarmDateTime());
+ instanceDate.SetFloatingL(aSortInstance.InstanceDate());
+ }
+ else
+ {
+ aAlarmEntry.iAlarmTime.SetLocalL(aSortInstance.InstanceAlarmDateTime());
+ instanceDate.SetLocalL(aSortInstance.InstanceDate());
+ }
+ aAlarmEntry.iInstanceId.SetEntryId(entry->EntryId());
+ aAlarmEntry.iInstanceId.SetDate(instanceDate);
+
+ if ( !entry->SummaryIsLoaded() )
+ {
+ entry->SetSummary(iModel->RestoreTextL(entry->SummaryStreamId()));
+ }
+
+ TInt len = entry->Summary().Length();
+
+ if ( len > KMaxAlarmMessageLength )
+ {
+ len = KMaxAlarmMessageLength;
+ }
+
+ aAlarmEntry.iMessage = KNullDesC;
+
+ for ( TInt ii = 0; ii < len; ++ii )
+ {
+ TChar ch(entry->Summary()[ii]);
+ switch (ch)
+ {
+ case CEditableText::EParagraphDelimiter :
+ case CEditableText::ELineBreak :
+ case CEditableText::EPageBreak :
+ case CEditableText::ETabCharacter :
+ case CEditableText::ENonBreakingHyphen :
+ case CEditableText::EPotentialHyphen :
+ case CEditableText::ENonBreakingSpace :
+ case CEditableText::EPictureCharacter :
+ aAlarmEntry.iMessage.Append(CEditableText::ESpace);
+ continue;
+ }
+ aAlarmEntry.iMessage.Append(ch);
+ }
+
+ aAlarmEntry.iSound = entry->AlarmSoundName();
+
+ CleanupStack::PopAndDestroy(); //entry
+
+ return ETrue;
+ }
+
+/** Find the next due alarm(s) with same time and if at least one exists then queue it with the alarm server
+@capability WriteUserData
+*/
+void CAgnAlarmActive::FindAndQueueNextAlarmL(TBool aSysTimeHasChanged)
+ {
+ TTime now;
+ now.HomeTime();
+
+ // Certainly on WINS an alarm may expire a few seconds before it is due, the
+ // following ensures that the same alarm isn't queued twice
+ // If system time has been changed, we don't want to increase "now" to make sure
+ // that the alarm whoes due time same as "now" is found.
+ const TInt KAlarmCount = iAlarmList->Count();
+ if ( KAlarmCount && !aSysTimeHasChanged)
+ {
+ TTime lastAlarm = (*iAlarmList)[KAlarmCount-1].iAlarmTime.LocalL();
+
+ if ( now < lastAlarm )
+ {
+ now += TTimeIntervalSeconds(1);
+ }
+ }
+
+ iAlarmList->Reset();
+
+ CArrayFixFlat<TAgnSortInstance>* alarmedIds = new (ELeave) CArrayFixFlat<TAgnSortInstance>(2);
+ CleanupStack::PushL(alarmedIds);
+
+ iModel->NextAlarmForServerL(now, *alarmedIds);
+ QueueNextAlarmL(alarmedIds);
+
+ CleanupStack::PopAndDestroy(alarmedIds);
+ }
+
+void CAgnAlarmActive::QueueNextAlarmL(CArrayFixFlat<TAgnSortInstance>* aAlarmedIds)
+// This function is only called by the server side since we want the alarm is queued in only server side
+ {
+ TTime now;
+ now.HomeTime();
+
+ // Certainly on WINS an alarm may expire a few seconds before it is due, the
+ // following ensures that the same alarm isn't queued twice
+ const TInt KAlarmCount = iAlarmList->Count();
+ if ( KAlarmCount )
+ {
+ TTime lastAlarm = (*iAlarmList)[KAlarmCount-1].iAlarmTime.LocalL();
+
+ if ( now < lastAlarm )
+ {
+ now += TTimeIntervalSeconds(1);
+ }
+ }
+
+ iAlarmList->Reset();
+
+ for ( TInt ii = aAlarmedIds->Count() - 1; ii >= 0; --ii )
+ {
+ //create an alarmEntry
+ TAgnAlarmEntry alarmEntry;
+
+ if (AssignToL(alarmEntry, (*aAlarmedIds)[ii]))
+ {
+ TKeyArrayFix key(_FOFF(TAgnAlarmEntry, iInstanceId), ECmpNormal8, sizeof(TAgnInstanceId));
+ iAlarmList->InsertIsqAllowDuplicatesL(alarmEntry, key);
+ }
+ }
+
+ Cancel();
+
+ if ( iAlarmList->Count() )
+ // Queue the first alarm in the alarm list
+ {
+ __ASSERT_DEBUG(IsAdded(), Panic(EAgmAgnAlarmActiveNotAdded));
+ iAlarmListIndex = 0;
+ const TAgnAlarmEntry& alarmEntry = (*iAlarmList)[0];
+
+ InitialiseAlarmL(iAlarm, alarmEntry, ETrue);
+
+ TAgnAlarmInfo alarmInfo;
+ GetAlarmInfoL(alarmEntry.iInstanceId, alarmInfo);
+
+ _DBGLOG_ALARM(AgmDebug::DebugLog("Queueing first alarm on list:");)
+ _DBGLOG_ALARM(AgmDebug::DebugLogAlarmL(alarmEntry);)
+
+ TPkgCAgnAlarmInfo pkgAgendaRef(alarmInfo);
+ SetActive();
+ iAlarmServer.AlarmAddWithNotification(iStatus, iAlarm, pkgAgendaRef);
+
+ if ( iAlarm.Id() == KNullAlarmId )
+ {
+ User::Leave(KErrGeneral);
+ }
+ }
+ }
+
+void CAgnAlarmActive::InitialiseAlarmL(TASShdAlarm& aAlarm, const TAgnAlarmEntry& aEntryAlarm, TBool aIsSessionAlarm)
+ {
+ aAlarm.Reset();
+ aAlarm.Message() = aEntryAlarm.iMessage;
+ aAlarm.Category() = KUidAgendaModelAlarmCategory;
+ aAlarm.SoundName() = aEntryAlarm.iSound;
+ aAlarm.DayOrTimed() = aEntryAlarm.iSessionType;
+
+ if (aEntryAlarm.iAlarmTime.TimeMode() == MAgnCalendarTimeMode::EFloating)
+ {
+ aAlarm.NextDueTime() = aEntryAlarm.iAlarmTime.LocalL();
+ }
+ else
+ {
+ aAlarm.SetUtcNextDueTime(aEntryAlarm.iAlarmTime.UtcL());
+ }
+
+ if ( aIsSessionAlarm )
+ {
+ aAlarm.Characteristics().Set(EAlarmCharacteristicsSessionSpecific);
+ }
+
+ if (!iQueueAlarmsInPast)
+ {
+ aAlarm.Characteristics().Set(EAlarmCharacteristicsDeQueueIfDueTimeInPast);
+ }
+ }
+
+void CAgnAlarmActive::FindAndQueueNextFewAlarmsL(const TInt aMaxNumberOfAlarms,const TInt aMaxNumberOfDays)
+ {
+ TTime now;
+ now.HomeTime();
+
+ FindAndQueueNextFewAlarmsL(now,now+TTimeIntervalDays(aMaxNumberOfDays),aMaxNumberOfAlarms);
+ }
+
+void CAgnAlarmActive::FindAndQueueNextFewAlarmsL(const TTime& aStartTime, const TTime& aEndTime, const TInt aMaxNumberOfAlarms)
+//
+// Find the next due alarm(s) and if at least one exists then queue it with the alarm server
+//
+ {
+ TTime currTime = aStartTime;
+
+ CArrayFixFlat<TAgnAlarmEntry>* alarmList = new (ELeave) CArrayFixFlat<TAgnAlarmEntry>(10);
+ CleanupStack::PushL(alarmList);
+
+ // Certainly on WINS an alarm may expire a few seconds before it is due, the
+ // following ensures that the same alarm isn't queued twice
+ if ( iAlarmList->Count() )
+ {
+ TTime lastAlarm = ((*iAlarmList)[0]).iAlarmTime.LocalL();
+
+ if ( currTime < lastAlarm )
+ {
+ currTime += TTimeIntervalSeconds(1);
+ }
+ }
+
+ CArrayFixFlat<TAgnSortInstance>* alarmedIds = new(ELeave) CArrayFixFlat<TAgnSortInstance>(10);
+ CleanupStack::PushL(alarmedIds);
+
+ iModel->NextFewAlarmsForServerL(currTime, aEndTime, *alarmedIds, aMaxNumberOfAlarms);
+
+ const TInt KAlarmedIdsCount = alarmedIds->Count();
+
+ for ( TInt ii = 0; ii < KAlarmedIdsCount; ++ii )
+ {
+ //create an alarmEntry
+ TAgnAlarmEntry alarmEntry;
+
+ if (AssignToL(alarmEntry, (*alarmedIds)[ii]))
+ {
+ TKeyArrayFix key(_FOFF(TAgnAlarmEntry, iAlarmTime), ECmpTInt64);//order by alarm time
+ alarmList->InsertIsqAllowDuplicatesL(alarmEntry, key);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(alarmedIds);
+
+ Cancel();
+
+ if(iStatus != KErrLocked)
+ {
+ TASShdAlarm alarm;
+ const TInt KCount = alarmList->Count();
+ for( TInt ii = 0; ii < KCount; ++ii )
+ {
+ const TAgnAlarmEntry& alarmEntry = (*alarmList)[ii];
+
+ InitialiseAlarmL(alarm, alarmEntry, EFalse);
+
+ TAgnAlarmInfo alarmInfo;
+ GetAlarmInfoL(alarmEntry.iInstanceId, alarmInfo);
+ TPkgCAgnAlarmInfo pkgAgendaRef(alarmInfo);
+
+ _DBGLOG_ALARM( AgmDebug::DebugLog("Queueing first alarm on list:");)
+ _DBGLOG_ALARM(AgmDebug::DebugLogAlarmL(alarmEntry);)
+
+ iAlarmServer.AlarmAdd(alarm, pkgAgendaRef);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(alarmList);
+ }
+
+// Get the TAgnAlarmEntry struct for the current entry or return NULL if not available
+const TAgnAlarmEntry* CAgnAlarmActive::CurrentAlarmEntry() const
+ {
+ if ( iAlarmList&&iAlarmList->Count() > 0 )
+ {
+ return ( &((*iAlarmList)[iAlarmListIndex]) );
+ }
+
+ return ( NULL );
+ }
+
+void CAgnAlarmActive::DoCancel()
+//
+// Cancel the alarm
+//
+// DoCancel only gets called from Cancel(). It will only be called if the object is active - which means that
+// there should therefore be an alarm to cancel.
+ {
+ const TAlarmId KId = iAlarm.Id();
+ if ( KId != KNullAlarmId )
+ {
+ iAlarmServer.AlarmNotificationCancelAndDequeue(KId); // resulting signal is picked up in Cancel()
+ }
+ }
+
+void CAgnAlarmActive::GetAlarmInfoL(const TAgnInstanceId& aInstanceId, TAgnAlarmInfo& aAlarmInfo) const
+ {
+ aAlarmInfo.iEntryId = aInstanceId;
+
+ aAlarmInfo.iTimeMode = aInstanceId.Date().TimeMode();
+
+ if(aAlarmInfo.iTimeMode==MAgnCalendarTimeMode::EFloating)
+ {
+ aAlarmInfo.iInstanceTime = aInstanceId.Date().LocalL();
+ }
+ else
+ {
+ aAlarmInfo.iInstanceTime = aInstanceId.Date().UtcL();
+ }
+
+ aAlarmInfo.iAlarmCategory = KUidAgendaModelAlarmCategory;
+
+ //Remove path from the filename, leave only Drive:Filename.ext
+ TParsePtrC parser(iModel->FileName());
+ aAlarmInfo.iFileName = parser.Drive();
+ aAlarmInfo.iFileName.Append(parser.NameAndExt());
+
+ CAgnEntry* entry = iModel->FetchEntryL(aInstanceId);
+ __ASSERT_ALWAYS(entry, User::Leave(KErrNotFound)); // alarm has expired for entry which cannot be found or has been deleted
+
+ CleanupStack::PushL(entry);
+
+ aAlarmInfo.iAgnUniqueId = entry->LocalUid();
+
+ if(aInstanceId.Date().TimeMode()==MAgnCalendarTimeMode::EFloating)
+ {
+ aAlarmInfo.iRecurrenceId = entry->RecurrenceId().LocalL();
+ }
+ else
+ {
+ aAlarmInfo.iRecurrenceId = entry->RecurrenceId().UtcL();
+ }
+ aAlarmInfo.iGlobalIdentifier = iModel->GetEntryGuidL(*entry);
+ CleanupStack::PopAndDestroy(entry);
+ }
+
+void CAgnAlarmActive::SetQueueAlarmsInPast(TBool aQueueAlarmsInPast)
+ {
+ iQueueAlarmsInPast = aQueueAlarmsInPast;
+ }
+
+const CAgnServFile& CAgnAlarmActive::AgnServFile()
+ {
+ return iModel->AgnServFile();
+ }
+
+CAgnAlarmServerChangeObserver* CAgnAlarmServerChangeObserver::NewL(MAgnAlarmServerTerminationCallBack* aCallBack, CAgnAlarm* aOwningObject)
+//
+// Create a CAgnAlarmServerChangeObserver object
+//
+ {
+ CAgnAlarmServerChangeObserver* self = new(ELeave) CAgnAlarmServerChangeObserver(aCallBack, aOwningObject);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return (self);
+ }
+
+CAgnAlarmServerChangeObserver::CAgnAlarmServerChangeObserver(MAgnAlarmServerTerminationCallBack* aCallBack, CAgnAlarm* aOwningObject)
+//
+// C'tor
+//
+ :iCallBack(aCallBack), iOwningObject(aOwningObject)
+ {
+ }
+
+void CAgnAlarmServerChangeObserver::ConstructL()
+ {
+ iTimeZoneConvertor = CAgnTlsProxy::CreateL(CAgnTlsProxy::TAgnTlsTzRulesType_Server);
+ }
+
+
+CAgnAlarmServerChangeObserver::~CAgnAlarmServerChangeObserver()
+//
+// D'tor
+//
+ {
+ delete iSystemId;
+ CAgnTlsProxy::Release(iTimeZoneConvertor);
+ }
+
+/**
+Filter notifications from the alarm server, if KErrServerTerminated is received then
+call the callback function
+*/
+void CAgnAlarmServerChangeObserver::HandleAlarmServerChangeL(TInt aChange)
+ {
+
+ if ( aChange == KErrServerTerminated )
+ {
+ if ( iCallBack )
+ {
+ iCallBack->AlarmServerTerminated();
+ }
+ else if ( iUserRequestStatus )
+ {
+ User::RequestComplete(iUserRequestStatus,KErrServerTerminated);
+ iUserRequestStatus = NULL;
+ }
+ }
+ else // iStatus != KErrServerTerminated
+ {
+ if (aChange == EAlarmChangeEventSystemDateTimeChanged)
+ {
+ CTzId* newSysTime=iTimeZoneConvertor->TzServer().GetTimeZoneIdL();
+ if( iSystemId && (*iSystemId==*newSysTime) )//when locale changes, we will receive notification twice but we only act once.
+ {
+ delete newSysTime;
+ }
+ else
+ {
+ delete iSystemId;
+ iSystemId=newSysTime;
+ }
+
+ const TAgnAlarmEntry* alarmEntry = iOwningObject->AlarmEntry();
+ TTime queuedEntryTime;
+
+ // INC045770: Alarms less than X days old should fire when the system time is put forward.
+ if ( alarmEntry && iOwningObject->QueueAlarmsInPast())
+ {
+ // Get the time of the currently scheduled alarm (serves as the old system time for our purposes.)
+ queuedEntryTime=alarmEntry->iAlarmTime.LocalL();
+ // sub 1st sec: FindAndQueue* adds 1 second to prevent scheduling an alarm twice.
+ // sub 2nd sec: Our sess alarm that has been cancelled needs to be aged 1 sec to get queued.
+ queuedEntryTime-=TTimeIntervalSeconds(2);
+
+ TTime now;
+ now.HomeTime();
+ TTimeIntervalDays delta = now.DaysFrom(queuedEntryTime);
+
+ // clock set forward X days or more after the session alarm; schedule all alarms within X days of the curr time.
+ if (delta >= TTimeIntervalDays(KSystemTimeChangeMaxDaysOld))
+ iOwningObject->FindAndQueueNextFewAlarmsL(now-TTimeIntervalDays(KSystemTimeChangeMaxDaysOld),now,KSystemTimeChangeMaxAlarmsQueued);
+ // clock set forward less than X days after sesion alarm, schedule all alarms between session alarm time and curr time
+ else if (delta >= TTimeIntervalDays(0))
+ iOwningObject->FindAndQueueNextFewAlarmsL(queuedEntryTime,now,KSystemTimeChangeMaxAlarmsQueued);
+ // else system time has been put backwards (normal code path can handle this case)
+ }
+ // *always* schedule a session alarm when the time changes
+ iOwningObject->FindAndQueueNextAlarmL(ETrue);
+ }
+ else if (aChange == EAlarmChangeEventRestoreCompleted ||
+ aChange == EAlarmChangeEventRestoreFailed)
+ {
+ // The restore has finished so try to find and queue the next few alarms
+ if (!iOwningObject->AgnServFile().IsLocked()
+ && !iOwningObject->AgnServFile().IsBackupRestoreLock())
+ {
+ iOwningObject->FindAndQueueNextAlarmL(EFalse);
+ }
+ }
+ }
+ }
+