前回は AlarmManger タイマー機能 でアラームを発生し BroadcastReceiver で受け取りました。今回は、その受け取ったアラームを NotificationManager を使って通知してみたいと思います。
2021.2.1
NotificationChannel
Notification、通知のことですが「時間になりました。」などの通知がStatus barや通知ドロワーに表示されるものです。
同時に通知音やバイブレータでユーザーにお知らせする機能です。
API level 26からは NotificationChannel が追加されました。アプリの通知のプライオリティを設定することができます。
1 2 3 4 5 6 |
IMPORTANCE_UNSPECIFIED // 優先度低い IMPORTANCE_NONE IMPORTANCE_MIN IMPORTANCE_LOW IMPORTANCE_DEFAULT IMPORTANCE_HIGH // 最高の優先度 |
また、アイコンに通知があった場合に通知ドットをつけることができます。いわゆるバッジです。また長押しするとメッセージをダイアログで出したりと色々とChannelで設定することができます。
NotificationManager
BroadcastReceiverを継承したクラスの onReceive() でアラームを受け取り通知する設定です。
NotificationManager:
インスタンスは getSystemService() を使って以下のように生成
1 2 |
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); |
NotificationChannel:
1 2 3 4 5 6 7 |
String channelId = "default"; NotificationChannel channel = new NotificationChannel( channelId, title, NotificationManager.IMPORTANCE_DEFAULT); channel.setDescription(message); |
NotificationCompat.Builder:
channel IDを引数として
1 |
NotificationCompat.Builder(Context context, String channelId) |
例えばこのように設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId) .setSmallIcon(android.R.drawable.btn_star) .setContentTitle("My notification") .setContentText(message) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .setAutoCancel(true); NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context); // 通知 notificationManagerCompat.notify(R.string.app_name, builder.build()); |
notify() が最終的に表示させる設定です。
notify(int id, Notification notification)
Alarm を PendingIntent で設定
10秒後のアラームを設定してみます。以前このページで繰り返しをやっていましたがDoze モードの対応が必要なので簡略化のため単発アラームにしました。(Dozeモードでもアラームを使う場合は以下のように色々と設定する必要があります。)
BroadcastReceiver でそれぞれを区別するために受け取るためにgetBroadcast() 第二引数、requestCode を設定して Intent に追加して送ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); // 10秒の遅れ calendar.add(Calendar.SECOND, 10); Intent intent = new Intent(getApplicationContext(), AlarmNotification.class); intent.putExtra("RequestCode",requestCode); pending = PendingIntent.getBroadcast( getApplicationContext(),requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // アラームをセットする am = (AlarmManager) getSystemService(ALARM_SERVICE); // 10秒後 am.setExact( AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pending); |
アラームをキャンセル
単発アラームですが一応cancel の設定もしておきます。
登録したものと同じIntentとPendingIntentからAlarmManagerを設定して
cancel(pending)を呼び出して解除します。
1 2 3 4 5 6 |
Intent indent = new Intent(getApplicationContext(), AlarmNotification.class); PendingIntent pending = PendingIntent.getBroadcast(getApplicationContext(), 0, indent, 0); // アラームを解除する AlarmManager am = (AlarmManager)MainActivity.this.getSystemService(ALARM_SERVICE); am.cancel(pending); |
サンプルコード
コードをまとめてみます
AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.testnotificationmanagerrepeat"> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".AlarmNotification" android:process=":remote" > </receiver> </application> </manifest> |
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
//package your.package.name; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Intent; import android.util.Log; import android.widget.Button; import android.widget.Toast; import java.util.Calendar; public class MainActivity extends AppCompatActivity { private AlarmManager am; private PendingIntent pending; private final int requestCode = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button buttonStart = this.findViewById(R.id.button_start); buttonStart.setOnClickListener(v -> { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); // 10sec calendar.add(Calendar.SECOND, 10); Intent intent = new Intent(getApplicationContext(), AlarmNotification.class); intent.putExtra("RequestCode",requestCode); pending = PendingIntent.getBroadcast( getApplicationContext(),requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // アラームをセットする am = (AlarmManager) getSystemService(ALARM_SERVICE); if (am != null) { am.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pending); // トーストで設定されたことをを表示 Toast.makeText(getApplicationContext(), "alarm start", Toast.LENGTH_SHORT).show(); Log.d("debug", "start"); } }); // アラームの取り消し Button buttonCancel = findViewById(R.id.button_cancel); buttonCancel.setOnClickListener(v -> { Intent indent = new Intent(getApplicationContext(), AlarmNotification.class); PendingIntent pending = PendingIntent.getBroadcast( getApplicationContext(), requestCode, indent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // アラームを解除する AlarmManager am = (AlarmManager)MainActivity.this. getSystemService(ALARM_SERVICE); if (am != null) { am.cancel(pending); Toast.makeText(getApplicationContext(), "alarm cancel", Toast.LENGTH_SHORT).show(); } else{ Log.d("debug", "null"); } }); } } |
AlarmNotification.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
//package your.package.name; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import java.text.SimpleDateFormat; import java.util.Locale; public class AlarmNotification extends BroadcastReceiver { @Override // データを受信した public void onReceive(Context context, Intent intent) { int requestCode = intent.getIntExtra("RequestCode",0); PendingIntent pendingIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); String channelId = "default"; // app name String title = context.getString(R.string.app_name); long currentTime = System.currentTimeMillis(); SimpleDateFormat dataFormat = new SimpleDateFormat("HH:mm:ss", Locale.JAPAN); String cTime = dataFormat.format(currentTime); // メッセージ + 11:22:331 String message = "時間になりました。 "+cTime ; // Notification Channel 設定 NotificationChannel channel = new NotificationChannel(channelId, title, NotificationManager.IMPORTANCE_DEFAULT); channel.setDescription(message); NotificationManager notificationManager = // (NotificationManager)context.getSystemService(NotificationManager.class); (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.createNotificationChannel(channel); NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId) .setSmallIcon(android.R.drawable.btn_star) .setContentTitle("My notification") .setContentText(message) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .setAutoCancel(true); NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context); // 通知 notificationManagerCompat.notify(R.string.app_name, builder.build()); } } |
一応レイアウトも
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#dfe" android:orientation="vertical" android:gravity="center" tools:context=".MainActivity"> <Button android:id="@+id/button_start" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_margin="10dp" android:text="@string/start" /> <Button android:id="@+id/button_cancel" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_margin="10dp" android:text="@string/cancel" /> </LinearLayout> |
リソースです
strings.xml
1 2 3 4 5 |
<resources> <string name="app_name">YourAppName</string> <string name="start">Start</string> <string name="cancel">Cancel</string> </resources> |
これで10秒後に以下の変化が現れます
- アラーム音
- 通知ドロワーを引き出すとメッセージ
- ステータスバーにアラームアイコンが表示
- アプリのアイコンに通知ドット(バッジ)が現れ、長押しするとメッセージが出ます
- アラームが発砲しない場合:「設定」「通知」で通知を許可しているか確認!
関連:
- AlarmManagerをBroadcastRecieverと使う
- Alarm を NotificationManager で通知する
- Doze mode で AlarmManager の繰り返しアラームを実装するには
- アプリの restart
References:
通知を作成する – Android Developers
NotificationChannel | Android Developers
GitHub – googlesamples/android-NotificationChannels
Notification.Builder | Android Developers