これが正しい方法かどうかわかりませんが、アラームとして機能したのでメモ
Androidでアラームを鳴らすためには、
- アラーム時に起動するサービスをPendingIntentを使って指定する
- 指定されたタイミングで起動したサービスからsendBroadcastを利用してレシーバーを起こす
- 起こされたレシーバーからアラーム時に起動するActivityをIntentによって指定、起動
というプロセスでいけるようです。
めんどくさいですが。
サービスとレシーバーを利用するためには権限が必要なため、Manifestに記載する
必要な部分のみ書いています。
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application>
<!-- MainActivityなど -->
<receiver android:name="AlarmReceiver" >
<intent-filter>
<action android:name="MyAlarmAction"></action>
</intent-filter>
</receiver>
<service android:name="MyAlarmService" ></service>
<activity android:name="AlarmNotificationActivity" ></activity>
</application>
actionにMyAlarmActionというものをセットしていますが、
これはサービスからレシーバーを起動する際に利用する識別子のようなものです。多分。
アラームの設定自体を行うMyAlarmManager.javaは以下の通り
public class MyAlarmManager {
Context c;
AlarmManager am;
private PendingIntent mAlarmSender;
private static final String TAG = MyAlarmManager.class.getSimpleName();
public MyAlarmManager(Context c){
// 初期化
this.c = c;
am = (AlarmManager)c.getSystemService(Context.ALARM_SERVICE);
Log.v(TAG,"初期化完了");
}
public void addAlarm(int alarmHour, int alarmMinute){
// アラームを設定する
mAlarmSender = this.getPendingIntent();
// アラーム時間設定
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
// 設定した時刻をカレンダーに設定
cal.set(Calendar.HOUR_OF_DAY, alarmHour);
cal.set(Calendar.MINUTE, alarmMinute);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
// 過去だったら明日にする
if(cal.getTimeInMillis() < System.currentTimeMillis()){
cal.add(Calendar.DAY_OF_YEAR, 1);
}
Toast.makeText(c, String.format("%02d時%02d分に起こします", alarmHour, alarmMinute), Toast.LENGTH_LONG).show();
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), mAlarmSender);
Log.v(TAG, cal.getTimeInMillis()+"ms");
Log.v(TAG, "アラームセット完了");
}
public void stopAlarm() {
// アラームのキャンセル
Log.d(TAG, "stopAlarm()");
am.cancel(mAlarmSender);
spm.updateToRevival();
}
private PendingIntent getPendingIntent() {
// アラーム時に起動するアプリケーションを登録
Intent intent = new Intent(c, MyAlarmService.class);
PendingIntent pendingIntent = PendingIntent.getService(c, PendingIntent.FLAG_ONE_SHOT, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
}
PendingIntentのFLAGについてはhttp://y-anz-m.blogspot.jp/2011/07/androidappwidget-pendingintent-putextra.htmlが詳しいです。
アラームを更新するのか、あるいは前のままにするのか等、用途に合わせて設定して下さい。
getPendingIntent()
で定義しているように、PendingIntent.getService
で呼び出すサービスを指定します。
MyAlarmManagerによって、アラームの時刻を設定したいActivityなどからaddAlarm(hour, minute)
で簡単にアラームをセットできます。
次にサービスを見ます。
public class MyAlarmService extends Service {
private static final String TAG = MyAlarmService.class.getSimpleName();
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
Thread thr = new Thread(null, mTask, "MyAlarmServiceThread");
thr.start();
Log.v(TAG,"スレッド開始");
}
// アラーム用サービス
Runnable mTask = new Runnable() {
public void run() {
// アラームを受け取るActivityを指定
Intent alarmBroadcast = new Intent();
// ここでActionをセットする(Manifestに書いたものと同じであれば何でもよい)
alarmBroadcast.setAction("MyAlarmAction");
// レシーバーへ渡す
sendBroadcast(alarmBroadcast);
// 役目を終えたサービスを止める
MyAlarmService.this.stopSelf();
Log.v(TAG,"サービス停止");
}
};
}
サービスからのBroadCastなIntentを受け取るレシーバー
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// アラームを受け取って起動するActivityを指定、起動
Intent notification = new Intent(context, AlarmNortificationActivity.class);
// 画面起動に必要
notification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(notification);
}
}
だんだんコードが減ってきて、言うことが無くなってきてます。
AlarmReceiverによって起こされるActivity
public class AlarmNortificationActivity extends Activity {
private MediaPlayer mp;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm_notification);
// スクリーンロックを解除する
// 権限が必要
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Toast.makeText(this, "アラーム!", Toast.LENGTH_SHORT).show();
}
@Override
public void onStart() {
super.onStart();
Toast.makeText(getApplicationContext(), "アラームスタート!", Toast.LENGTH_LONG).show();
// 音を鳴らす
if (mp == null)
// resのrawディレクトリにtest.mp3を置いてある
mp = MediaPlayer.create(this, R.raw.test);
mp.start();
}
@Override
public void onDestroy() {
super.onDestroy();
stopAndRelaese();
}
private void stopAndRelaese() {
if (mp != null) {
mp.stop();
mp.release();
}
}
@Override
protected void onResume() {
super.onResume();
alarmNowText = (TextView) findViewById(R.id.alarm_now_time);
handler.sendEmptyMessage(WHAT);
// mam.stopAlarm();
}
}
これでalarm_notification.xml
が表示され、Toastが出るはずです。
意外とめんどくさいアラームのメモでした。
アラームを設定する際のベストプラクティスがよくわかっていないので、アドバイス頂けると嬉しいです。