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
Related
In my app it is important to display a notification at a certain point in time (as alarm for Accident detection if the user does not move anymore).
This alarm is working on all Android versions < 10 and is also working with the most Phones with android 10. One of the exceptions seams to be the Samsung S10 (Plus). With this Phone all notifications are for 1-2 minutes delayed if the Phone is in Sleep-Mode (Display is black)!
Here some code snippets to show the Problem.
First we tried to do it with an JobIntentService:
public class MyNotificationService extends JobIntentService {
....
#Override
protected void onHandleWork(#NonNull Intent intent) {
NotificationType notificationType = NotificationType.valueOf(intent.getExtras().getInt(INTENT_EXTRA_NOTIFICATION_TYPE));
boolean alarmingNotification = intent.getBooleanExtra(INTENT_EXTRA_NOTIFICATION_TYPE_ALARM, false);
NotificationStorage notificationStorage = NotificationStorage.getInstance(context);
notificationStorage.setPendingNotificationType(notificationType);
intent.putExtra(INTENT_EXTRA_ALARM_NOTIFICATION, alarmingNotification);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.setClass(context, PopupOnLockScreenActivity.class);
startActivity(notificationStarterIntent)
}
...
}
Result: Popup does not open immediately as expected (1-2 minutes delayed)
Then i tried as workaround with Notification with a NotificationChannel (IMPORTANCE_HIGH) and NotificationCompat.Builder (PRIORITY_MAX):
public class MyNotificationService extends JobIntentService {
....
#Override
protected void onHandleWork(#NonNull Intent intent) {
NotificationType notificationType = NotificationType.valueOf(intent.getExtras().getInt(INTENT_EXTRA_NOTIFICATION_TYPE));
boolean alarmingNotification = intent.getBooleanExtra(INTENT_EXTRA_NOTIFICATION_TYPE_ALARM, false);
NotificationStorage notificationStorage = NotificationStorage.getInstance(context);
notificationStorage.setPendingNotificationType(notificationType);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.d(TAG, "showPopupOnLockScreen XXX");
String channelName = getResources().getString(R.string.safety_notification_channel_name);
//String description = getString(R.string.channel_description);
String description = "XXXXX";
int importance = NotificationManager.IMPORTANCE_HIGH;
android.app.NotificationChannel channel = new android.app.NotificationChannel(UepaaNetAndroidConstants.ANDROID_NOTIFICATION_CHANNEL_ID, channelName, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
android.app.NotificationManager notificationManager = getSystemService(android.app.NotificationManager.class);
notificationManager.createNotificationChannel(channel);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channel.getId())
.setSmallIcon(R.drawable.notification_symptom_small)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
notificationManager.notify(123, builder.build());
}
}
...
}
Result: Notification will be not showed immediately as expected (1-2 minutes delayed)
Wake-Up does not work on Samsung S10
I also tried to put the app in the lists to prevent the app from Battery-Manager and Sleep-Modes. (https://www.youtube.com/watch?v=npGw_r-v25k) But the problem still exists!
Can somebody help me? Our app is useless without notifications.
To reproduce this problem I pushed a project on github: https://github.com/gatschet/androidAlarmTest.git
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.
When app is running and device is locked I'm able to start the activity. But when app is in background and device is locked not able to start the activity even though I'm getting the control in BroadcastReceiver class. This is my intent call.
context.startActivity(new Intent(context, ReceiveCallActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setAction(Intent.ACTION_ANSWER)
.putExtra("title", intent.getStringExtra("title"))
.putExtra("action", intent.getStringExtra("action")));
Manifest of Activity
<activity
android:name=".ReceiveCallActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:excludeFromRecents="true"
android:launchMode="singleTop"
android:showOnLockScreen="true"
android:showWhenLocked="true"
android:turnScreenOn="true"
android:windowSoftInputMode="adjustPan|stateHidden" />
ReceiveCallActivity.class
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
} else {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
}
setContentView(R.layout.receive_call_activity);
...
...
}
setShowWhenLocked(true) && setTurnScreenOn(true) helps to open app even if device is locked but app has to be in foreground for that.
PS: I'm getting the control in BroadcastReceiver in all scenarios.
TIA
I was checking different permissions given to Skype from Settings, and noticed 'Show on Lock Screen' is enabled while the same was disabled for my App. On enabling it, BroadcastReceiver is able to open Activity in all scenarios. I read it's a issue with Xiamoi devices(I'm using Note 5 Pro).
EDIT
For Android 10 need to add USE_FULL_SCREEN_INTENT permission in manifest.
Then when the screen is locked, PendingIntent set as FullScreenIntent on NotificationCompat.Builder will be called.
My Notification code:
private void showCallNotification(Map<String, String> dataMap) {
//CREATING pendingIntent
...
...
...
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 2, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent cancelPendingIntent = PendingIntent.getBroadcast(this, 1, cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews notificationLayout = new RemoteViews(getPackageName(), R.layout.notification_small);
notificationLayout.setTextViewText(R.id.tvTitle, dataMap.get("sender"));
notificationLayout.setTextViewText(R.id.tvContent, getString(R.string.incoming_call));
notificationLayout.setOnClickPendingIntent(R.id.tvAccept, pendingIntent);
notificationLayout.setOnClickPendingIntent(R.id.tvDecline, cancelPendingIntent);
RemoteViews notificationLayoutExpanded = new RemoteViews(getPackageName(), R.layout.notification_large);
notificationLayoutExpanded.setTextViewText(R.id.tvTitle, dataMap.get("sender"));
notificationLayoutExpanded.setTextViewText(R.id.tvContent, getString(R.string.incoming_call));
notificationLayoutExpanded.setOnClickPendingIntent(R.id.btAccept, pendingIntent);
notificationLayoutExpanded.setOnClickPendingIntent(R.id.btDecline, cancelPendingIntent);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, AppConstants.CALL_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(dataMap.get("sender"))
.setContentText(getString(R.string.incoming_call))
.setAutoCancel(true)
.setTimeoutAfter(CALL_DISMISS_TIME)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setCustomBigContentView(notificationLayout)
.setCustomContentView(notificationLayoutExpanded)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(fullScreenPendingIntent)
.setFullScreenIntent(fullScreenPendingIntent, true);
if (Build.VERSION.SDK_INT < 26) {
builder.setPriority(NotificationCompat.PRIORITY_MAX);
}
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createCallNotificationChannel();
}
notificationManager.notify(notificationId, builder.build());
}
And i call it like this
onMessageReceived()
if (Build.VERSION.SDK_INT > 28) {
if (isAppOnForeground(getApplicationContext())) {
sendBroadcast(remoteMessage);
} else {
showCallNotification(dataMap);
}
} else {
sendBroadcast(remoteMessage);
}
I am trying to start a foreground service. I get notified that the service does start but the notification always gets suppressed. I double checked that the app is allowed to show notifications in the app info on my device. Here is my code:
private void showNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher);
Notification notification = new NotificationCompat.Builder(getApplicationContext())
.setContentTitle("Revel Is Running")
.setTicker("Revel Is Running")
.setContentText("Click to stop")
.setSmallIcon(R.mipmap.ic_launcher)
//.setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true).build();
startForeground(Constants.FOREGROUND_SERVICE,
notification);
Log.e(TAG,"notification shown");
}
Here is the only error I see in relation:
06-20 12:26:43.635 895-930/? E/NotificationService: Suppressing notification from the package by user request.
It's because of Android O bg services restrictions.
So now you need to call startForeground() only for services that were started with startForegroundService() and call it in first 5 seconds after service has been started.
Here is the guide - https://developer.android.com/about/versions/oreo/background#services
Like this:
//Start service:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(new Intent(this, YourService.class));
} else {
startService(new Intent(this, YourService.class));
}
Then create and show notification (with channel as supposed earlier):
private void createAndShowForegroundNotification(Service yourService, int notificationId) {
final NotificationCompat.Builder builder = getNotificationBuilder(yourService,
"com.example.your_app.notification.CHANNEL_ID_FOREGROUND", // Channel id
NotificationManagerCompat.IMPORTANCE_LOW); //Low importance prevent visual appearance for this notification channel on top
builder.setOngoing(true)
.setSmallIcon(R.drawable.small_icon)
.setContentTitle(yourService.getString(R.string.title))
.setContentText(yourService.getString(R.string.content));
Notification notification = builder.build();
yourService.startForeground(notificationId, notification);
if (notificationId != lastShownNotificationId) {
// Cancel previous notification
final NotificationManager nm = (NotificationManager) yourService.getSystemService(Activity.NOTIFICATION_SERVICE);
nm.cancel(lastShownNotificationId);
}
lastShownNotificationId = notificationId;
}
public static NotificationCompat.Builder getNotificationBuilder(Context context, String channelId, int importance) {
NotificationCompat.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
prepareChannel(context, channelId, importance);
builder = new NotificationCompat.Builder(context, channelId);
} else {
builder = new NotificationCompat.Builder(context);
}
return builder;
}
#TargetApi(26)
private static void prepareChannel(Context context, String id, int importance) {
final String appName = context.getString(R.string.app_name);
String description = context.getString(R.string.notifications_channel_description);
final NotificationManager nm = (NotificationManager) context.getSystemService(Activity.NOTIFICATION_SERVICE);
if(nm != null) {
NotificationChannel nChannel = nm.getNotificationChannel(id);
if (nChannel == null) {
nChannel = new NotificationChannel(id, appName, importance);
nChannel.setDescription(description);
nm.createNotificationChannel(nChannel);
}
}
}
Remember that your foreground notification will have the same state as your other notifications even if you'll use different channel ids, so it might be hidden as a group with others. Use different groups to avoid it.
The problem was i am using Android O and it requires more information. Here is the successful code for android O.
mNotifyManager = (NotificationManager) mActivity.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createChannel(mNotifyManager);
mBuilder = new NotificationCompat.Builder(mActivity, "YOUR_TEXT_HERE").setSmallIcon(android.R.drawable.stat_sys_download).setColor
(ContextCompat.getColor(mActivity, R.color.colorNotification)).setContentTitle(YOUR_TITLE_HERE).setContentText(YOUR_DESCRIPTION_HERE);
mNotifyManager.notify(mFile.getId().hashCode(), mBuilder.build());
#TargetApi(26)
private void createChannel(NotificationManager notificationManager) {
String name = "FileDownload";
String description = "Notifications for download status";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel mChannel = new NotificationChannel(name, name, importance);
mChannel.setDescription(description);
mChannel.enableLights(true);
mChannel.setLightColor(Color.BLUE);
notificationManager.createNotificationChannel(mChannel);
}
For me everything was set correctly (also added FOREGROUND_SERVICE permission to manifest),
but I just needed to uninstall the app and reinstall it.
If none of the above worked you should check if your notification id is 0 ...
SURPRISE!! it cannot be 0.
Many thanks to #Luka Kama for this post
startForeground(0, notification); // Doesn't work...
startForeground(1, notification); // Works!!!
if you are targeting Android 9(Pie) api level 28 and higher than you should give FOREGROUND_SERVICE permission in manifest file.see this link : https://developer.android.com/about/versions/pie/android-9.0-migration#bfa
I can not believe it. In my case, after adding 'android:name=".App"' to AndroidManifest.xml, the notification started showing.
Example:
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
For Android API level 33+ you need to request POST_NOTIFICATIONS runtime permission. Although this doesn't prevent the foreground service from running, it's still mandatory to notify as we did for < API 33:
Note: Apps don't need to request the POST_NOTIFICATIONS permission in order to launch a foreground service. However, apps must include a notification when they start a foreground service, just as they do on previous versions of Android.
See more in Android Documentation.
In my case, it was caused by me using IntentService.
In short, if you want a foreground service then subclass Service.
In my android application, I want to generate a notification when current time matches with the time that I have retrieved from my database. And the notification should be generated even if the application is not running. For this I have done something like this, but this is not working (no notification is being generated).
I am new to android, and I have seen many examples and tutorials for solving this issue, but they did not helped. So please give Answer that what should I do for getting the desired result?
In MainActivity.java I am doing this:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*here I am retrieving time from database*/
String time_from_database = "20:00:00";
if(Calendar.getInstance()==time_from_database) {
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(MainActivity.this, NotGen.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(MainActivity.this, 0, intent, 0);
alarmMgr.set(AlarmManager.RTC, Calendar.getInstance(), alarmIntent);
}
}
}
this is code of NotGen.java class:
public class NotGen extends BroadcastReceiver {
public NotificationCompat.Builder mBuilder;
#Override
public void onReceive(Context context, Intent intent) {
PendingIntent pIntent = PendingIntent.getActivity(context,0,intent,0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);
mBuilder.setTicker("Ticker Title");
mBuilder.setSmallIcon(R.drawable.my_img);
mBuilder.setContentTitle("Notification Alert, Click Me!");
mBuilder.setContentText("Hi, This is Android Notification Detail!");
mBuilder.setContentIntent(pIntent).getNotification();
mBuilder.setAutoCancel(true);
mBuilder.getNotification().flags |= Notification.FLAG_AUTO_CANCEL;
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mBuilder.setSound(alarmSound);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0,mBuilder.build());
}
}
Calendar.getInstance()==time_from_database will never work.
First, getInstance() is going to create a new instance, and == is object identity equality.
Second, time_from_database is a String ("20:00:00"). A Calendar instance will never equal that, if for no other reason than a Calendar is a combination of date and time.
You can achieved it using Service. Service will running in background all the time even your application is not running.
1) Create service and register it into Manifest file.
2) Start it on application start.
3) Into service you can generating your notification when current time will matched with database time.
For service example you can see below links
http://javatechig.com/android/android-service-example
http://www.tutorialspoint.com/android/android_services.htm