/* Copyright © 1994 Apple Computer, Inc. All Rights Reserved. author Mike Engber False Alarm v2 This sample illustrates how to set alarms on the Newton. Do not be put off by the large size of the package - most of that space is from a cool sound resource which gets played when the alarm goes off. If this is causing you grief, you can easily replace the sound resource with one of your own choosing. Version History v1 - initial release v2 - rebuilt using new platorm file (new alarm stub) - bug fix - if the FalseAlarm app was closed when the alarm went off, DoAlarm blindly sent messages to a child view (that didn't exist since FalseAlarm was closed) */ It is IMPORTANT that you have a copy of AlarmPkgUtil and thoroughly read AlarmPkgUtil.ReadMe before you start working with alarms. Using the alarm functions may cause about ~4K of your user's internal store to be permanently taken up (with alarm code). Currently, the alarm functions are the only ones in the NTK platform file that do this permanent installation of code. Read AlarmPkgUtil.ReadMe for details. Alarm API Description The alarm API provides a way for 3rd parties to set alarms ala the built-in Calendar app. These alarms will execute at the specified time, waking up the Newton if necessary. AddAlarm(alarmKey,time,notifyArgs,callBackFn,callBackParams) return value - alarmKey alarmKey - A string used to uniquely identify the alarm. You should use your signature or app symbol as a suffix to guarantee uniqueness among different applications. e.g. "wakeUpReg:PIEDTS". If there is already an alarm with with the specified alarmKey, it is removed and replaced with the new alarm. time - Integer encoding the time of the alarm in minutes since midnight, January 1, 1904. (ala Time()) notifyArgs - An array of 3 arguments to pass to Notify when the alarm goes off. (passing nil means Notify won't be called) callBackFn - A closure to be executed when your alarm goes off. (passing nil means no closure should be executed). callBackParams - parameters to be passed to callBackFn. (pass nil if no callBackFn is being used) AddAlarm is used to register an alarm to execute at a specified time. The alarm will wake up the Newton if necessary. You can specify a system notify message to be displayed. You can take other actions by specifying a closure. The time an alarm executes is approximate. There may be multiple alarms scheduled for the same time, if one of the alarms does something time consuming it will delay the execution of other alarms (or take long enough so that other alarms go off). In the case of simultaneously scheduled alarms the execution order is unspecified. Once an alarm "goes off," it's removed. So you only need to call RemoveAlarm if you want to abort an alarm. If you want to change an existing alarm, simply call AddAlarm with the same alarmKey. The new version of the alarm will replace the old one. If you want to schedule an alarm periodically, your callBackFn should call AddAlarm to schedule the next occurence. Debugging your callBackFn will be difficult. When it is called, any exceptions raised will be caught and ignored by the alarm mechanism. I suggest debugging your callBackFn's thoroughly before passing them to AddAlarm. Alarms are kept in a soup so they will persist across restarts and when your package is removed. Note that this means the argument you pass will be stored in a soup - which means they will be deeply copied. You should be carful to avoid indirectly referencing large objects For example, closures reference their lexical environment and self at the time they are created. Functions defined in "Project Data" or evaluate slot should be ok. Functions created in the NTK inspector are not (their lexical environment is the Newton global variables). Further note that when your alarm runs your app may not be open. In fact, your app may not even be installed. You need to be sure and handle these cases appropriately. e.g. if GetRoot().(kAppSymbol) then GetRoot().(kAppSymbol):DoSomething() else GetRoot():Notify(...) RemoveAlarm(alarmKey) return value - nil if no alarm with that key was found. An unspecified non-nil value if the alarm was found and removed. alarmKey - The unique string passed to AddAlarm which identifies the alarm. RemoveAlarm unschedules an alarm. If you want your app's alarms to execute only if your app is installed, you'll need to call RemoveAlarm in your remove script. GetAlarm(alarmKey) return value - frame containing the 5 slots described below or nil if no alarm is found. This frame and it contents should not be modified Any other (undocumented) slots you find in it should be ignored. key: the unique string which identifies the alarm, time: the time at which the alarm will "go off" notifyArgs: array of 3 argument for Notify (or nil), callBackFn: closure (or nil), callBackParams: array of arguments for callBackFn (or nil) alarmKey - The unique string passed to AddAlarm which identifies the alarm. GetAlarm returns information on the specified alarm. GetAppAlarmKeys(alarmKeySuffix) return value - array of alarmKeys (strings) alarmKeySuffix - string - specifies a suffix with which all your alarmKeys end. E.g. ":PIEDTS" or ":AlarmSample1:PIEDTS" Returns an array of all an app's alarmKeys. They will be in execution order (earliest to latest). RemoveAppAlarms(alarmKeySuffix) return value - integer, the number of alarms removed alarmKeySuffix - string - specifies a suffix with which all your alarmKeys end. E.g. ":PIEDTS" or ":AlarmSample1:PIEDTS" Removes all of an app's alarms. This would be a good routine to call in your RemoveScript if your alarms can't meaningfully execute when your app is not installed. Usage Notes: It is intended that apps will be courteous in their usage of alarms. Limiting apps to a single alarm seems too harsh. On the other hand, we don't want apps scheduling a daily wake-up alarm for the next year by scheduling 365 different alarms. Remember, each alarm you schedule takes up space in the Newton's internal store. Similarly, your alarm actions should be quick so you don't block other alarms. If you need to do something time consuming or repetative, use a deferred action or set up an idle script. Note that idle scripts stop when the Newton goes to sleep. So using an idle script can only ensure the user notice your alarm next time they turn on the Newton. You can set more alarms to make sure the Newton wakes up periodically and tries to get the user's attention. However, each wake up uses power so you probably want to put a limit on this or you will eventually drain their Newton.