commonappservices/alarmserver/Server/Source/ASSrvAlarm.cpp
changeset 0 2e3d3ce01487
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:
       
    14 //
       
    15 
       
    16 #include "ASSrvAlarm.h"
       
    17 
       
    18 // User includes
       
    19 #include "ASSrvTimer.h"
       
    20 #include "ASSrvDataPool.h"
       
    21 #include "ASSrvAlarmQueue.h"
       
    22 #include "ASSrvStaticUtils.h"
       
    23 #include "ASSrvSoundSettings.h"
       
    24 #include "ASSrvServerWideData.h"
       
    25 #include "ASSrvAlarmSoundDetails.h"
       
    26 #include "ASSrvIteratorByState.h"
       
    27 #include "ASSrvSoundController.h"
       
    28 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    29 #include "ASShdAlarm_internal.h"
       
    30 #endif
       
    31 
       
    32 
       
    33 // Definitions
       
    34 //#define __DEBUGGING_TIMES
       
    35 
       
    36 
       
    37 //
       
    38 // ----> TASSrvAlarm (source)
       
    39 //
       
    40 
       
    41 //*************************************************************************************
       
    42 /**
       
    43  * Constructor
       
    44  */
       
    45 TASSrvAlarm::TASSrvAlarm(CASSrvServerWideData& aData)
       
    46 :	iSoundPeriodCycleNumber(KUndefinedCycleIndex), iStartTimeForSoundCalculations(Time::NullTTime()),
       
    47 	iSoundState(ESoundStatePlayingNothing), iInternalServerFlags(0),
       
    48 	iOriginatingSessionId(KErrNotFound), iServerWideData(aData)
       
    49 	{
       
    50 	}
       
    51 
       
    52 
       
    53 //
       
    54 //
       
    55 //
       
    56 
       
    57 
       
    58 //*************************************************************************************
       
    59 /**
       
    60  * Copy operator. Only copies certain data members. Possibly this
       
    61  * should be removed...
       
    62  */
       
    63 TASSrvAlarm& TASSrvAlarm::operator=(const TASSrvAlarm& aAlarm)
       
    64 	{
       
    65 	TASShdAlarm::operator=(aAlarm);
       
    66 	//
       
    67 	iSoundPeriodCycleNumber = aAlarm.iSoundPeriodCycleNumber;
       
    68 	iStartTimeForSoundCalculations = aAlarm.iStartTimeForSoundCalculations;
       
    69 	iSoundState = aAlarm.iSoundState;
       
    70 	iInternalServerFlags = aAlarm.iInternalServerFlags;
       
    71 	iOriginatingSessionId = aAlarm.iOriginatingSessionId;
       
    72 	iNotificationMessage = aAlarm.iNotificationMessage;
       
    73 	//
       
    74 	return *this;
       
    75 	}
       
    76 
       
    77 
       
    78 //
       
    79 //
       
    80 //
       
    81 
       
    82 
       
    83 //*************************************************************************************
       
    84 /**
       
    85  * Change the status of this alarm, i.e. enabled, disabled
       
    86  *
       
    87  * @return  TInt KErrNone on success, or one of the system wide standard error codes.
       
    88  *				 KErrLocked is returned if this alarm is a "workday" alarm but no valid
       
    89  *				 workdays have been defined.
       
    90  */
       
    91 TInt TASSrvAlarm::SetStatus(TAlarmStatus aStatus)
       
    92 	{
       
    93 	return doSetStatus(aStatus, EFalse);
       
    94 	}
       
    95 
       
    96 
       
    97 /**
       
    98 Change the state of this alarm.
       
    99 */
       
   100 void TASSrvAlarm::SetState(TAlarmState aState)
       
   101 	{
       
   102 	const TAlarmState oldState = State();
       
   103 	
       
   104 	// Only process a change in state.
       
   105 	if (oldState == aState)
       
   106 		{
       
   107 		return;
       
   108 		}
       
   109 
       
   110 	// Update current state.
       
   111 	iState = aState;
       
   112 
       
   113 	// If a paused alarm has re-notified (after the pause period is up) or has
       
   114 	// been dismissed then clear the paused flag.
       
   115 	if (HasSoundPaused() || iState == EAlarmStateNotifying || iState == EAlarmStateNotified)
       
   116 		{
       
   117 		ClearSoundPausedFlag();
       
   118 		}
       
   119 
       
   120 	// Handle new state.
       
   121 	switch(aState)
       
   122 		{
       
   123 	case EAlarmStateQueued:
       
   124 	case EAlarmStateSnoozed:
       
   125 	case EAlarmStateWaitingToNotify:
       
   126 	case EAlarmStateInPreparation:
       
   127 		break;
       
   128 
       
   129 	case EAlarmStateNotified:
       
   130 		{		
       
   131 		// If the alarm does not repeat or it is a 24 hour alarm then we do
       
   132 		// nothing.  Notified alarms are cleaned up by the queue when they are
       
   133 		// more than 7 days old.
       
   134 		if (RepeatDefinition() != EAlarmRepeatDefintionRepeatOnce && RepeatDefinition() != EAlarmRepeatDefintionRepeatNext24Hours)
       
   135 			{
       
   136 			// Work out when the alarm should next repeat.
       
   137 			PrepareForNextRepeat();
       
   138 			}
       
   139 		}
       
   140 		break;
       
   141 
       
   142 	case EAlarmStateNotifying:
       
   143 		{
       
   144 		TTime now(ASSrvStaticUtils::UtcTimeNow());
       
   145 		ReinitializeSoundState(now);
       
   146 		}
       
   147 		break;
       
   148 
       
   149 	default:
       
   150 		{
       
   151 		__ASSERT_DEBUG(EFalse, ASSrvStaticUtils::Fault(ASSrvStaticUtils::EASSrvFaultAlarmStateNotHandled));
       
   152 		}
       
   153 		break;
       
   154 		}
       
   155 
       
   156 	// Notify queue so that it can work out if it needs to do some reordering.
       
   157 	// Only do this if this alarm has been queued (which we can infer if this
       
   158 	// alarm has a non-null identifier).
       
   159 	if (Id() != KNullAlarmId)
       
   160 		{
       
   161 		ServerData().Queue().HandleAlarmStateChanged(Id(), oldState);
       
   162 		}
       
   163 
       
   164 	// We call ourselves recursively if we are a repeating alarm.  We must do
       
   165 	// this *after* the above HandleAlarmStateChanged() call because there must
       
   166 	// be two state change notifictions otherwise observers will not behave
       
   167 	// correctly...
       
   168 	switch (RepeatDefinition())
       
   169 		{
       
   170 	case EAlarmRepeatDefintionRepeatOnce:
       
   171 	case EAlarmRepeatDefintionRepeatNext24Hours:
       
   172 		break;
       
   173 
       
   174 	case EAlarmRepeatDefintionRepeatDaily:
       
   175 	case EAlarmRepeatDefintionRepeatWorkday:
       
   176 	case EAlarmRepeatDefintionRepeatWeekly:
       
   177 #ifdef SYMBIAN_ALARM_REPEAT_EXTENSIONS
       
   178 	case EAlarmRepeatDefinitionRepeatDailyOnGivenDays:
       
   179 #endif
       
   180 		if (oldState == EAlarmStateNotifying)
       
   181 			{
       
   182 			// Make sure we keep the snoozed state and not change to queued as
       
   183 			// in the non-repeating alarms.
       
   184 			if (aState == EAlarmStateSnoozed)
       
   185 				{
       
   186 				if (Id() != KNullAlarmId)
       
   187 					{
       
   188 					ServerData().Queue().HandleAlarmStateChanged(Id(), aState);						
       
   189 					}
       
   190 				}
       
   191 			else
       
   192 				{
       
   193 				SetState(EAlarmStateQueued);					
       
   194 				}
       
   195 			}
       
   196 		break;
       
   197 
       
   198 	default:
       
   199 		break;
       
   200 		}
       
   201 	}
       
   202 
       
   203 //*************************************************************************************
       
   204 /**
       
   205  * Change the characteristics of this alarm
       
   206  */
       
   207 void TASSrvAlarm::SetCharacteristicsL(TAlarmCharacteristicsFlags aFlags, TASSrvSessionId aSessionChangingFlags)
       
   208 	{
       
   209 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
       
   210 	// if it is a wakeup alarm and they are trying to set session specific then leave
       
   211 	if (aFlags.IsSet(EAlarmCharacteristicsSessionSpecific) && IsWakeup())
       
   212 		{
       
   213 		User::Leave(KErrArgument);		
       
   214 		}
       
   215 #endif
       
   216 	
       
   217 	const TAlarmCharacteristicsFlags oldCharacteristics = Characteristics();
       
   218 	if	(oldCharacteristics.Value() == aFlags.Value())
       
   219 		return;
       
   220 
       
   221 	// If it was session-specific, but it isn't anymore, then we need
       
   222 	// to complete the pending notification with KErrCancel
       
   223 	if	(oldCharacteristics.IsSet(EAlarmCharacteristicsSessionSpecific) &&
       
   224 		 !aFlags.IsSet(EAlarmCharacteristicsSessionSpecific))
       
   225 		{
       
   226 		// If there was a notification request then we complete it
       
   227 		NotificationMessageComplete(KErrCancel);
       
   228 
       
   229 		// Indicate that this alarm is no longer owned by a session
       
   230 		iFlags.Set(EASShdAlarmFlagsHasBecomeOrphaned);
       
   231 		}
       
   232 	else if (!oldCharacteristics.IsSet(EAlarmCharacteristicsSessionSpecific) &&
       
   233 		aFlags.IsSet(EAlarmCharacteristicsSessionSpecific))
       
   234 		{
       
   235 		// The session indicated wishes to take ownership of this alarm (but
       
   236 		// can't request a expiry notification because these can only be setup
       
   237 		// when an alarm is first created).
       
   238 		SetOriginatingSessionId(aSessionChangingFlags);
       
   239 
       
   240 		// Indicate that this alarm is now owned by a session
       
   241 		iFlags.Clear(EASShdAlarmFlagsHasBecomeOrphaned);
       
   242 		}
       
   243 
       
   244 	// Update state now
       
   245 	iCharacteristics = aFlags;
       
   246 
       
   247 	// Notify queue so that it can work out if it needs to do
       
   248 	// some re-ordering (only do this if we've been queued, and therefore
       
   249 	// have an alarm id).
       
   250 	if	(Id() != KNullAlarmId)
       
   251 		ServerData().Queue().HandleAlarmCharacteristicsChanged(Id(), oldCharacteristics);
       
   252 	}
       
   253 
       
   254 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
       
   255 void TASSrvAlarm::SetWakeupAndNotifyQueueL(TBool aEnable)
       
   256 	{
       
   257 	if (IsWakeup() == aEnable)
       
   258 		{
       
   259 		return;
       
   260 		}
       
   261 
       
   262 	if (aEnable && iCharacteristics.IsSet(EAlarmCharacteristicsSessionSpecific))
       
   263 		{
       
   264 		// you cannot set a session alarm as wakeup
       
   265 		User::Leave(KErrArgument);		
       
   266 		}
       
   267 	
       
   268 	SetWakeup(aEnable);
       
   269 	if (Id() != KNullAlarmId)
       
   270 		{
       
   271 		ServerData().Queue().HandleWakeupChanged(Id());
       
   272 		}
       
   273 	}
       
   274 #endif
       
   275 
       
   276 #ifdef SYMBIAN_ALARM_REPEAT_EXTENSIONS
       
   277 void TASSrvAlarm::SetAlarmDaysL(TUint8 aAlarmDays)
       
   278 	{
       
   279 	// Check if any modification to current alarms days is required.
       
   280 	if (aAlarmDays == AlarmDays())
       
   281 		{
       
   282 		return;
       
   283 		}
       
   284 
       
   285 	User::LeaveIfError(SetAlarmDays(aAlarmDays));
       
   286 	User::LeaveIfError(ASSrvStaticUtils::ValidateAlarm(*this));
       
   287 	
       
   288 	// Notify queue so that it can work out if it needs to do some reordering.
       
   289 	ServerData().Queue().HandleAlarmDaysChanged(Id());
       
   290 	}
       
   291 #endif
       
   292 
       
   293 void TASSrvAlarm::SetAlarmOrphaned()
       
   294 	{
       
   295 	iFlags.Set(EASShdAlarmFlagsHasBecomeOrphaned);
       
   296 	}
       
   297 	
       
   298 //*************************************************************************************
       
   299 /**
       
   300  * Set the originating session id for this alarm. The originating session Id is the
       
   301  * session Id (a unique id allocated to each session) which is used to track
       
   302  * all "session alarms" within the server.
       
   303  */
       
   304 void TASSrvAlarm::SetOriginatingSessionId(TASSrvSessionId aId)
       
   305 	{
       
   306 	iOriginatingSessionId = aId;
       
   307 	if	(aId >= 0)
       
   308 		{
       
   309 		iFlags.Set(EASShdAlarmFlagsHasOwningSession);
       
   310 		}
       
   311 	else
       
   312 		{
       
   313 		iFlags.Clear(EASShdAlarmFlagsHasOwningSession);
       
   314 		}
       
   315 	}
       
   316 
       
   317 
       
   318 //
       
   319 //
       
   320 //
       
   321 
       
   322 
       
   323 /**
       
   324 Return the originating session id.
       
   325 
       
   326 @return The id of the session that created the TASSrvAlarm.
       
   327 */
       
   328 TASSrvSessionId TASSrvAlarm::OriginatingSessionId() const
       
   329 	{
       
   330 	return iOriginatingSessionId;
       
   331 	}
       
   332 
       
   333 
       
   334 /**
       
   335 Return the alarm's sound state.
       
   336 
       
   337 @return The state of the alarm's sound.
       
   338 */
       
   339 TASSrvAlarm::TSoundState TASSrvAlarm::SoundState() const
       
   340 	{
       
   341 	return iSoundState;
       
   342 	}
       
   343 
       
   344 
       
   345 //
       
   346 //
       
   347 //
       
   348 
       
   349 
       
   350 //*************************************************************************************
       
   351 /**
       
   352  * Issue a request for notifications when this alarm expires
       
   353  */
       
   354 void TASSrvAlarm::RequestExpiryNotificationL(const RMessage2& aMessage)
       
   355 	{
       
   356 	// Queue for notifications. This allows us to observe when the alarm expires
       
   357 	// and notify the client
       
   358 	ServerData().Timer().NotifyAlarmExpiredL(*this);
       
   359 
       
   360 	// Save a pointer
       
   361 	iNotificationMessage = aMessage;
       
   362 
       
   363 	// Update flags to indicate we have a pending notification message pointer
       
   364 	iInternalServerFlags.Set(EInternalServerFlagsNotifyPending);
       
   365 	}
       
   366 
       
   367 
       
   368 //*************************************************************************************
       
   369 /**
       
   370  * Cancel a previous expiry notification request
       
   371  */
       
   372 void TASSrvAlarm::RequestExpiryNotificationComplete(TInt aErrorCode)
       
   373  	{
       
   374 	NotificationMessageComplete(aErrorCode);	
       
   375  	}
       
   376 
       
   377 /**
       
   378 Return whether or not the alarm has a notification request pending.
       
   379 
       
   380 @return A TBool that is ETrue if the alarm has a notification request pending.
       
   381 */
       
   382 TBool TASSrvAlarm::HasNotificationRequestPending() const
       
   383 	{
       
   384 	return iInternalServerFlags.IsSet(EInternalServerFlagsNotifyPending) && HasOwningSession();
       
   385 	}
       
   386 
       
   387 
       
   388 //*************************************************************************************
       
   389 /**
       
   390  * Map the specified time object (data member) to the nearest minute (rounding down)
       
   391  */
       
   392 void TASSrvAlarm::RoundDownTimeToMinute(TTimeType aType)
       
   393 	{
       
   394 	switch(aType)
       
   395 		{
       
   396 	case ETimeTypeNextDue:
       
   397 		ASSrvStaticUtils::RoundTimeDownToTheMinute(iNextDueTime);
       
   398 		break;
       
   399 	case ETimeTypeOriginalExpiry:
       
   400 		ASSrvStaticUtils::RoundTimeDownToTheMinute(iOriginalExpiryTime);
       
   401 		break;
       
   402 		}
       
   403 	}
       
   404 
       
   405 
       
   406 //*************************************************************************************
       
   407 /**
       
   408  * Destroy this alarm. Removes it from the queue and marks it as inactive.
       
   409  */
       
   410 void TASSrvAlarm::DeQueue()
       
   411 	{
       
   412 	ServerData().Queue().DeQueueAlarm(*this);
       
   413 	}
       
   414 
       
   415 
       
   416 //*************************************************************************************
       
   417 /**
       
   418  * Reset this alarm back to a completely uninitialized state.
       
   419  */
       
   420 void TASSrvAlarm::Reset()
       
   421 	{
       
   422 	TASShdAlarm::Reset();
       
   423 	//
       
   424 	iInternalServerFlags = 0;
       
   425 	iOriginatingSessionId = 0;
       
   426 	iSoundPeriodCycleNumber = 0;
       
   427 	}
       
   428 
       
   429 
       
   430 /**
       
   431 Clears the alarm's flags.
       
   432 */
       
   433 void TASSrvAlarm::ClearFlags()
       
   434 	{
       
   435 	iFlags = 0;
       
   436 	}
       
   437 
       
   438 
       
   439 /**
       
   440 Set the alarm's sound state.
       
   441 
       
   442 @param aSoundState The new TSoundState of this alarm.
       
   443 */
       
   444 void TASSrvAlarm::SetSoundState(TSoundState aSoundState)
       
   445 	{
       
   446 	iSoundState = aSoundState;
       
   447 	}
       
   448 
       
   449 
       
   450 //*************************************************************************************
       
   451 /**
       
   452  * Toggle the sound state of this alarm
       
   453  */
       
   454 void TASSrvAlarm::ToggleSoundState()
       
   455 	{
       
   456 	// Invert the existing sound state
       
   457 	if	(iSoundState == ESoundStatePlayingNothing)
       
   458 		iSoundState = ESoundStatePlayingSound;
       
   459 	else
       
   460 		iSoundState = ESoundStatePlayingNothing;
       
   461 	}
       
   462 
       
   463 
       
   464 //*************************************************************************************
       
   465 /**
       
   466  * If sound is temporarily silenced, then this method is used to re-initialize
       
   467  * the alarm's starting time for any future sound calculations.
       
   468  */
       
   469 void TASSrvAlarm::ReinitializeSoundState(const TTime& aBaselineForSoundTiming)
       
   470 	{
       
   471 	// Reset the cycle and sound state ready to start playing
       
   472 	ASSrvStaticUtils::TodayAtTheSpecifiedTime(aBaselineForSoundTiming, iStartTimeForSoundCalculations);
       
   473 	SetSoundState(TASSrvAlarm::ESoundStatePlayingNothing);
       
   474 	SetSoundTimingCycleIndex(0);
       
   475 	}
       
   476 
       
   477 
       
   478 //*************************************************************************************
       
   479 /**
       
   480  * Work out when the alarm sound should next start or stop playing.
       
   481  */
       
   482 TTime TASSrvAlarm::CalculateAndPrepareNextSoundCycle()
       
   483 	{
       
   484 	// If the new state is not to play any sound, and we've already progressed
       
   485 	// through all the Sound Intervals, the SoundTimingCycleIndex will have
       
   486 	// been set to KErrNotFound (see below)
       
   487 	if ((SoundState() == ESoundStatePlayingNothing) &&
       
   488 		(SoundTimingCycleIndex() == KErrNotFound)
       
   489 #ifdef SYMBIAN_ALARM_REPEAT_EXTENSIONS
       
   490 		|| Continuous()
       
   491 #endif
       
   492 		)
       
   493 		{
       
   494 		SetSoundTimingCycleIndex(0); // just to be safe, we'll reset this.
       
   495 		return Time::NullTTime();
       
   496 		}
       
   497 
       
   498 	const CASSrvSoundSettings& soundSettings = ServerData().SoundSettings();
       
   499 
       
   500 	// If the new state is not to play any sound, then we should work out when 
       
   501 	// we should start playing sound again. If we're now about to start playing sound
       
   502 	// we should work out when we're going to stop playing it again.
       
   503 	CASSrvSoundSettings::TSoundCyclePosition position = CASSrvSoundSettings::ESoundCyclePositionAtStart;
       
   504 	if (SoundState() == ESoundStatePlayingSound)
       
   505 		{
       
   506 		position = CASSrvSoundSettings::ESoundCyclePositionAtEnd;
       
   507 		}
       
   508 
       
   509 	//
       
   510 #ifdef __DEBUGGING_TIMES
       
   511 	TDateTime startTimeForSoundCalculations = iStartTimeForSoundCalculations.DateTime();
       
   512 #endif
       
   513 
       
   514 	ASSrvStaticUtils::TodayAtTheSpecifiedTime(iStartTimeForSoundCalculations, iStartTimeForSoundCalculations);
       
   515 #ifdef __DEBUGGING_TIMES
       
   516 	startTimeForSoundCalculations = iStartTimeForSoundCalculations.DateTime();
       
   517 #endif
       
   518 
       
   519 	TTime returnTime(soundSettings.SoundIntervalTime(iStartTimeForSoundCalculations, SoundTimingCycleIndex(), position));
       
   520 #ifdef __DEBUGGING_TIMES
       
   521 	TDateTime returnTimeDT = returnTime.DateTime();
       
   522 #endif
       
   523 
       
   524 	// Increment position at the end of the cycle
       
   525 	if (SoundState() == ESoundStatePlayingSound)
       
   526 		{
       
   527 		// There will always be at least one sound play interval, so we can 
       
   528 		// assume that here. If there hadn't been any intervals, the CASSrvSoundController
       
   529 		// would be considered disabled, and wouldn't have invoked the current method.
       
   530 		TInt tempSS = SoundTimingCycleIndex();
       
   531 		if (tempSS >= (soundSettings.SoundIntervalCount()-1)) // Index E (0..SoundIntervalCount()-1)
       
   532 			{
       
   533 			switch ( soundSettings.RepeatSetting() )
       
   534 				{
       
   535 			case EAlarmSoundRepeatSettingLoop:
       
   536 				// Go back to the first cycle, resetting the start time
       
   537 				// to avoid setting an alarm time in the past.
       
   538 				tempSS = 0;
       
   539 				iStartTimeForSoundCalculations = returnTime;
       
   540 				break;
       
   541 			case EAlarmSoundRepeatSettingRepeatLast:
       
   542 				{
       
   543 				// Repeat the last interval; Don't change the Sound Interval
       
   544 				// Index (currently tempSS). The last offset will be added to
       
   545 				// iStartTimeForSoundCalculations in the call to SoundIntervalTime,
       
   546 				// so we need to update it so that the timing is correct.
       
   547 
       
   548 				// Determine the duration of the last interval:
       
   549 				TTime lastStartTime(soundSettings.SoundIntervalTime(iStartTimeForSoundCalculations,
       
   550 																	soundSettings.SoundIntervalCount()-1,
       
   551 																	CASSrvSoundSettings::ESoundCyclePositionAtStart ));
       
   552 				TTime nextToLastStartTime(soundSettings.SoundIntervalTime(iStartTimeForSoundCalculations,
       
   553 																	soundSettings.SoundIntervalCount()-2,
       
   554 																	CASSrvSoundSettings::ESoundCyclePositionAtStart ));
       
   555 				TTimeIntervalMinutes diff;
       
   556 				lastStartTime.MinutesFrom(nextToLastStartTime, diff);
       
   557 				iStartTimeForSoundCalculations += diff;
       
   558 				}
       
   559 				break;
       
   560 			case EAlarmSoundRepeatSettingStop:
       
   561 				// This will cause TTime::NullTTime() to be returned to the
       
   562 				// Sound Controller when the next time interval expires.
       
   563 				tempSS = KErrNotFound;
       
   564 				break;
       
   565 				}
       
   566 			}
       
   567 		else
       
   568 			{
       
   569 			tempSS++;
       
   570 			}
       
   571 		SetSoundTimingCycleIndex(tempSS);
       
   572 		}
       
   573 	return returnTime;
       
   574 	}
       
   575 
       
   576 
       
   577 //*************************************************************************************
       
   578 /**
       
   579  * Perform some sanity checking after internalizing an alarm or receiving
       
   580  * an alarm via the client API. Checks that the alarm isn't too old to 
       
   581  * still be considered valid. If the alarm is okay, its status is changed
       
   582  * to enabled. Note that this method checks the workdays, and hence it
       
   583  * might also disable an otherwise "valid" alarm.
       
   584  * 
       
   585  * @return  KErrNone if the alarm is valid (and therefore may be queued),
       
   586  *			KErrArgument if this alarm isn't valid, KErrLocked if a "Workdays" alarm
       
   587  *			has no valid workdays to test itself against (but is otherwise valid).
       
   588  */
       
   589 TInt TASSrvAlarm::ValidateAndEnable(TTimeIntervalSeconds aAllowableWindow, TBool aAllowAnyOnceAlarmInThePast, TBool aEnable)
       
   590 	{
       
   591 	TInt alarmErrorCode = KErrArgument;
       
   592 	//
       
   593 	if (OriginalExpiryTime() == Time::NullTTime())
       
   594 		{
       
   595 		OriginalExpiryTime() = NextDueTime();
       
   596 		}
       
   597 	// Was the alarm notifying or snoozed when the server closed?
       
   598 	// If so, we don't want to adjust the next due time.
       
   599 	if (State() == EAlarmStateNotifying)
       
   600 		{
       
   601 		// Set the state back to EAlarmStateQueued so the alarm will notify again.
       
   602 		iState = EAlarmStateQueued;
       
   603 		alarmErrorCode = KErrNone;
       
   604 		}
       
   605 	else if (State() == EAlarmStateSnoozed)
       
   606 		{
       
   607 		alarmErrorCode = KErrNone;
       
   608 		}
       
   609 	else
       
   610 		{
       
   611 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
       
   612 		if (!(IsWakeup() && iCharacteristics.IsSet(EAlarmCharacteristicsSessionSpecific)))
       
   613 			{
       
   614 #endif
       
   615 			TTime oldestValidTimeForAlarms(ASSrvStaticUtils::UtcTimeNow());
       
   616 			if	(NextDueTime() != Time::NullTTime())
       
   617 				{
       
   618 				if	(RepeatDefinition() == EAlarmRepeatDefintionRepeatOnce)
       
   619 					{
       
   620 					// Does the alarm fall within the window?
       
   621 					oldestValidTimeForAlarms -= aAllowableWindow;
       
   622 			
       
   623 					// 1. Ignore alarms in the past (taking the window into account)
       
   624 					// 2. If the "allow anything" flag is set (parameter) then we always
       
   625 					//    allow the alarm.
       
   626 					// 3. If the alarm is in the past, but it's state is "Notified" then we 
       
   627 					//    allow it anyway.
       
   628 					const TBool insideWindow = NextDueTime() >= oldestValidTimeForAlarms;
       
   629 					if	(insideWindow || aAllowableWindow.Int() < 0 || aAllowAnyOnceAlarmInThePast || State() == EAlarmStateNotified)
       
   630 						{
       
   631 						// This alarm is okay
       
   632 						alarmErrorCode = KErrNone;
       
   633 						}
       
   634 					}
       
   635 				else
       
   636 					{
       
   637 					// The alarm must be one of the repeating types.
       
   638 					__ASSERT_ALWAYS(RepeatDefinition() != EAlarmRepeatDefintionRepeatOnce, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicInvalidAlarmRepeat));
       
   639 	
       
   640 					// If it's a repeat in the next 24 hours then we need to
       
   641 					// work out the next time. Otherwise, we can use the standard
       
   642 					// PrepareForNextRepeat method.
       
   643 					if	(RepeatDefinition() == EAlarmRepeatDefintionRepeatNext24Hours)
       
   644 						{
       
   645 						ASSrvStaticUtils::CalculateNext24HoursRepeat(*this, aAllowableWindow);
       
   646 						alarmErrorCode = KErrNone;
       
   647 						}
       
   648 					else
       
   649 					    {
       
   650 					    alarmErrorCode = PrepareForNextRepeat(aAllowableWindow);
       
   651 					    }
       
   652 					}
       
   653 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
       
   654 				}
       
   655 #endif
       
   656 			}
       
   657 		}
       
   658 
       
   659 	// If the alarm is valid then we enable it. Note that this will leave (otherwise) valid
       
   660 	// "Workdays" alarms disabled (e.g. if there aren't any workdays defined by the user, then
       
   661 	// the alarm is valid, but we can't enable it because we don't know when it will next be
       
   662 	// due).
       
   663 	if	(alarmErrorCode == KErrNone && aEnable)
       
   664 		{
       
   665 		// Enable the alarm if its not rejected
       
   666 		const TInt error = doSetStatus(EAlarmStatusEnabled, EFalse);
       
   667 		__ASSERT_ALWAYS(error == KErrNone, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicCannotSetAlarmStatus)); // Something has really gone wrong...
       
   668 		}
       
   669 
       
   670 	return alarmErrorCode;
       
   671 	}
       
   672 
       
   673 
       
   674 //*************************************************************************************
       
   675 /**
       
   676  * Snooze this alarm until the specified time
       
   677  */
       
   678 void TASSrvAlarm::Snooze(const TTime& aTimeToAwaken)
       
   679 	{
       
   680 	TTime tempTTime = aTimeToAwaken;
       
   681 	ASSrvStaticUtils::RoundTimeDownToTheMinute(tempTTime);
       
   682 	NextDueTime() = tempTTime;
       
   683 
       
   684 	// Changing the state to snoozed will notify the alarm queue of a state change.
       
   685 	// At this point, the queue is resorted to ensure that the snoozed alarm is
       
   686 	// present in the queue at the right point (since a snoozed alarm may end up
       
   687 	// moving to the head of the queue).
       
   688 	SetState(EAlarmStateSnoozed);
       
   689 	}
       
   690 
       
   691 
       
   692 /**
       
   693 Returns ETrue if the alarm sound playing has been paused.
       
   694 
       
   695 @return ETrue if the alarm sound playing has been paused, EFalse otherwise.
       
   696 */
       
   697 TBool TASSrvAlarm::HasSoundPaused() const
       
   698 	{
       
   699 	return iInternalServerFlags.IsSet(EASShdAlarmFlagsSoundHasBeenPaused);
       
   700 	}
       
   701 
       
   702 
       
   703 /**
       
   704 Sets an internal flag.
       
   705 
       
   706 @internalComponent
       
   707 */
       
   708 void TASSrvAlarm::SetSoundPausedFlag()
       
   709 	{
       
   710 	iInternalServerFlags.Set(EASShdAlarmFlagsSoundHasBeenPaused);
       
   711 	}
       
   712 
       
   713 
       
   714 /**
       
   715 Clears an internal flag.
       
   716 
       
   717 @internalComponent
       
   718 */
       
   719 void TASSrvAlarm::ClearSoundPausedFlag()
       
   720 	{
       
   721 	iInternalServerFlags.Clear(EASShdAlarmFlagsSoundHasBeenPaused);
       
   722 	}
       
   723 
       
   724 
       
   725 //
       
   726 //
       
   727 //
       
   728 
       
   729 
       
   730 //*************************************************************************************
       
   731 /**
       
   732  * Set the data for this alarm. Leaves with KErrInUse if this alarm
       
   733  * already has associated data.
       
   734  */
       
   735 void TASSrvAlarm::DataAttachL(HBufC8* aData)
       
   736 	{
       
   737 	CASSrvDataPool& dataPool = ServerData().DataPool();
       
   738 	dataPool.DataPoolAddDataL(Id(), aData);
       
   739 
       
   740 	// Set the base-class flags
       
   741 	iFlags.Set(EASShdAlarmFlagsHasAssociatedData);
       
   742 
       
   743 	// make sure all data gets saved
       
   744 	ServerData().Queue().HandleAlarmDataChanged(Id());
       
   745 	}
       
   746 
       
   747 
       
   748 //*************************************************************************************
       
   749 /**
       
   750  * Remove the data from the pool. Leaves if the alarm doesn't have
       
   751  * any associated data.
       
   752  */
       
   753 void TASSrvAlarm::DataDetachL()
       
   754 	{
       
   755 	CASSrvDataPool& dataPool = ServerData().DataPool();
       
   756 	dataPool.DataPoolRemoveDataL(Id());
       
   757 
       
   758 	// Clear the base-class flags
       
   759 	iFlags.Clear(EASShdAlarmFlagsHasAssociatedData);
       
   760 	}
       
   761 
       
   762 
       
   763 //*************************************************************************************
       
   764 /**
       
   765  * Returns the size in bytes of the data associated with this alarm.
       
   766  * Leaves with KErrNotFound if there is no data for this alarm.
       
   767  */
       
   768 TInt TASSrvAlarm::DataSizeL() const
       
   769 	{
       
   770 	TInt size = 0;
       
   771 	CASSrvDataPool& dataPool = ServerData().DataPool();
       
   772 	//
       
   773 	if	(HasAssociatedData() && dataPool.DataPoolContainsEntry(Id()))
       
   774 		size = dataPool.DataPoolEntry(Id()).Size();
       
   775 	else
       
   776 		User::Leave(KErrNotFound);
       
   777 	//
       
   778 	return size;
       
   779 	}
       
   780 
       
   781 
       
   782 //*************************************************************************************
       
   783 /**
       
   784  * Access the data associated with this alarm. Will leave with 
       
   785  * KErrNotFound if this alarm doesn't have any data.
       
   786  */
       
   787 const TDesC8& TASSrvAlarm::DataL() const
       
   788 	{
       
   789 	CASSrvDataPool& dataPool = ServerData().DataPool();
       
   790 	//
       
   791 	if	(!HasAssociatedData() || !dataPool.DataPoolContainsEntry(Id()))
       
   792 		User::Leave(KErrNotFound);
       
   793 	//
       
   794 	const TDesC8& data = dataPool.DataPoolEntry(Id());
       
   795 	return data;
       
   796 	}
       
   797 
       
   798 
       
   799 //*************************************************************************************
       
   800 /**
       
   801  * Same as DataL() except this panics if the alarm doesn't have any
       
   802  * data.
       
   803  */
       
   804 const TDesC8& TASSrvAlarm::Data() const
       
   805 	{
       
   806 	return ServerData().DataPool().DataPoolEntry(Id());
       
   807 	}
       
   808 
       
   809 
       
   810 //
       
   811 //
       
   812 //
       
   813 
       
   814 
       
   815 //*************************************************************************************
       
   816 /**
       
   817  * When attempting to action this alarm, a timer error occurred. Depending
       
   818  * on the alarm type, a different action is performed.
       
   819  */
       
   820 void TASSrvAlarm::HandleTimerError(TInt aErrorCode)
       
   821 	{
       
   822 	__ASSERT_ALWAYS(aErrorCode != KErrNone, ASSrvStaticUtils::Fault(ASSrvStaticUtils::EASSrvFaultPhantomErrorReported));
       
   823 
       
   824 	// Need to notify session if there was a pending notification request
       
   825 	NotificationMessageComplete(aErrorCode);
       
   826 
       
   827 	// Destroy the alarm
       
   828 	DeQueue();
       
   829 	}
       
   830 
       
   831 
       
   832 //*************************************************************************************
       
   833 /**
       
   834  * Called when an alarm is removed from the queue. Notifies any observers
       
   835  * that this alarm has died.
       
   836  */
       
   837 void TASSrvAlarm::HandleDeQueue()
       
   838 	{
       
   839 	NotificationMessageComplete(KErrDied);
       
   840 	}
       
   841 
       
   842 
       
   843 /**
       
   844 Called when the date/time or work days changes.
       
   845 */
       
   846 TBool TASSrvAlarm::HandleDateTimeChangedL(TUint aWorkdays, TBool aWorkdaysChanged)
       
   847 	{
       
   848 	// If this alarm has an outstanding expiry notification request it will be
       
   849 	// completed with KErrCancel.
       
   850 	NotificationMessageComplete(KErrCancel);
       
   851 	
       
   852 	TBool agendaAlarmInPast = EFalse;
       
   853 	TTime alarmDue;
       
   854 
       
   855 	// If the work days have changed (e.g. by a change in locale) and this alarm
       
   856 	// is a "work day" alarm then the alarm state is updated based upon the new
       
   857 	// work days.
       
   858 	if (aWorkdaysChanged && RepeatDefinition() == EAlarmRepeatDefintionRepeatWorkday)
       
   859 		{
       
   860 		if (!aWorkdays)
       
   861 			{
       
   862 			User::LeaveIfError(doSetStatus(EAlarmStatusDisabled, ETrue));
       
   863 			return agendaAlarmInPast;
       
   864 			}
       
   865 		// Enable the alarm now we have some work days.
       
   866 		const TInt error = doSetStatus(EAlarmStatusEnabled, ETrue);
       
   867 		__ASSERT_ALWAYS(error == KErrNone, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicCannotSetAlarmStatus));
       
   868 		PrepareForNextRepeat();
       
   869 		return agendaAlarmInPast;
       
   870 		}
       
   871 	
       
   872 	TTime timeNow = ASSrvStaticUtils::UtcTimeNow();
       
   873 	// tempTime is used for rounding purposes.  In most cases it is equal to
       
   874 	// NextDueTime().	
       
   875 	TTime tempTime(NextDueTime());
       
   876 	if (timeNow.DaysFrom(NextDueTime()).Int() == 0)
       
   877 		{
       
   878 		TTimeIntervalMinutes MinuteInterval;
       
   879 		timeNow.MinutesFrom(NextDueTime(), MinuteInterval);
       
   880 		tempTime = NextDueTime();
       
   881 		tempTime -= MinuteInterval; 
       
   882 		}
       
   883 
       
   884 	const TInt days(timeNow.DaysFrom(tempTime).Int() > 0 ?
       
   885 		timeNow.DaysFrom(tempTime).Int() :
       
   886 		timeNow.DaysFrom(NextDueTime()).Int());
       
   887 
       
   888 	// If the time has changed to the past we do not re-expire if the time
       
   889 	// crossed a previous boundary for this alarm.  If the time has changed
       
   890 	// to the future and crossed a repeat boundary then we expire
       
   891 	// immediately.
       
   892 	
       
   893 	switch(RepeatDefinition())
       
   894 		{
       
   895 	case EAlarmRepeatDefintionRepeatNext24Hours:
       
   896 		// Is next due time more than 1 day in the future?
       
   897 		if (days <= -1)
       
   898 			{
       
   899 			// Alarm changes to "repeat once" and at a fixed time.
       
   900 			TAlarmCharacteristicsFlags tempAFlags = Characteristics();
       
   901 			tempAFlags.Clear(EAlarmRepeatDefintionRepeatNext24Hours);
       
   902 			tempAFlags.Set(EAlarmRepeatDefintionRepeatOnce);
       
   903 			SetCharacteristicsL(tempAFlags, OriginatingSessionId());
       
   904 			RepeatDefinition() = EAlarmRepeatDefintionRepeatOnce;
       
   905 			}
       
   906 		// Fall through intentionally so that the following case is applied if
       
   907 		// the alarm repeat definition has been changed above from "next 24
       
   908 		// hours" to "repeat once". 
       
   909 
       
   910 	case EAlarmRepeatDefintionRepeatOnce:
       
   911 		timeNow.DateTime().SetSecond(0);
       
   912 		alarmDue = NextDueTime();
       
   913 		if (!iCharacteristics.IsSet(EAlarmCharacteristicsIsFixed))
       
   914 	        {
       
   915 			// We need to compare alarm due time and current time in local.
       
   916 			// Since it is a floating alarm the offset for the alarm due time is
       
   917 	        // taken from previous offset stored with server. 
       
   918 		    alarmDue += ServerData().CachedUtcOffset();
       
   919 		    timeNow += User::UTCOffset();	        
       
   920 	        }
       
   921 		if (days >= 1 || (iCharacteristics.IsSet(EAlarmCharacteristicsDeQueueIfDueTimeInPast) && alarmDue < timeNow))
       
   922 			{
       
   923 			// The new time is at least one day after the original expiry time.
       
   924 			// Alternatively it is an agenda alarm which does not want to be
       
   925 			// notified if it is in the past.  We delete the alarm silently.
       
   926 			if (iCharacteristics.IsSet(EAlarmCharacteristicsDeQueueIfDueTimeInPast) && State() != EAlarmStateNotified)
       
   927 				{
       
   928 				agendaAlarmInPast = ETrue;
       
   929 				}
       
   930 			DeQueue();
       
   931 			}
       
   932 		break;
       
   933 
       
   934 	case EAlarmRepeatDefintionRepeatDaily:
       
   935 	case EAlarmRepeatDefintionRepeatWorkday:
       
   936 	case EAlarmRepeatDefintionRepeatWeekly:
       
   937 #ifdef SYMBIAN_ALARM_REPEAT_EXTENSIONS
       
   938 	case EAlarmRepeatDefinitionRepeatDailyOnGivenDays:
       
   939 #endif
       
   940 		// When days is 0 the alarm would be within 24 hours either in the
       
   941 		// future or in the past in which case there is no need to recalculate
       
   942 		// the next due time.
       
   943 		if (days != 0)
       
   944 			{
       
   945 			PrepareForNextRepeat();
       
   946 			}
       
   947 		break;
       
   948 
       
   949 	default:
       
   950 		__ASSERT_DEBUG(EFalse, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicInvalidAlarmRepeat));
       
   951 		break;
       
   952 		}
       
   953 		
       
   954 	return agendaAlarmInPast;
       
   955 	}
       
   956 
       
   957 
       
   958 //
       
   959 //
       
   960 //
       
   961 
       
   962 
       
   963 //*************************************************************************************
       
   964 /**
       
   965  * @see MASSrvAlarmTimerObserver
       
   966  */
       
   967 void TASSrvAlarm::MATimerHandleAlarmExpired(TAlarmTimerEvent aEvent, TAlarmId aAlarmId)
       
   968 	{
       
   969 	// We're only interested in alarm expiry events relating to this alarm.
       
   970 	if	(aAlarmId != Id())
       
   971 		return;
       
   972 
       
   973 	if	(iInternalServerFlags.IsSet(EInternalServerFlagsNotifyPending))
       
   974 		{
       
   975 		// Map the event onto an error value
       
   976 		TInt completionCode = KErrNone;
       
   977 		switch(aEvent)
       
   978 			{
       
   979 		case EAlarmTimerEventAlarmExpired:
       
   980 			completionCode = KErrNone;
       
   981 			break;
       
   982 		case EAlarmTimerEventTimeOrDateChanged:
       
   983 			completionCode = KErrAbort;
       
   984 			break;
       
   985 		case EAlarmTimerEventTimingError:
       
   986 			completionCode = KErrGeneral;
       
   987 			break;
       
   988 		default:
       
   989 			__ASSERT_DEBUG(EFalse, ASSrvStaticUtils::Fault(ASSrvStaticUtils::EASSrvFaultTimerEventNotHandled));
       
   990 			break;
       
   991 			}
       
   992 
       
   993 		// Now complete the message
       
   994 		NotificationMessageComplete(completionCode);
       
   995 		}
       
   996 	}
       
   997 
       
   998 /**
       
   999 Return the server data object.
       
  1000 
       
  1001 @return The server data object created by the server that owns all the data.
       
  1002 */
       
  1003 CASSrvServerWideData& TASSrvAlarm::ServerData() const
       
  1004 	{
       
  1005 	return iServerWideData;
       
  1006 	}
       
  1007 
       
  1008 
       
  1009 //
       
  1010 //
       
  1011 //
       
  1012 
       
  1013 
       
  1014 //*************************************************************************************
       
  1015 /**
       
  1016  * Complete an outstanding notification request
       
  1017  */
       
  1018 void TASSrvAlarm::NotificationMessageComplete(TInt aCompletionCode)
       
  1019 	{
       
  1020 	if	(iInternalServerFlags.IsSet(EInternalServerFlagsNotifyPending))
       
  1021 		{
       
  1022 		// Complete the outstanding request
       
  1023 		iNotificationMessage.Complete(aCompletionCode);
       
  1024 
       
  1025 		// Update flags to indicate we no longer have a pending 
       
  1026 		// notification message pointer
       
  1027 		iInternalServerFlags.Clear(EInternalServerFlagsNotifyPending);
       
  1028 
       
  1029 		// Reset session identified
       
  1030 		SetOriginatingSessionId(KErrNotFound);
       
  1031 
       
  1032 		// Done with this now
       
  1033 		ServerData().Timer().NotifyAlarmExpiredCancel(*this);
       
  1034 		}
       
  1035 	}
       
  1036 
       
  1037 
       
  1038 /**
       
  1039 Calculate when this alarm is next due to expire.
       
  1040 
       
  1041 @param aAllowableWindow
       
  1042 	This is a delta to apply to the curren time when calculating the next expiry
       
  1043 	time.  The delta is usually 0 seconds, however, when alarms are internalized
       
  1044 	from the backup store, we apply a 59 second delta which allows alarms which
       
  1045 	are less than one minute old to be treated as "not yet expired".  This
       
  1046 	allows devices with unpredictable start up times to show alarm expiry
       
  1047 	dialogs rather than alams silently going missing.
       
  1048 
       
  1049 @return
       
  1050 	KErrNone if the alarm state is consistent, KErrArgument if this method is
       
  1051 	being called for the wrong type of alarm or KErrLocked if a "work day"
       
  1052 	alarm has no valid work days to test itself against.
       
  1053 */
       
  1054 TInt TASSrvAlarm::PrepareForNextRepeat(TTimeIntervalSeconds aAllowableWindow)
       
  1055 	{
       
  1056 	// This should never be called for "repeat once" or "repeat next 24 hour"
       
  1057 	// alarms.
       
  1058 	__ASSERT_DEBUG
       
  1059 		(
       
  1060 		RepeatDefinition() != EAlarmRepeatDefintionRepeatOnce &&
       
  1061 		RepeatDefinition() != EAlarmRepeatDefintionRepeatNext24Hours,
       
  1062 		ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicInvalidAlarmRepeat)
       
  1063 		);
       
  1064 	if (RepeatDefinition() == EAlarmRepeatDefintionRepeatOnce ||
       
  1065 		 RepeatDefinition() == EAlarmRepeatDefintionRepeatNext24Hours
       
  1066 		)
       
  1067 		{
       
  1068 		return KErrArgument;
       
  1069 		}
       
  1070 
       
  1071 	// This alarm has just been acknowledged. If it repeats we need to
       
  1072 	// reschedule it.
       
  1073 	TTime timeNow(ASSrvStaticUtils::UtcTimeNow());
       
  1074 
       
  1075 	// CTimer::At() can complete >1 second early.	
       
  1076 	timeNow += TTimeIntervalSeconds(KAlarmServerCTimerFudgeTimeInSeconds);
       
  1077 
       
  1078 	TTimeIntervalDays daysToAddFromNow = 0;
       
  1079 	TTimeIntervalDays rollOverDaysToAddFromNow = 7;
       
  1080 
       
  1081 	// Update the nextRepeat object to contain the right hour and minutes
       
  1082 	// component from the last repeat time.
       
  1083 	TTime nextRepeat;
       
  1084 	
       
  1085 	TDateTime nextRepeatDateTime = timeNow.DateTime();
       
  1086 	const TDateTime oldTime = OriginalExpiryTime().DateTime();
       
  1087 	nextRepeatDateTime.SetHour(oldTime.Hour());
       
  1088 	nextRepeatDateTime.SetMinute(oldTime.Minute());
       
  1089 	nextRepeat = nextRepeatDateTime;
       
  1090 	
       
  1091 	// Use local time to find the current day number in the week. 
       
  1092 	TTime nextRepeatLocal = nextRepeat + User::UTCOffset();
       
  1093 
       
  1094 	// Remove seconds and microseconds part.
       
  1095 	ASSrvStaticUtils::RoundTimeDownToTheMinute(nextRepeat);
       
  1096 	
       
  1097 	switch (RepeatDefinition())
       
  1098 		{
       
  1099 	case EAlarmRepeatDefintionRepeatDaily:
       
  1100 		{
       
  1101 		// The time is fixed, but the day changes.
       
  1102 		rollOverDaysToAddFromNow = 1;
       
  1103 		}
       
  1104 		break;
       
  1105 
       
  1106 	case EAlarmRepeatDefintionRepeatWeekly:
       
  1107 		{
       
  1108 		// Same day, next week. 
       
  1109 		daysToAddFromNow = OriginalExpiryTime().DayNoInWeek() - timeNow.DayNoInWeek();
       
  1110 		}
       
  1111 		break;
       
  1112 	
       
  1113 	case EAlarmRepeatDefintionRepeatWorkday:
       
  1114 		{
       
  1115 		// Same time at next work day.
       
  1116 		const TUint KWorkDays = TLocale().WorkDays();
       
  1117 		if (!KWorkDays)
       
  1118 			{
       
  1119 			// If there are no work days defined then we disable the alarm.
       
  1120 			// When a change in work days is detected (caused by a change in
       
  1121 			// locale) the HandleDateTimeChanged() method will be called and the
       
  1122 			// alarm will be enabled again.
       
  1123 #ifdef _DEBUG
       
  1124 			const TInt ret = 
       
  1125 #endif
       
  1126 			doSetStatus(EAlarmStatusDisabled, ETrue);
       
  1127 			__ASSERT_DEBUG(ret == KErrNone, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicCannotSetAlarmStatus));
       
  1128 			return KErrLocked;
       
  1129 			}
       
  1130         ASSrvStaticUtils::DaysUntilNextActiveAlarmDay(daysToAddFromNow,
       
  1131         	rollOverDaysToAddFromNow, nextRepeatLocal.DayNoInWeek(), KWorkDays);
       
  1132 		}
       
  1133 		break;
       
  1134 	
       
  1135 #ifdef SYMBIAN_ALARM_REPEAT_EXTENSIONS
       
  1136 	case EAlarmRepeatDefinitionRepeatDailyOnGivenDays:
       
  1137 		{
       
  1138 		// Same time at next alarm day.
       
  1139         ASSrvStaticUtils::DaysUntilNextActiveAlarmDay(daysToAddFromNow,
       
  1140         	rollOverDaysToAddFromNow, nextRepeatLocal.DayNoInWeek(),
       
  1141         	AlarmDays());
       
  1142 		}
       
  1143 		break;
       
  1144 #endif
       
  1145 
       
  1146 	default:
       
  1147 		{
       
  1148 		__ASSERT_DEBUG(EFalse, ASSrvStaticUtils::Panic(ASSrvStaticUtils::EASSrvPanicInvalidAlarmRepeat));
       
  1149 		}
       
  1150 		break;
       
  1151 		}
       
  1152 
       
  1153 	// Add the number of days on so that we repeat on the right day in the
       
  1154 	// future.
       
  1155 	nextRepeat += daysToAddFromNow;
       
  1156 
       
  1157     // If the NextDueTime() is after the nextRepeat time that has been
       
  1158 	// calculated so far then the alarm has already notified and been
       
  1159 	// rescheduled for its next repeat.  We don't enable the allowable window in
       
  1160 	// this case because it is possible that the alarm could be rescheduled for
       
  1161 	// the last repeat (that it has already notified about) if it is within the
       
  1162 	// allowable window.
       
  1163 	if (NextDueTime() <= nextRepeat)
       
  1164 		{
       
  1165 		timeNow -= aAllowableWindow;
       
  1166 		}
       
  1167 
       
  1168 	// If the calculated time is still before the current time then add the
       
  1169 	// roll-over period too.  This mirrors the EALWL repeat code.  We also allow
       
  1170 	// a window (specified as a parameter to this function in seconds) so that
       
  1171 	// during startup we don't expire alarms which are less than a minute old.
       
  1172 	if (nextRepeat < timeNow)
       
  1173 	    {
       
  1174 	    nextRepeat += rollOverDaysToAddFromNow;
       
  1175         // If calculated time after adding one rollOverDay is still before the
       
  1176 	    // current time then move it one day forward.
       
  1177         if (RepeatDefinition() == EAlarmRepeatDefintionRepeatWorkday && 
       
  1178         	nextRepeat - TTimeIntervalDays(rollOverDaysToAddFromNow.Int() - 1) < timeNow)
       
  1179             {
       
  1180             nextRepeat += TTimeIntervalDays(1);
       
  1181             }
       
  1182 	    }
       
  1183 
       
  1184 	// Update next due time and original expiry time.
       
  1185 	NextDueTime() = nextRepeat;
       
  1186 	OriginalExpiryTime() = nextRepeat;
       
  1187 
       
  1188 	return KErrNone;
       
  1189 	}
       
  1190 
       
  1191 
       
  1192 /**
       
  1193 Sets the alarm's sound timing cycle index number.
       
  1194 
       
  1195 @param aSoundNumber The alarm's sound timing cycle index number.
       
  1196 */
       
  1197 void TASSrvAlarm::SetSoundTimingCycleIndex(TASSrvAlarmSoundCycleNumber aSoundNumber)
       
  1198 	{
       
  1199 	iSoundPeriodCycleNumber = aSoundNumber;
       
  1200 	}
       
  1201 
       
  1202 
       
  1203 /**
       
  1204 Gets the alarm's sound timing cycle index number.
       
  1205 
       
  1206 @return The alarm's sound timing cycle index number.
       
  1207 */
       
  1208 TASSrvAlarmSoundCycleNumber TASSrvAlarm::SoundTimingCycleIndex() const
       
  1209 	{
       
  1210 	return iSoundPeriodCycleNumber;
       
  1211 	}
       
  1212 
       
  1213 
       
  1214 /**
       
  1215  * Internalize of the Alarm Queue after a Restore (from a backup)
       
  1216  * deletes the old queue.  This method sends a Cancel notification for
       
  1217  * a 'Session Alarm' to its the TRequestStatus object.
       
  1218  */
       
  1219 void TASSrvAlarm::CancelSessionAlarm()
       
  1220 	{
       
  1221 	// If there was a notification request then we complete it
       
  1222 	if(iCharacteristics.IsSet(EAlarmCharacteristicsSessionSpecific))
       
  1223 		NotificationMessageComplete(KErrCancel);
       
  1224 	}
       
  1225 	
       
  1226 /**
       
  1227 Set alarm status and update disable flag.
       
  1228 
       
  1229 @param aStatus
       
  1230 	Alarm status to set.
       
  1231 	
       
  1232 @param aAutoDisabled
       
  1233 	If it's called by locale change handler.
       
  1234 */
       
  1235 TInt TASSrvAlarm::doSetStatus(TAlarmStatus aStatus, TBool aAutoDisabled)
       
  1236 	{
       
  1237 	const TAlarmStatus oldStatus = Status();
       
  1238 	
       
  1239 	if (oldStatus == aStatus)
       
  1240 		{
       
  1241 		if (aStatus == EAlarmStatusDisabled && !aAutoDisabled) 
       
  1242 			{
       
  1243 			//Change from auto-disabled to manual-disabled
       
  1244 			iFlags.Set(EASShdAlarmFlagsPermanentDisabled);	
       
  1245 			}
       
  1246 		return KErrNone;	
       
  1247 		}
       
  1248 	
       
  1249 	switch (aStatus)
       
  1250 		{
       
  1251 	case EAlarmStatusEnabled:
       
  1252 		if (RepeatDefinition() == EAlarmRepeatDefintionRepeatWorkday)
       
  1253 			{
       
  1254 			if (aAutoDisabled && iFlags.IsSet(EASShdAlarmFlagsPermanentDisabled))
       
  1255 				{
       
  1256 				// Called by locale change handler and we will not enable the
       
  1257 				// alarm as it has been disabled manually.
       
  1258 				return KErrNone;
       
  1259 				}
       
  1260 				
       
  1261 			// Calculate its next valid expiry date.  Will return KErrLocked if
       
  1262 			// there are no work days defined.
       
  1263 			const TInt error = PrepareForNextRepeat();
       
  1264 			if (error != KErrNone)
       
  1265 				{
       
  1266 				return error;
       
  1267 				}
       
  1268 			}
       
  1269 		iFlags.Clear(EASShdAlarmFlagsPermanentDisabled);	
       
  1270 		break;
       
  1271 
       
  1272 	case EAlarmStatusDisabled:
       
  1273 		if(aAutoDisabled)
       
  1274 			{
       
  1275 			iFlags.Clear(EASShdAlarmFlagsPermanentDisabled);	
       
  1276 			}
       
  1277 		else
       
  1278 			{
       
  1279 			iFlags.Set(EASShdAlarmFlagsPermanentDisabled);	
       
  1280 			}	
       
  1281 		break;
       
  1282 
       
  1283 	default:
       
  1284 		__ASSERT_DEBUG(EFalse, ASSrvStaticUtils::Fault(ASSrvStaticUtils::EASSrvFaultAlarmStatusNotHandled));
       
  1285 		break;
       
  1286 		}
       
  1287 
       
  1288 	// Update status now.
       
  1289 	iStatus = aStatus;
       
  1290 
       
  1291 	// Notify queue so that it can work out if it needs to do
       
  1292 	// some re-ordering (only do this if we've been queued, and therefore
       
  1293 	// have an alarm id).
       
  1294 	if (Id() != KNullAlarmId)
       
  1295 		{
       
  1296 		ServerData().Queue().HandleAlarmStatusChanged(Id(), oldStatus);
       
  1297 		}
       
  1298 
       
  1299 	return KErrNone;
       
  1300 	}
       
  1301