guys, I am developing an alarm app in which alarm is triggering good and at the right time but the drawback is when the alarm is ringing with an activity then when we press the home button too it is ringing the real problem is when the application is closed by pressing the home button and pressing or swiping close all apps the application getting destroyed I need something like Google does like showing a notification and playing sound even if the application is closed.
So I think someone is having Idea about this issue.
Here is what from Google Clock
Googel Clock image
Because of android Q, I had developed something that when the user is alive at the time of alarm then we just show notification with the help of this.
public class DismissAlarmNotificationController {
public final int NOTIFICATION_ID = 1;
public static final String INTENT_KEY_NOTIFICATION_ID = "notificationId";
public final String CHANNEL_ID = "channel-01";
private NotificationManager notificationManager;
private Context context;
private final int IMPORTANCE = NotificationManager.IMPORTANCE_HIGH;
public DismissAlarmNotificationController(Context context) {
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
this.context = context;
}
public void showNotification() {
Intent fullScreenIntent = new Intent(context, DismissAlarmActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(context, 0,
fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(
CHANNEL_ID, getChannelName(), IMPORTANCE);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_alarm_on_notification)
.setContentTitle(context.getString(R.string.dismiss_alarm_notification_title))
.setContentText(context.getString(R.string.dismiss_alarm_notification_body, getCurrentTime()))
.setAutoCancel(true)
.addAction(getDismissNotificationAction())
.setFullScreenIntent(fullScreenPendingIntent, true);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
public String getChannelName() {
return context.getString(R.string.app_name) + "Channel";
}
public void cancelNotification() {
notificationManager.cancelAll();
}
private NotificationCompat.Action getDismissNotificationAction() {
Intent dismissIntent = new Intent(context, DismissNotificationReceiver.class);
dismissIntent.putExtra(INTENT_KEY_NOTIFICATION_ID, NOTIFICATION_ID);
PendingIntent dismissNotificationPendingIntent = PendingIntent.getBroadcast(context, 0, dismissIntent, PendingIntent.FLAG_CANCEL_CURRENT);
return new NotificationCompat.Action.Builder(
0,
context.getString(R.string.dismiss_alarm_notification_dismiss_button_title),
dismissNotificationPendingIntent)
.build();
}
private String getCurrentTime() {
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm");
Date currentTime = new Date();
return dateFormat.format(currentTime);
}
}
Thanks in advance.
Give a try to Android's WorkManager!
It lets you run background works even if the app is closed or the phone has been restarted.
Hope it will help!
Related
I have created a sample notification for a project I am currently working on, using this code in the onCreate method of my Main Activity.
I have also got a TimePicker Fragment class, which as the name suggests, opens up a time picker dialogue which allows the user to set a specific time of day. Then, the hour and minutes are stored in DataSite.class, which holds a number of get and set methods. Below is the code for TimePicker.class:
public class TimePickerFragment extends DialogFragment
implements TimePickerDialog.OnTimeSetListener {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the current time as the default values for the picker
final Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
// Create a new instance of TimePickerDialog and return it
return new TimePickerDialog(getActivity(), this, hour, minute,
DateFormat.is24HourFormat(getActivity()));
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
DataSite ds = new DataSite();
ds.setHour(hourOfDay);
ds.setMinute(minute);
}
}
In short, I would like to schedule the createNotificationChannel(); method call on the Main Activity, according to the hour and minutes the user has selected. As I said, the time information is stored in DataSite.
I have gotten the time picker working, and the notification shows as expected. All that I need now is a way to combine these two functionalities. As far as I can tell from other forum posts, I will have to use the Alarm Manager, but nothing I have read elsewhere works for me.
Edit: I have attempted to utilize the AlarmManager. Below you can see the full code I currently have so far:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_initial_screen);
.
.
.
.
.
Intent intent = new Intent(this, InitialScreen.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "reflectnotification")
.setSmallIcon(R.drawable.app_icon_background)
.setContentTitle("Reflect Reminder")
.setContentText("Time to Reflect on your selected Goal!")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Time to Reflect on your selected Goal!"))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
createNotificationChannel();
// notificationManager.notify(200, builder.build());
hour = ((DataSite)getApplication()).getHour();
minute = ((DataSite)getApplication()).getMinute();
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
Toast.makeText(getApplicationContext(),"Picked time: "+ hour +":"+minute, Toast.LENGTH_LONG).show();
alarmMgr = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Intent intent2 = new Intent(getApplicationContext(), InitialScreen.class);
alarmIntent = PendingIntent.getBroadcast(getApplicationContext(), 200, intent2, 0);
alarmMgr.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), alarmIntent);
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Reflect Reminder";
String description = "Time to Reflect on your selected Goal!";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel("reflectnotification", name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
If there is an exact time that the notification needs to be sent, you will want to use AlarmManager. See https://developer.android.com/training/scheduling/alarms
The docs describe when to use AlarmManager vs. other APIs: https://developer.android.com/guide/background#alarms
Okay After too much research and fighting with this finally I did it
Note: this is suitable for Android O+ Versions
In Activity Class
button.setOnClickListener(view -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Calendar calendar = Calendar.getInstance();
//10 is for how many seconds from now you want to schedule also you can create a custom instance of Callender to set on exact time
calendar.add(Calendar.SECOND, 10);
//function for Creating [Notification Channel][1]
createNotificationChannel();
//function for scheduling the notification
scheduleotification(calendar);
}
});
code for createNotificationChannel()
#RequiresApi(api = Build.VERSION_CODES.O)
public void createNotificationChannel() {
String id = "channelID";
String name = "Daily Alerts";
String des = "Channel Description A Brief";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(id, name, importance);
channel.setDescription(des);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
}
code for scheduleNotification(Calender calendar);
#RequiresApi(api = Build.VERSION_CODES.M)
public void scheduleNotification(Calendar calendar) {
Intent intent = new Intent(getApplicationContext(), Notification.class);
intent.putExtra("titleExtra", "Dynamic Title");
intent.putExtra("textExtra", "Dynamic Text Body");
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
Toast.makeText(getApplicationContext(), "Scheduled ", Toast.LENGTH_LONG).show();
}
Notification.kt
class Notification : BroadcastReceiver()
{
override fun onReceive(context: Context, intent: Intent) {
message = intent.getStringExtra("textExtra").toString()
title = intent.getStringExtra("titleExtra").toString()
val notification =
NotificationCompat.Builder(context, channelID).setSmallIcon(R.drawable.notification)
.setContentText(message).setContentTitle(title).build()
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.notify(notificationId, notification)
}
}
I want to run a background function which listens to the clipboard and when a string greater than 200 characters is copied then it will execute the function to show notification and then the proper Activity.class.
I am unable to create a service which runs in the background all the time even when the app is closed and the phone is restarted. Current I am starting that function in MyApp class which extends Application as I am unable to understand any tutorial based on services which can give me what I want.
Below is my code for MyApp
MyApp.class
public class MyApp extends Application {
private PrefManager prefManager;
#Override
public void onCreate() {
super.onCreate();
prefManager = new PrefManager(this);
if (prefManager.isNotifOns()) {
getClipTexts();
}
}
//Listener to listen change in clipboard
private void getClipTexts() {
final ClipboardManager clipboardManager = (ClipboardManager) this.getSystemService(Context.CLIPBOARD_SERVICE);
clipboardManager.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {
#Override
public void onPrimaryClipChanged() {
try {
String textToPaste = clipboardManager.getPrimaryClip().getItemAt(0).getText().toString();
if (textToPaste.length() > 200) {
makeNotification(textToPaste);
}
} catch (Exception ignored) {
}
}
});
}
//Creating notifications after copying the clipboard text
public void makeNotification(String input) {
Intent notifIntent = new Intent(getApplicationContext(), PostActivity.class);
notifIntent.putExtra("post", input);
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
int notificationId = 1;
String channelId = "channel-01";
String channelName = "Copy to Post";
int importance = 0;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
importance = NotificationManager.IMPORTANCE_DEFAULT;
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel mChannel = new NotificationChannel(
channelId, channelName, importance);
notificationManager.createNotificationChannel(mChannel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext(), channelId)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Post copied content")
.setContentText(input)
.setAutoCancel(true);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(getApplicationContext());
stackBuilder.addNextIntent(notifIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
notificationManager.notify(notificationId, mBuilder.build());
}
}
Can anyone please write this function in a service which runs in background and supports in all Android Versions.
The above code does what I want as long as the app is running on foreground but I want to run the function even when App is closed or phone is restarted even in android versions above Android N. Please give me a proper answer I will be thankful for that.
I am stuck with my app which needs to repeat one notification after one hour (Medical purpose). As my field is totally opposite and I am noob in coding any help will be appreciated. I know I have to add something in notification receiver to repeat notifications. But every time I try to repeat the app crashes.
(This is a little but unique idea to solve a real world problem I will credit everyone from whom I've received even a little help )
Here is my MainActivity
private NotificationManagerCompat manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = NotificationManagerCompat.from(this);
}
public void Shownotification(View v) {
String title = "You Did it!";
String message = "Some Text";
Notification notification = new NotificationCompat.Builder(this, CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.build();
manager.notify(0,notification);
}
Notification Channel
public class App extends Application {
public static final String CHANNEL_1_ID = "channel1";
public static final String CHANNEL_2_ID = "channel2";
#Override
public void onCreate() {
super.onCreate();
createNotificationChannels();
}
private void createNotificationChannels() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel1 = new NotificationChannel(
CHANNEL_1_ID,
"Channel 1",
NotificationManager.IMPORTANCE_HIGH
);
channel1.setDescription("This is Channel 1");
NotificationChannel channel2 = new NotificationChannel(
CHANNEL_2_ID,
"Channel 2",
NotificationManager.IMPORTANCE_LOW
);
channel2.setDescription("This is Channel 2");
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel1);
manager.createNotificationChannel(channel2);
}
}
Notification Reciever
public class NotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String title = "You Did it!";
String message = "Some Text";
Notification notification = new NotificationCompat.Builder(context, CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 1);
Intent i = new Intent("android.action.DISPLAY_NOTIFICATION");
i.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
PendingIntent broadcast = PendingIntent.getBroadcast(context, 100, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), broadcast);
}
you can set new notification when previous one triggers.in onReceive Method of BroadcastReceiver.
I need to show the user a notification at the same time every day (based on a user selecting the time it is shown). With API 25 and earlier I can use AlarmManager without a problem. However with API 26 (Oreo) it will crash my app if the app is in the background for more than a few minutes. Nothing I've done seems to prevent AlarmManager crashing after about a minute of the app being in the background.
Based on what I have seen online the only solution is to use a JobScheduler, but there doesn't seem to be anyway to have a JobScheduler start at a certain time and then recur every day. (I can have it run at a certain time by calling setOverrideDeadline or I can make it recurring by calling setPeriodic, but calling both throws and exception.)
This is my code for the JobScheduler (I have it set to recur every 15 seconds for testing, but I also want to be able to start it at a certain time):
private void setReminders(){
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_BOOT_COMPLETED) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.RECEIVE_BOOT_COMPLETED }, 613);
return;
}
SharedPreferences sharedPreferences = this.getSharedPreferences(getString(R.string.shared_pref_file_name), ContextWrapper.MODE_PRIVATE);
boolean showReminder = sharedPreferences.getBoolean(getString(R.string.shared_pref_reminder_active_key), false);
int hour = sharedPreferences.getInt(getString(R.string.shared_pref_reminder_hour_key), 21);
int minute = sharedPreferences.getInt(getString(R.string.shared_pref_reminder_minute_key), 0);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
long startUpTime = Calendar.getInstance().getTimeInMillis() + 10000; //calendar.getTimeInMillis() + 10000;
JobInfo.Builder builder = new JobInfo.Builder( 613, new ComponentName(getPackageName(), SefiraReminderJobService.class.getName()));
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
.setOverrideDeadline(15000)
.setRequiresDeviceIdle(false)
.setRequiresCharging(false)
.setPersisted(true);
builder.setPeriodic(Math.max(15000, JobInfo.getMinPeriodMillis()));
JobScheduler jobScheduler = (JobScheduler) getSystemService( Context.JOB_SCHEDULER_SERVICE );
if(jobScheduler.schedule(builder.build()) == JobScheduler.RESULT_FAILURE ) {
Log.w("MainActivity.setReminders", "Something went wrong when scheduling the reminders" );
}
}
This is my JobIntentService class:
public final class ReminderJobService extends JobIntentService {
private NotificationManager notificationManager;
private PendingIntent pendingIntent;
private static int NOTIFICATION_ID = 1234;
private static String NOTIFICATION_CHANNEL_ID = "my-reminder-channel";
private Notification notification;
#Override
protected void onHandleWork(#NonNull Intent intent) {
Context context = this.getApplicationContext();
notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent mIntent = new Intent(this, MainActivity.class);
pendingIntent = PendingIntent.getActivity(context, 0, mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Reminders", NotificationManager.IMPORTANCE_DEFAULT);
// Configure the notification channel.
notificationChannel.setDescription("My Reminders");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_launcher_foreground)
//.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.ic_launcher))
//.setTicker("ticker value")
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM))
.setContentTitle("Reminder")
.setContentText("Reminder Message").build();
notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
notification.ledARGB = 0xFFFFA500;
notification.ledOnMS = 800;
notification.ledOffMS = 1000;
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
notificationManager.notify(NOTIFICATION_ID, notification);
} catch (Exception ex){
ex.printStackTrace();
}
}
}
My AndroidManifest contains the following:
<service android:name="ReminderJobService"
android:permission="android.permission.BIND_JOB_SERVICE"></service>
As well as:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
How can I send a recurring notification each day at a specific time on Android 26/8.0/Oreo even when the app is in the background?
This workable decision but with deprecated logic:
public scheduleEvent(int id, long scheduleTime) {
final PendingIntent pendingIntent = pendingIntent(id);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, scheduleTime, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, scheduleTime, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, scheduleTime, pendingIntent);
}
private PendingIntent pendingIntent(int id) {
final Intent intent = new Intent(app, EventReceiver.class);
intent.setAction("some event " + id);
return PendingIntent.getBroadcast(context, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
Create EventReceiver don't forget add it in AndroidManifest
public class EventReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
final ComponentName comp = new ComponentName(context.getPackageName(), EventService.class.getName());
startWakefulService(context, intent.setComponent(comp));
}
}
Create EventService, also add it to the AndroidManifest
public class EventService extends IntentService {
#Override
protected void onHandleIntent(final Intent intent) {
//Your logic here
}
}
I have a service which runs in foreground with, among other things, a stopwatch. When the service starts the notification appears, and when it ends I update it with sound and some text that indicates that it's finished. The problem is that this works well until api 25, but for 26 and 27 it updates the notification alright, but makes no sound. Here's the relevant code:
The creation of the notification inside the service:
mBuilder = new NotificationCompat.Builder(context, "Main")
.setSmallIcon(R.drawable.ic_notification_temp)
.setContentTitle(step.getDescription())
.setContentText(getString(R.string.notification_text))
.setVisibility(VISIBILITY_PUBLIC)
.setOngoing(true);
.setDeleteIntent(deletePendingIntent);
.setContentIntent(contentPendingIntent);
.addAction(R.drawable.ic_stop_red_24dp, getString(R.string.cancel),finnishPendingIntent);
mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(mId, mBuilder.build());
The update to the notification builder when the "work" is finished:
mBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
mBuilder.setVibrate(new long[]{0, 300, 0, 400, 0, 500});
mBuilder.setOngoing(false);
mBuilder.setAutoCancel(true);
mBuilder.setContentText(getString(R.string.notification_finished_text));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mBuilder.setChannelId("Sound");
mBuilder.setCategory(NotificationCompat.CATEGORY_ALARM);
}
mNotificationManager.notify(mId, mBuilder.build());
The 2 channels created just for api 26 or up on app start:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create the normal NotificationChannel
CharSequence name = getString(R.string.app_name);
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel channel = new NotificationChannel("Main", name, importance);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = (NotificationManager) getSystemService(
NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
// Create theNotificationChannel with sound
importance = NotificationManager.IMPORTANCE_HIGH;
name = getString(R.string.notification_channel_sound);
NotificationChannel sound = new NotificationChannel("Sound", name, importance);
sound.enableVibration(true);
sound.setVibrationPattern(new long[]{0, 300, 0, 400, 0, 500});
AudioAttributes aa = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
.build();
sound.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), aa);
notificationManager.createNotificationChannel(sound);
}
And that's where I'm at now. I've tried to not use setsound() as I've read that the notification should just play the default sound with the appropriate importance (and of course I've even uninstalled the app between tries to correctly update the channel settings) but nothing seems to work for api 26 and I just don't know what I'm doing wrong.
I had the exact same problems with most of my emulator AVDs. The following fixed it for me:
start the affected AVD
long press the AVD's power button
restart the AVD
Afterwards it should work again.
Tried to reproduce your issue and finished with created MVP, maybe this will help you to find the problem:
Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View btn = findViewById(R.id.clickMe);
btn.setTag(NotifService.CHANNEL_ID_MAIN);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String channelId = (String) v.getTag();
Intent intent = new Intent(v.getContext(), NotifService.class);
intent.putExtra(NotifService.TAG, channelId);
if (channelId.equals(NotifService.CHANNEL_ID_MAIN)) {
v.setTag(NotifService.CHANNEL_ID_SOUND);
} else {
v.setTag(NotifService.CHANNEL_ID_MAIN);
}
v.getContext().startService(intent);
}
});
}
}
Service:
public class NotifService extends IntentService {
public static final String TAG = "NotificationService";
public static final String CHANNEL_ID_MAIN = "Main";
public static final String CHANNEL_ID_SOUND = "Sound";
public static final int NOTIFICATION_ID = 123;
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*/
public NotifService() {
super(TAG);//Used to name the worker thread, important only for debugging.
}
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID_MAIN, "Channel Main", NotificationManager.IMPORTANCE_LOW);
NotificationChannel sound = new NotificationChannel(CHANNEL_ID_SOUND, "Channel Sound", NotificationManager.IMPORTANCE_HIGH);
sound.enableVibration(true);
sound.setVibrationPattern(new long[]{0, 300, 0, 400, 0, 500});
AudioAttributes aa = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
.build();
sound.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), aa);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
notificationManager.createNotificationChannel(sound);
}
}
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
String channelId = intent.getStringExtra(TAG);
showNotification(channelId);
}
private void showNotification(String channelId) {
boolean inProgress = channelId.equals(CHANNEL_ID_MAIN);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Work")
.setContentText(inProgress ? "InProgress" : "Finished")
.setOngoing(inProgress)
.setVisibility(VISIBILITY_PUBLIC)
.setAutoCancel(!inProgress);
if (!inProgress) {
builder.setCategory(NotificationCompat.CATEGORY_ALARM);
}
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
}
}
This works good on my device 8.1 and Emulator 8.1 (without sound on first click for first notification and with vibration + sound on second click for work complete notification).