commonappservices/alarmserver/Server/Source/ASSrvAlarmQueue.cpp
changeset 0 2e3d3ce01487
child 60 d55467af0fda
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     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 	}