There are a bunch of pieces on this one.
You need:
1. an activity(RingBellActivity) to do something
2. a broadcast receiver (AlarmReceiver) that ties to the alarm manager to receive the alarm request
3. a setup activity(MainActivity) to schedule the task(tied to the MAIN, LAUNCHER)
4. an activity to schedule it next time the android reboots
Special bonus for…
5. A way to turn it off
6. a behind the scenes activity with no user interaction(RingBellService)
Step 0 – xml files
res/layout/main_activity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TimePicker
android:id="@+id/timePicker1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginTop="17dp" />
<Button
android:id="@+id/btnGo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/timePicker1"
android:layout_marginTop="44dp"
android:text="Wakeme" />
<Button
android:id="@+id/btnStop"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/btnGo"
android:text="Cancel" />
<Button
android:id="@+id/btnTest"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/btnStop"
android:text="Test" />
</RelativeLayout>
manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.steelmarble.ontime"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".RingBellActivity"
android:theme="@android:style/Theme.NoDisplay">
</activity>
<receiver android:name=".AlarmReceiver" android:process=":remote"></receiver>
<service android:name="RingBellService"></service>
<receiver android:name="Autostart">
<intent-filter>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="com.steelmarble.ontime.AUTOSTART" />
</intent-filter>
</receiver>
</application>
</manifest>
Step 1
public class RingBellActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "DingALing", System.currentTimeMillis());
// This is intent, we want to launch when user clicks on the notification.
Intent intentTL = new Intent(this, MainActivity.class);
notification.setLatestEventInfo(this, "TIME", "To Do Something!",
PendingIntent.getActivity(this, 0, intentTL, PendingIntent.FLAG_CANCEL_CURRENT));
notification.flags = Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL;
nm.notify(1, notification);
finish();
}
}
2. a broadcast receiver (AlarmReceiver) that ties to the alarm manager to receive the alarm request
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent scheduledIntent = new Intent(context, RingBellActivity.class);
scheduledIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(scheduledIntent);
}
}
3. a setup activity(MainActivity) to schedule the task(tied to the MAIN, LAUNCHER)
public class MainActivity extends Activity {
public static final String PREFERENCE_FILENAME = "AppGamePrefs";
TimePicker timePicker;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// setup UI time scheuler
timePicker=(TimePicker) findViewById(R.id.timePicker1);
SharedPreferences prefs = getSharedPreferences(PREFERENCE_FILENAME,MODE_PRIVATE);
timePicker.setCurrentHour(prefs.getInt("hour",10));
timePicker.setCurrentMinute(prefs.getInt("min",0));
// Schedule it...
Button b = (Button) findViewById(R.id.btnGo);
b.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
Date stamp = cal.getTime();
stamp.setHours(timePicker.getCurrentHour());
stamp.setMinutes(timePicker.getCurrentMinute());
PendingIntent pendingIntent = getAlarmPendingIntent(MainActivity.this);
AlarmManager manager=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent); // kill any other outstanding requests first
manager.setRepeating(AlarmManager.RTC_WAKEUP, stamp.getTime(), 10*1000, pendingIntent);
// or as a one-shot
//manager.set(AlarmManager.RTC_WAKEUP, stamp.getTime(), pendingIntent);
finish();
}
});
// unschedule
Button b2 = (Button) findViewById(R.id.btnStop);
b2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
AlarmManager manager=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
manager.cancel(getAlarmPendingIntent(MainActivity.this));
finish();
}
});
// special bonus bonus - test the reboot code without rebooting
// click wakeme(to set), cancel(to turn it off), test(fake the reboot by calling custom intent)
Button b3 = (Button) findViewById(R.id.btnTest);
b3.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction(Autostart.CUSTOM_INTENT);
sendBroadcast(intent);
}
});
}
@Override
public void onDestroy(){
// save the preferences
super.onDestroy();
SharedPreferences.Editor editor = getSharedPreferences(PREFERENCE_FILENAME,MODE_PRIVATE).edit();
editor.putInt("hour", timePicker.getCurrentHour());
editor.putInt("min", timePicker.getCurrentMinute());
editor.commit();
}
// one stop shop so we can set/cancel without recoding all over the place
public static PendingIntent getAlarmPendingIntent(Context context){
Intent intent= new Intent(context,AlarmReceiver.class);
return PendingIntent.getBroadcast(context,0, intent,0);
}
4. an activity to schedule it next time the android reboots
public class Autostart extends BroadcastReceiver {
public static final String CUSTOM_INTENT = "com.steelmarble.ontime.AUTOSTART";
@Override
public void onReceive(Context context, Intent arg1) {
String text="Coming right up";
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
SharedPreferences prefs = context.getSharedPreferences(MainActivity.PREFERENCE_FILENAME,context.MODE_PRIVATE);
Date dStamp= cal.getTime();
Date dNow = cal.getTime();
dStamp.setHours(prefs.getInt("hour",1));
dStamp.setMinutes(prefs.getInt("minute",23));
Long stamp = dStamp.getTime();
Long now = dNow.getTime();
if(now>stamp){
// to late for today, avoid immediate trigger and schedule for tomorrow
stamp+= AlarmManager.INTERVAL_DAY; // add one day
text="Scheduled for tomorrow";
}
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "DingALing", System.currentTimeMillis());
// This is intent, we want to launch when user clicks on the notification.
Intent intentTL = new Intent(context, MainActivity.class);
notification.setLatestEventInfo(context, "TIME", text,
PendingIntent.getActivity(context, 0, intentTL, PendingIntent.FLAG_CANCEL_CURRENT));
notification.flags = Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL;
nm.notify(1, notification);
PendingIntent pendingIntent=MainActivity.getAlarmPendingIntent(context);
AlarmManager manager=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
manager.setRepeating(AlarmManager.RTC_WAKEUP, stamp, 10*1000, pendingIntent);
}
}
Special bonus for…
5. A way to turn it off
i'd add a checkbox in the main_activity and tie it to preferences, then use that on autostart
6. a behind the scenes activity with no user interaction (sounds like a service to me or a fast alternative)
6a. Create a service
public class RingBellService extends Service {
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "RingBellService", Toast.LENGTH_LONG).show();
}
}
6b. Change the AlarmReceiver to issue a
public class AlarmReceiver extends BroadcastReceiver {
/* Start some run once service */
@Override
public void onReceive(Context context, Intent intent) {
Intent scheduledIntent = new Intent(context, RingBellService.class);
scheduledIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(scheduledIntent);
}
}
Bugs and More
Did I see the preferences get reset to default?