I have set a reminder in my app, but the screen does not turn on when the notification arises and neither does it pop up. I just get the notification the notification bar.
The device should wake up(if locked) or show notification pop up(if unlocked)
AlarmReceiver class :
public class AlarmReceiver extends BroadcastReceiver {
private final String CHANNEL_ID="Reminder";
#Override
public void onReceive(Context context, Intent intent) {
//wake
WakeLocker.acquire(context);
int notificationId = intent.getIntExtra("notificationId", 0);
Intent mainIntent = new Intent(context, Reminder.class);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, mainIntent, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Reminder";
String description = "Reminder for Workout";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, name, importance);
notificationChannel.setDescription(description);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);
//FOR ANDROID OLDER THAN VERSION OREO (8.0)
NotificationManager mynotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
builder.setSmallIcon(android.R.drawable.ic_lock_idle_alarm)
.setContentTitle("It's Time")
.setContentText("Let's Workout")
.setWhen(System.currentTimeMillis())
.setAutoCancel(true)
.setContentIntent(contentIntent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
mynotificationManager.notify(notificationId, builder.build());
//wake
WakeLocker.release();
}
}
}
WakeLocker class :
public abstract class WakeLocker {
private static PowerManager.WakeLock wakeLock;
public static void acquire(Context context) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, "HomeFitness:WAKE_LOCK_TAG");
wakeLock.acquire(1000);
}
public static void release() {
if (wakeLock != null) wakeLock.release(); wakeLock = null;
}
}
Reminder class :
public void onClick(View v)
{
TimePicker t=findViewById(R.id.timepicker);
Intent intent=new Intent(Reminder.this,AlarmReceiver.class);
intent.putExtra("notificationId",notificationId);
PendingIntent alarmIntent=PendingIntent.getBroadcast(Reminder.this, 0 , intent , PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarm=(AlarmManager) getSystemService(ALARM_SERVICE);
switch(v.getId())
{
case R.id.set:
int hr= t.getHour();
int min=t.getMinute();
Calendar startTime = Calendar.getInstance();
startTime.set(Calendar.HOUR_OF_DAY,hr);
startTime.set(Calendar.MINUTE,min);
startTime.set(Calendar.SECOND,0);
startTime.set(Calendar.MILLISECOND,0);
long alarmStartTime=startTime.getTimeInMillis();
alarm.set(AlarmManager.RTC_WAKEUP,alarmStartTime,alarmIntent);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, startTime.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, alarmIntent);
//added later for higher android
alarm.setExact(AlarmManager.RTC_WAKEUP,startTime.getTimeInMillis(),alarmIntent);
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,startTime.getTimeInMillis(),alarmIntent);
//new close
Toast.makeText(Reminder.this,"Reminder Set", Toast.LENGTH_SHORT).show();
break;
case R.id.cancelb:
alarm.cancel(alarmIntent);
Toast.makeText(Reminder.this, "Reminder Canceled", Toast.LENGTH_SHORT).show();
break;
}
}
ACQUIRE_CAUSES_WAKEUP can't be used together with PARTIAL_WAKE_LOCK. Try removing the latter.
Try .setPriority(NotificationCompat.PRIORITY_MAX) for the notification (and change it for the channel too).
/**
* Wake lock flag: Turn the screen on when the wake lock is acquired.
* <p>
* Normally wake locks don't actually wake the device, they just cause
* the screen to remain on once it's already on. Think of the video player
* application as the normal behavior. Notifications that pop up and want
* the device to be on are the exception; use this flag to be like them.
* </p><p>
* Cannot be used with {#link #PARTIAL_WAKE_LOCK}.
* </p>
*/
public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
The only way to wake the screen is:
PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
However, this will (maybe) stop working in newer Android versions.
Related
How can my app play a short sound every hour, even when it is not running in the foreground?
Try-1: I tried a handler, but this does not help.
Try-2: as #Marcin, suggested, I tried the AlarmManager. No sound is played when the mobile is inactive. When I open the app, then it plays the sound.
Try-3: Add a notification channel with high priority on it. This plays the sound at least once, even when the mobile is standby. Swiping the notification away won't play the sound again. Setting the notification autoCancel to false won't help.
private void setAlarm() {
alarmManager = (AlarmManager) getSystemService( Context.ALARM_SERVICE);
Intent intent = new Intent( this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast( this, 0, intent, FLAG_IMMUTABLE);
alarmManager.setInexactRepeating( AlarmManager.RTC_WAKEUP,
LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(),
60000L, pendingIntent);
createNotificationChannel();
}
private void createNotificationChannel() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "My ReminderChannel";
String description = "Channel for the Alarm manager";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel( "myandroid", name, importance);
channel.setDescription( description);
NotificationManager notificationManager = getSystemService( NotificationManager.class);
notificationManager.createNotificationChannel( channel);
}
}
The AlarmReceiver is:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent( context, MainActivity.class);
intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity( context, 0, i, PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "myandroid")
.setSmallIcon(R.drawable.add_checklist_item)
.setContentTitle("Wakeup")
.setContentText("Descsription")
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent( pendingIntent);
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
notificationManagerCompat.notify(12345, builder.build());
playRingtone();
}
public void playRingtone() {
try {
MediaPlayer mp = MediaPlayer.create(MainActivity.mainActivity, R.raw.tock);
mp.start();
mp.setOnCompletionListener(MediaPlayer::release);
} catch (Exception e) {
e.printStackTrace();
}
}
}
In the AndroidManifest.xml is:
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<receiver android:name="com.example.myapp.AlarmReceiver"/>
</application>
Of course I don't want my silent app draining my battery.
Use workmanager.
here is the link.
I am working on a simple Water Reminder app. One of the final things that are left to implement is adding "Remind me later" option when the reminder notification pops. I've searched in many similar questions and articles but I didn't find solution. The thing is that I dont even know what i'm supposed to do...Start some activity, or send something to broadcast receiver or something else. I don't even know how to start trying different approaches. I will be very thankfull if someone helps me! Below is the code. What can I add to the code to implement this function?
public class ReminderManager {
public void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Uri soundUri = Uri.parse(Constants.PATH_TO_NOTIFICATION_RINGTONE);
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build();
NotificationChannel notificationChannel = new NotificationChannel
(Constants.NOTIFICATION_CHANNEL_ID, "WaterReminderChannel", NotificationManager.IMPORTANCE_HIGH);
notificationChannel.setSound(soundUri, audioAttributes);
notificationChannel.setDescription("Channel for Water Reminder");
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(notificationChannel);
}
}
public void setReminder() {
Intent intent = new Intent(context, ReminderBroadcastReceiver.class);
PendingIntent pendingIntentForBroadcast = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + MainActivity.reminderTime, pendingIntentForBroadcast);
}
public class ReminderBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent i) {
if (MainActivity.reminderTime > 0 && !MainActivity.dayFinished) {
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
Uri soundUri = Uri.parse(Constants.PATH_TO_NOTIFICATION_RINGTONE);
Notification notification = new NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.mipmap.water)
.setContentTitle("Water Reminder")
.setContentText("It's time to drink something!")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setSound(soundUri)
.setDefaults(Notification.DEFAULT_VIBRATE)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(1, notification);
}
}
If I understand you correctly, I believe the simplest way to handle this is to use Notification “action buttons.” See https://developer.android.com/training/notify-user/build-notification for more detail.
Thanks. Your information helped me to solve the problem. I've made it and want to share my code because it's very simple and maybe will save someone's time instead of searching alot of complicated solutions like I did.
So, below is the code that set alarm for specified by the user time, then after that time occurs the BroadcastReceiver gets triggered even when the phone is in idle state thanks to "AlarmManagerCompat.setExactAndAllowWhileIdle" (works for older and newer Android versions). Then the receiver checks by which action is triggered - SNOOZE or REMINDER. If it's SNOOZE, it calls the setReminder() method of my custom ReminderManager class to reset the alarm and then calls notificationManager.cancelAll() to remove the previous notification banner. If it's REMINDER then it calls the showNotification() method which build the notification and show it to the user (I don't find the need to build the notification before the time when the AlarmManager is set to trigger the receiver).
In my ReminderManager class I have createNotificationChannel() method which is needed for newer Android versions and I call it in onCreate of MainActivity. The setReminder() method is called from places that it needs the reminder to be set (when the user sets notification and from the BroadcastReciever as described above) and the showNotification() method is called from BroadcastReciever as described above.
public class BroadcastReceiver extends android.content.BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ReminderManager reminderManager = new ReminderManager(context);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
if (intent.getAction().equals(Constants.SNOOZE_ACTION)) {
reminderManager.setReminder();
notificationManager.cancelAll();
} else if (intent.getAction().equals(Constants.REMINDER_ACTION)) {
reminderManager.showNotification();
}
}
}
public class ReminderManager {
private final Context context;
public ReminderManager(Context context) {
this.context = context;
}
public void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build();
NotificationChannel notificationChannel = new NotificationChannel
(Constants.NOTIFICATION_CHANNEL_ID, "WaterReminderChannel",
NotificationManager.IMPORTANCE_HIGH);
notificationChannel.setSound
(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), audioAttributes);
notificationChannel.setDescription("Channel for Water Reminder");
NotificationManager notificationManager =
context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(notificationChannel);
}
}
public void setReminder() {
Intent intent = new Intent(context, BroadcastReceiver.class);
intent.setAction(Constants.REMINDER_ACTION);
PendingIntent pendingIntentForBroadcast =
PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP,
System.currentTimeMillis()
+ MainActivity.reminderTime, pendingIntentForBroadcast);
}
public void showNotification() {
Intent maniActivityIntent = new Intent(context, MainActivity.class);
PendingIntent mainActivityPendingIntent =
PendingIntent.getActivity(context, 0, maniActivityIntent, 0);
Intent snoozeIntent = new Intent(context, BroadcastReceiver.class);
snoozeIntent.setAction(Constants.SNOOZE_ACTION);
PendingIntent snoozePendingIntent =
PendingIntent.getBroadcast(context, 0, snoozeIntent, 0);
Notification notification = new NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.mipmap.water)
.setContentTitle("Water Reminder")
.setContentText("It's time to drink something!")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setDefaults(Notification.DEFAULT_VIBRATE)
.setContentIntent(mainActivityPendingIntent)
.addAction(android.R.drawable.ic_lock_idle_alarm, "Remind me later", snoozePendingIntent)
.setAutoCancel(true)
.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(0, notification);
}
}
I'm trying to create an android full screen notification to show an activity over the lock screen, like an alarm clock.
The notification always occurs, but the activity is never started over the lock screen; it just rings and shows a notification icon on the lock screen if the phone is off. It shows a heads up notification if the phone is on as expected. A debug print indicates the notification channel is successfully registered at importance level HIGH/4 as requested.
I've tried it on 5 different android device versions: Android 10, 8.0.0, 6.0.1, 5.1.1
I've followed the android developers documentation linked below. I also linked a couple similar stack overflow questions.
https://developer.android.com/training/notify-user/time-sensitive
https://developer.android.com/training/notify-user/build-notification#urgent-message
Full screen intent not starting the activity but do show a notification on android 10
FullScreen Notification
Below is a very minimal version of the application code, an activity with 1 button to schedule the notification in the future with a broadcast receiver so it fires after the screen is locked.
compileSdkVersion 29
buildToolsVersion "29.0.2"
minSdkVersion 25
targetSdkVersion 29
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
public class AppReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (FullscreenActivity.FULL_SCREEN_ACTION.equals(intent.getAction()))
FullscreenActivity.CreateFullScreenNotification(context);
}
}
public class FullscreenActivity extends AppCompatActivity {
private static final String CHANNEL_ID = "my_channel";
static final String FULL_SCREEN_ACTION = "FullScreenAction";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
createNotificationChannel(this);
}
/**
* Use button to set alarm manager with a pending intent to create the full screen notification
* after use has time to shut off device to test with the lock screen showing
*/
public void buttonClick(View view) {
Intent intent = new Intent(this, AppReceiver.class);
intent.setAction(FULL_SCREEN_ACTION);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
if (am != null) {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 15000, pi);
}
}
static void CreateFullScreenNotification(Context context) {
Intent fullScreenIntent = new Intent(context, FullscreenActivity.class);
fullScreenIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);//?
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(context, 0,
fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Full Screen Alarm Test")
.setContentText("This is a test")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setDefaults(NotificationCompat.DEFAULT_ALL) //?
.setFullScreenIntent(fullScreenPendingIntent, true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(1, notificationBuilder.build());
}
private static void createNotificationChannel(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
if (notificationManager != null && notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);
channel.setDescription("channel_description");
notificationManager.createNotificationChannel(channel);
}
//DEBUG print registered channel importance
if (notificationManager != null && notificationManager.getNotificationChannel(CHANNEL_ID) != null) {
Log.d("FullScreenActivity", "notification channel importance is " + notificationManager.getNotificationChannel(CHANNEL_ID).getImportance());
}
}
}
}
I was finally able to get this to work after finding this answer for an incoming call:
https://stackoverflow.com/a/53192049/13008865
The part missing from the android document examples for full screen intents was that the activity the full screen intent tries to show needs a couple WindowManager.LayoutParams flags set:
FLAG_SHOW_WHEN_LOCKED and FLAG_TURN_SCREEN_ON.
Here's the final minimal test app code I hope is useful for others trying to do an alarm clock type app. I tested successfully on the 4 OS versions listed above with target sdk 29 and minimum sdk 15. The only manifest permission needed was USE_FULL_SCREEN_INTENT and only for devices running android Q/29 and above.
public class AppReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (FullscreenActivity.FULL_SCREEN_ACTION.equals(intent.getAction()))
FullscreenActivity.CreateFullScreenNotification(context);
}
}
public class FullscreenActivity extends AppCompatActivity {
private static final String CHANNEL_ID = "my_channel";
static final String FULL_SCREEN_ACTION = "full_screen_action";
static final int NOTIFICATION_ID = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
createNotificationChannel(this);
//set flags so activity is showed when phone is off (on lock screen)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
/**
* Use button to set alarm manager with a pending intent to create the full screen notification
* after use has time to shut off device to test with the lock screen showing
*/
public void buttonClick(View view) {
Intent intent = new Intent(FULL_SCREEN_ACTION, null, this, AppReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 15000, pendingIntent);
}
NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID); //cancel last notification for repeated tests
}
static void CreateFullScreenNotification(Context context) {
Intent intent = new Intent(context, FullscreenActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Full Screen Alarm Test")
.setContentText("This is a test")
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setContentIntent(pendingIntent)
.setFullScreenIntent(pendingIntent, true);
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notificationBuilder.build());
}
private static void createNotificationChannel(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);
channel.setDescription("channel_description");
notificationManager.createNotificationChannel(channel);
}
}
}
}
//use the following code it will work
//also put this in your Manifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK"/>
//put this in manifest in your specific activity you want to show on lock
//screen
android:showWhenLocked="true"
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
getWindow().addFlags(AccessibilityEventCompat.TYPE_WINDOWS_CHANGED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
As per other answers posted here, the two flags FLAG_SHOW_WHEN_LOCKED and FLAG_TURN_SCREEN_ON are crucial for Android version above OREO.
However seems like the docs suggests it is better to declare them in AndroidManifest for that activity instead:
When using the Window flag during activity startup, there may not be time
to add it before the system stops your activity for being behind the
lock-screen. This leads to a double life-cycle as it is then restarted.
For me, instead of adding the flags programmatically, adding them in AndroidManifest is cleaner anyway, and it works well in my testing
<activity
android:name=".IncomingCallActivity"
android:showForAllUsers="true"
android:showWhenLocked="true"
android:turnScreenOn="true"
android:theme="#style/AppTheme" />
Not sure if showForAllUsers is needed, but I read somewhere that it is better to include it.
For me, what helped was Ranjith Kumar's answer in this question.
Below is the same code, in Java:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
// For newer than Android Oreo: call setShowWhenLocked, setTurnScreenOn
setShowWhenLocked(true);
setTurnScreenOn(true);
// If you want to display the keyguard to prompt the user to unlock the phone:
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
keyguardManager.requestDismissKeyguard(this, null);
} else {
// For older versions, do it as you did before.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
I also had a similar issue, for me the problem was not with window Flags but when triggering notification both the notification channel should have IMPORTANCE_HIGH and notification with HIGH_PRIORITY and also of you are using redmi you have to set permission explicitly on app settings
I'm trying to make a daily notification which will be show at a specific time.
Unfortunately it doesn't show.
I tried to follow couples tuto (also from developer.android.com) and checked similar questions that have already been asked. To save hour I'm using Hawk library.
Intent intent = new Intent(getContext(), AlarmReceiver.class);
int notificationId = 1;
intent.putExtra("notificationId", notificationId);
PendingIntent alarmIntent = PendingIntent.getBroadcast(getContext(), 0,
intent,PendingIntent.FLAG_NO_CREATE);
AlarmManager alarm = (AlarmManager) getContext().getSystemService(getContext().ALARM_SERVICE);
switch (view.getId()) {
int hour = timePicker.getCurrentHour();
int minute = timePicker.getCurrentMinute();
// Create time
....
//set alarm
alarm.setRepeating(AlarmManager.RTC_WAKEUP, alarmStartTime, AlarmManager.INTERVAL_DAY, alarmIntent);
Hawk.put("notification_hour", alarmStartTime);
break;
case R.id.cancel_button:
//cancel notification
break;
}
}
and here AlarmReceiver class
public class AlarmReceiver extends BroadcastReceiver {
public AlarmReceiver () {
}
#Override
public void onReceive(Context context, Intent intent) {
sendNotification(context, intent);
}
private void sendNotification(Context con, Intent intent) {
int notificationId = intent . getIntExtra ("notificationId", 1);
String message = " message";
Intent mainIntent = new Intent(con, MainActivity.class);
PendingIntent contentIntent = PendingIntent . getActivity (con, 0, mainIntent, 0);
NotificationManager myNotificationManager =(NotificationManager) con . getSystemService (Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Notification.Builder(con);
builder.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("Reminder")
.setContentText(message)
.setWhen(System.currentTimeMillis())
.setAutoCancel(true)
.setContentIntent(contentIntent)
.setPriority(Notification.PRIORITY_MAX)
.setDefaults(Notification.DEFAULT_ALL);
myNotificationManager.notify(notificationId, builder.build());
}
}
In OREO, they have redesigned notifications to provide an easier and more consistent way to manage notification behavior and settings. Some of these changes include:
Notification channels: Android 8.0 introduces notification channels that allow you to create a user-customizable channel for each type of notification you want to display.
Notification dots: Android 8.0 introduces support for displaying dots, or badges, on app launcher icons. Notification dots reflect the presence of notifications that the user has not yet dismissed or acted on.
Snoozing: Users can snooze notifications, which causes them to disappear for a period of time before reappearing. Notifications reappear with the same level of importance they first appeared with.
Messaging style: In Android 8.0, notifications that use the MessagingStyle class display more content in their collapsed form. You should use theMessagingStyle class for notifications that are messaging-related.
Here, we have created the NotificationHelper class that require the Context as the constructor params. NOTIFICATION_CHANNEL_ID variable has been initialize in order to set the channel_id to NotificationChannel.
The method createNotification(…) requires title and message parameters in order to set the title and content text of the notification. In order to handle the notification click event we have created the pendingIntent object, that redirect towards SomeOtherActivity.class.
Notification channels allow you to create a user-customizable channel for each type of notification you want to display. So, if the android version is greater or equals to 8.0, we have to create the NotificationChannel object and set it to createNotificationChannel(…) setter property of NotificationManager.
public class NotificationHelper {
private Context mContext;
private NotificationManager mNotificationManager;
private NotificationCompat.Builder mBuilder;
public static final String NOTIFICATION_CHANNEL_ID = "10001";
public NotificationHelper(Context context) {
mContext = context;
}
/**
* Create and push the notification
*/
public void createNotification(String title, String message)
{
/**Creates an explicit intent for an Activity in your app**/
Intent resultIntent = new Intent(mContext , SomeOtherActivity.class);
resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext,
0 /* Request code */, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder = new NotificationCompat.Builder(mContext);
mBuilder.setSmallIcon(R.mipmap.ic_launcher);
mBuilder.setContentTitle(title)
.setContentText(message)
.setAutoCancel(false)
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
.setContentIntent(resultPendingIntent);
mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O)
{
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "NOTIFICATION_CHANNEL_NAME", importance);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.enableVibration(true);
notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
assert mNotificationManager != null;
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
mNotificationManager.createNotificationChannel(notificationChannel);
}
assert mNotificationManager != null;
mNotificationManager.notify(0 /* Request Code */, mBuilder.build());
}
Just include a NotificationChannel and set a channel id to it.
I've got my local notifications running on androids prior to SDK 26
But in a Android O I've got the following warning, and the broadcast receiver is not fired.
W/BroadcastQueue: Background execution not allowed: receiving Intent { act=package.name.action.LOCAL_NOTIFICATION cat=[com.category.LocalNotification] flg=0x14 (has extras) } to package.name/com.category.localnotifications.LocalNotificationReceiver
From what I've read broadcast receivers are more restricted in android O, but if so, how should I schedule the broadcast if I want it launching even if the main activity is not running?
Should I use services instead of receivers?
This is the AlarmManager launch code:
public void Schedule(String aID, String aTitle, String aBody, int aNotificationCode, long aEpochTime)
{
Bundle lExtras = new Bundle();
lExtras.putInt("icon", f.getDefaultIcon());
lExtras.putString("title", aTitle);
lExtras.putString("message", aBody);
lExtras.putString("id", aID);
lExtras.putInt("requestcode", aNotificationCode);
Intent lIntent =
new Intent(LocalNotificationScheduler.ACTION_NAME)
.addCategory(NotificationsUtils.LocalNotifCategory)
.putExtras(lExtras);
PendingIntent lPendIntent = PendingIntent.getBroadcast(f.getApplicationContext(), aNotificationCode,
lIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager lAlarmMgr = (AlarmManager) f.getSystemService(Context.ALARM_SERVICE);
lAlarmMgr.set(AlarmManager.RTC, 1000, lPendIntent);
}
This is the receiver code:
public class LocalNotificationReceiver extends BroadcastReceiver {
public static native void nativeReceiveLocalNotification (String aID, String aTitle, String aMessage, boolean aOnForeground );
/** This method receives the alarms set by LocalNotificationScheduler,
* notifies the CAndroidNotifications c++ class, and (if needed) ships a notification banner
*/
#Override
public void onReceive(Context aContext, Intent aIntent)
{
Toast.makeText(context, text, duration).show();
}
}
Android manifest:
<receiver android:name="com.category.localnotifications.LocalNotificationReceiver">
<intent-filter>
<action android:name="${applicationId}.action.LOCAL_NOTIFICATION" />
<category android:name="com.category.LocalNotification" />
</intent-filter>
</receiver>
Android O are pretty new to-date. Hence, I try to digest and provide as accurate possible information.
From https://developer.android.com/about/versions/oreo/background.html#broadcasts
Apps that target Android 8.0 or higher can no longer register broadcast receivers for implicit broadcasts in their manifest.
Apps can use Context.registerReceiver() at runtime to register a receiver for any broadcast, whether implicit or explicit.
Apps can continue to register explicit broadcasts in their manifest.
Also, in https://developer.android.com/training/scheduling/alarms.html , the examples are using explicit broadcast, and doesn't mention anything special regarding Android O.
May I suggest you try out explicit broadcast as follow?
public static void startAlarmBroadcastReceiver(Context context, long delay) {
Intent _intent = new Intent(context, AlarmBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, _intent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
// Remove any previous pending intent.
alarmManager.cancel(pendingIntent);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delay, pendingIntent);
}
AlarmBroadcastReceiver
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
}
}
In AndroidManifest, just define the class as
<receiver android:name="org.yccheok.AlarmBroadcastReceiver" >
</receiver>
Today i had the same problem and my notification was not working. I thought Alarm manager is not working in Oreo but the issue was with Notification. In Oreo we need to add Channel id. Please have a look into my new code:
int notifyID = 1;
String CHANNEL_ID = "your_name";// The id of the channel.
CharSequence name = getString(R.string.channel_name);// The user-visible name of the channel.
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
// Create a notification and set the notification channel.
Notification notification = new Notification.Builder(HomeActivity.this)
.setContentTitle("Your title")
.setContentText("Your message")
.setSmallIcon(R.drawable.notification)
.setChannelId(CHANNEL_ID)
.build();
Check this solution. It worked like charm.
https://stackoverflow.com/a/43093261/4698320
I am showing my method:
public static void pendingListNotification(Context context, String totalCount) {
String CHANNEL_ID = "your_name";// The id of the channel.
CharSequence name = context.getResources().getString(R.string.app_name);// The user-visible name of the channel.
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationCompat.Builder mBuilder;
Intent notificationIntent = new Intent(context, HomeActivity.class);
Bundle bundle = new Bundle();
bundle.putString(AppConstant.PENDING_NOTIFICATION, AppConstant.TRUE);//PENDING_NOTIFICATION TRUE
notificationIntent.putExtras(bundle);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= 26) {
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
mNotificationManager.createNotificationChannel(mChannel);
mBuilder = new NotificationCompat.Builder(context)
// .setContentText("4")
.setSmallIcon(R.mipmap.logo)
.setPriority(Notification.PRIORITY_HIGH)
.setLights(Color.RED, 300, 300)
.setChannelId(CHANNEL_ID)
.setContentTitle(context.getResources().getString(R.string.yankee));
} else {
mBuilder = new NotificationCompat.Builder(context)
// .setContentText("4")
.setSmallIcon(R.mipmap.logo)
.setPriority(Notification.PRIORITY_HIGH)
.setLights(Color.RED, 300, 300)
.setContentTitle(context.getResources().getString(R.string.yankee));
}
mBuilder.setContentIntent(contentIntent);
int defaults = 0;
defaults = defaults | Notification.DEFAULT_LIGHTS;
defaults = defaults | Notification.DEFAULT_VIBRATE;
defaults = defaults | Notification.DEFAULT_SOUND;
mBuilder.setDefaults(defaults);
mBuilder.setContentText(context.getResources().getString(R.string.you_have) + " " + totalCount + " " + context.getResources().getString(R.string.new_pending_delivery));//You have new pending delivery.
mBuilder.setAutoCancel(true);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
Create the AlarmManager by defining an explicit intent (explicitly define the class name of the broadcast receiver):
private static PendingIntent getReminderReceiverIntent(Context context) {
Intent intent = new Intent("your_package_name.ReminderReceiver");
// create an explicit intent by defining a class
intent.setClass(context, ReminderReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
Also do not forget to create a notification channel for Android Oreo (API 26) when creating the actual notification:
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (VERSION.SDK_INT >= VERSION_CODES.O) {
notificationManager.createNotificationChannel(NotificationFactory.createNotificationChannel(context));
} else {
notificationManager.notify(NotificationsHelper.NOTIFICATION_ID_REMINDER, notificationBuilder.build());
}
try this code for android O 8.1
Intent nIntent = new Intent("android.media.action.DISPLAY_NOTIFICATION");
nIntent.addCategory("android.intent.category.DEFAULT");
nIntent.putExtra("message", "test");
nIntent.setClass(this, AlarmReceiver.class);
PendingIntent broadcast = PendingIntent.getBroadcast(getAppContext(), 100, nIntent, PendingIntent.FLAG_UPDATE_CURRENT);