在智能手机日益普及的今天,对手机应用的需求也越来越高。今年生日,决定给自己一个挑战,开发一款功能更全面的智能手机闹钟应用。由于之前使用过许多其他手机,对智能手机内置的闹钟功能感到有些失望。它非常基础,只能设置时间,而且没有更多的自定义选项。因此,决定自己动手,开发一款能够满足需求的闹钟应用。
首先使用了Timer对象,它能够在正确的时间触发事件。唯一的问题是,它无法将手机从待机模式唤醒。经过一番搜索,了解到需要设置系统通知,以便手机能够退出待机状态。在寻找执行原生代码的方法时,发现了OpenNetCF。它提供了一套很好的类库,并且包含了通知功能。
代码实现相对简单。设置一个Timer对象,每小时检查一次即将到来的闹钟事件。如果在接下来的一小时内发现有闹钟,它会设置另一个Timer对象来执行,并设置OpenNETCF.Win32.Notify中的Notify.RunAppAtTime。实际播放闹钟(公鸡打鸣声)的是一个独立的SmartPhone应用,它使用OpenNETCF.Windows.Forms中的SoundPlayer控件来播放Wav文件。
为了持久化闹钟数据,使用了DataSet的ReadXml和WriteXml方法。以下是C#代码示例:
private void GetNextNotificationInfo()
{
this.nextAlarmUp = 0;
DataSet dsAlarms = new DataSet();
if (File.Exists(ConfigFile) == true)
{
dsAlarms.ReadXml(ConfigFile);
if (dsAlarms.Tables.Count != 0 && dsAlarms.Tables[0].Rows.Count != 0)
{
DateTime dtCurrent = DateTime.Now;
long CurrentTimeInTicks = dtCurrent.TimeOfDay.Ticks;
int currentDayOfWeek = (int)dtCurrent.DayOfWeek;
string filterExpression =
"Enabled = true AND TimeInTicks >= " + CurrentTimeInTicks +
"AND Days LIKE '%" +
Convert.ToString(currentDayOfWeek) +
"%'";
string sortExpression =
"TimeInTicks DESC";
DataRow[] drActiveAlarms =
dsAlarms.Tables[0].Select(filterExpression,
sortExpression);
if (drActiveAlarms.Length > 0)
{
DataRow drSelectedAlarm = drActiveAlarms[0];
long SelectedTimeInTicks =
Convert.ToInt64(drSelectedAlarm["TimeInTicks"]);
if (SelectedTimeInTicks > CurrentTimeInTicks)
{
TimeSpan tsSelectedTime = new TimeSpan(SelectedTimeInTicks);
TimeSpan tsCurrentTime = dtCurrent.TimeOfDay;
TimeSpan tsDifference = tsSelectedTime - tsCurrentTime;
if (tsDifference.TotalSeconds < 3600)
{
// set timerNotify to fire 1 minute before alarm time
// and set the AlarmExec to run after a minute
this.nextAlarmUp = Convert.ToInt32(drSelectedAlarm["ID"]);
this.timerNotify.Interval =
Convert.ToInt32(tsDifference.TotalMilliseconds - 60*1000);
this.timerNotify.Enabled = true;
}
else
{
this.nextAlarmUp = 0;
this.timerNotify.Enabled = false;
}
}
}
}
}
}
private void timerNotify_Tick(object sender, System.EventArgs e)
{
this.timerNotify.Enabled = false;
Notify.RunAppAtTime(
this.AppPath +
"SDAlarmExec.exe",
DateTime.Now.AddMinutes(1));
this.ExecuteDisable();
GetNextNotificationInfo();
}
在开发过程中,注意到了一些可能对创建SmartPhone应用有帮助的点:
1. 默认情况下,当将数据保存为XML文件时,文件会创建在根目录。要获取应用程序的路径,需要使用Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName。这会返回/Storage Card/Program Files/SmartAlarm.exe。使用Assembly.GetExecutingAssembly().GetModules()[0].Name获取程序集名称,并将其替换为空字符串,就得到了路径。
2. 构建Cab选项失败。但它确实在Obj/Release文件夹下创建了一个Build.bat文件(如果正在构建发布包)。
3. 更新批处理文件以使用C:\Program Files\Windows CE Tools\wce420\SMARTPHONE 2003\Tools\CabwizSP.exe生成Cab,而不是使用C:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\bin\cabwiz.exe。
4. 从C:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\wce400\armv4复制vsd_setup.dll到C:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\Smartphone\wce400\armv4。
5. 从C:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\wce400\x86复制vsd_setup.dll到C:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\Smartphone\wce400\x86。
6. 对于OpenNetCF,手动在手机上安装OpenNETCF.SDF.smp.armv4.cab。
7. 如果使用OpenNetCF,模拟器默认不再工作。如果想使用模拟器,请将OpenNetCF引用的程序集添加为项目的内容。