I have created a BackgroundService class which extends Service class.
I have a Timer which keeps track of the duration between checks. In the onCreate method I set it for 10 seconds, so the behavior I'm expecting is that it sends a status notification message every 10 seconds. The issue I'm having is that every 10 seconds, I hear the status notification "sound" as I enabled it, but I do not see the text reminder on the top of the screen, which only appears on the first notification service alert. Does anyone know how to fix this?
I attached a good deal of source for this class below: Thanks in Advance!
private Timer timer;
private TimerTask updateTask = new TimerTask() {
#Override
public void run() {
Log.i(TAG, "Timer task doing work!");
// Process junk here:
sendNotification("Please leave in 5 min!!!");
}
};
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.i(TAG, "Background Service creating");
timer = new Timer("DurationTimer");
timer.schedule(updateTask, 1000L, 10*1000L);
}
public void sendNotification(CharSequence message)
{
// Execute Check and Notify
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
int icon = R.drawable.simon;
CharSequence tickerText = message;
long when = System.currentTimeMillis();
Notification notification = new Notification(icon, tickerText, when);
Context context = getApplicationContext();
CharSequence contentTitle = "LEAVE NOW!";
CharSequence contentText = "LEAVE NOW!!";
Intent notificationIntent = new Intent(this, BackgroundService.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.defaults |= Notification.DEFAULT_SOUND;
//notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
int HELLO_ID = 1;
mNotificationManager.notify(HELLO_ID, notification);
}
Change the value of contentText with each iteration.
Example:
CharSequence contentText = "LEAVE NOW!! " + System.currentTimeMillis();
I think you will find that the message text changes constantly because you already have a Notification with the same ID as the Notification you wish to send. So what happens is that the text is simply changed.
Another way:
mNotificationManager.clear(HELLO_ID);
Do that before you create the new Notification.
Related
I am making a android app which will allow the user to press a button and show a notification with a timer counting down for a certain amount of time. Although I have made the notification persistent so it cannot be dismissed, when the app closes the notification gets destroyed.
Is there any way to allow a notification to continue running once the app is closed and not get destroyed.
Here is the code for starting my notification and timer:
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "notifyLemubit")
.setSmallIcon(holder.img_timer.getImageAlpha())
.setContentTitle("Timer Running")
.setContentText("Time Until Your " + timer.getTimer_name() + " Tree has Fully Grown: " + timer.getTimer_duration_s())
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
final NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
notificationManagerCompat.notify(timer.getTimer_id(), builder.build());
new CountDownTimer(10 * ONE_SECOND, ONE_SECOND) {
#Override
public void onTick(long ms_until_done) {
builder.setContentText("Time Until Your " + timer.getTimer_name() + " Tree has Fully Grown: " + ms_until_done / ONE_SECOND);
notificationManagerCompat.notify(timer.getTimer_id(), builder.build());
}
#Override
public void onFinish() {
notificationManagerCompat.cancel(timer.getTimer_id());
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "notifyLemubit")
.setSmallIcon(holder.img_timer.getImageAlpha())
.setContentTitle("Timer Finished")
.setContentText("Your " + timer.getTimer_name() + " is Fully Grown!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
final NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
notificationManagerCompat.notify(timer.getTimer_id(), builder.build());
}
}.start();
Any help is appreciated, Thanks
The only way by far i know is using a Foreground service by extending the Service or IntentService class
And inside your activity or adapter use this to start the service
context.startService(Intent(context,PersistentNotificationService.class))
For the service here use this one
public class PersistentNotificationService extends Service {
private final static int ONE_SECOND = 1000;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "notifyLemubit")
.setSmallIcon(R.drawable.img_timer)
.setContentTitle("Timer Running")
.setContentText("Your title goes here")
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
new CountDownTimer(10 * ONE_SECOND, ONE_SECOND) {
#Override
public void onTick(long ms_until_done) {
// Whatever code you want here
}
#Override
public void onFinish() {
// To cancel , just close the service
stopForeground(true);
stopSelf();
}
}.start();
startForeground(2342, builder.build());
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
How to show Foreground Service activity by clicking Notification? When I use my code, it starts new activity, but I need the activity, where service is working. Here is my code (Android Oreo):
public class APSService : Service
{
public static bool isRunning = false;
public override void OnCreate()
{
base.OnCreate();
}
public override void OnDestroy()
{
isRunning = false;
base.OnDestroy();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
isRunning = true;
byte[] input = intent.GetByteArrayExtra("inputExtra");
Intent notificationIntent = new Intent(this, Java.Lang.Class.FromType((typeof(MainActivity))));
PendingIntent pendingIntent = PendingIntent.GetActivity(this,
0, notificationIntent, 0);
var builder = new NotificationCompat.Builder(this, MainActivity.CHANNEL_ID)
.SetContentTitle("APS Service")
.SetSmallIcon(Resource.Drawable.notifypump)
.SetContentText("Start program...")
.SetContentIntent(pendingIntent);
Notification notification = builder.Build();
StartForeground(1, notification);
//do heavy work on background thread
return StartCommandResult.NotSticky;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
}
And in MainActivity in OnCreate:
protected override void OnCreate(Bundle savedInstanceState)
{
if (!APSService.isRunning)
{
createNotificationChannel();
startService();
}
else
{
NotificationChannel serviceChannel = new NotificationChannel
(
CHANNEL_ID,
"APS service Channel",
NotificationImportance.Default
);
notificationManager = (NotificationManager)GetSystemService(Java.Lang.Class.FromType((typeof(NotificationManager))));
notificationManager.CreateNotificationChannel(serviceChannel);
UpdateNotification("Loading...");
APSService.isRunning = true;
}
}
I hope you would help for solving this problem. Thanks a lot.
I write a demo about it, here is a GIF.
You can achieve the festure like following code.
[Service]
class MyForegroundService : Service
{
public const int SERVICE_RUNNING_NOTIFICATION_ID = 10000;
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
CreateNotificationChannel();
string messageBody = "service starting";
// / Create an Intent for the activity you want to start
Intent resultIntent = new Intent(this,typeof(Activity1));
// Create the TaskStackBuilder and add the intent, which inflates the back stack
TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);
stackBuilder.AddNextIntentWithParentStack(resultIntent);
// Get the PendingIntent containing the entire back stack
PendingIntent resultPendingIntent = stackBuilder.GetPendingIntent(0, PendingIntentFlags.UpdateCurrent);
var notification = new Notification.Builder(this, "10111")
.SetContentIntent(resultPendingIntent)
.SetContentTitle("Foreground")
.SetContentText(messageBody)
.SetSmallIcon(Resource.Drawable.main)
.SetOngoing(true)
.Build();
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
//do you work
return StartCommandResult.Sticky;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
// Notification channels are new in API 26 (and not a part of the
// support library). There is no need to create a notification
// channel on older versions of Android.
return;
}
var channelName = Resources.GetString(Resource.String.channel_name);
var channelDescription = GetString(Resource.String.channel_description);
var channel = new NotificationChannel("10111", channelName, NotificationImportance.Default)
{
Description = channelDescription
};
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
}
}
Here is my demo.
https://github.com/851265601/ForegroundServiceDemo
It's not clear to me what Activity you want to open
How to show Foreground Service activity
A Foreground service runs independently from your app
You are launching the MainActivity here:
Intent notificationIntent = new Intent(this,Java.Lang.Class.FromType((typeof(MainActivity))));
can you clarify what do want to do here?
ps: I know it's not an answer, can't comment yet
I tried making an app that sends a custom notification to android wear, that part worked but then I wanted to implement a service so that the app will send the notification every minute. But I am missing something,can you guys help me please? Thanks a lot! The error points to "this", I am new to android programming, I really don't know how to solve this.
public class MainActivity extends Activity {
public class notifService extends Service {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
public IBinder onBind(Intent arg0) {
return null;
}
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
final Intent intent1 = new Intent(this, notifService.class);
scheduler.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
setContentView(R.layout.activity_main);
//Create PendingIntent
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
//Create Notification Action
NotificationCompat.Action action = new NotificationCompat.Action.Builder(
R.mipmap.app_icon, getString(R.string.wearTitle), pendingIntent).build();
//Create Notification
Notification notification = new NotificationCompat.Builder(this)
.setContentText(getString(R.string.content))
.setContentTitle(getString(R.string.title))
.setSmallIcon((R.mipmap.app_icon))
.extend(new NotificationCompat.WearableExtender().addAction(action))
.build();
//Create Notification Manager
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(this);
notificationManagerCompat.notify(001, notification);
}
}, 60, 60, TimeUnit.SECONDS);
I'm getting this error on GCM and sometime I receive the message but no notification was generated. Could anyone help me to identify what's the problem?
Here's my code (some business logic code was removed for simplicity):
GcmBroadcastReceiver:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
GcmIntentService:
public class GcmIntentService extends GCMBaseIntentService {
private static final String TAG = "GCMIntentService";
public GcmIntentService() {
super(ConstantManager.SENDER_ID);
}
/**
* Method called on device registered
**/
#Override
protected void onRegistered(Context context, String registrationId) {
Log.i(TAG, "Device registered: regId = " + registrationId);
}
/**
* Method called on device un registred
* */
#Override
protected void onUnregistered(Context context, String registrationId) {
Log.i(TAG, "Device unregistered");
}
/**
* Method called on Receiving a new message
* */
#Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = intent.getExtras().getString("message");
String type = intent.getExtras().getString("type");
int eventId = 0;
generateNotification(context, message,2,eventId);
}
/**
* Method called on receiving a deleted message
* */
#Override
protected void onDeletedMessages(Context context, int total) {
Log.i(TAG, "Received deleted messages notification");
// notifies user
generateNotification(context, "Deleted Message",0,0);
}
/**
* Method called on Error
* */
#Override
public void onError(Context context, String errorId) {
Log.i(TAG, "Received error: " + errorId);
}
#Override
protected boolean onRecoverableError(Context context, String errorId) {
// log message
Log.i(TAG, "Received recoverable error: " + errorId);
return super.onRecoverableError(context, errorId);
}
/**
* Issues a notification to inform the user that server has sent a message.
*/
#SuppressWarnings("deprecation")
private static void generateNotification(Context context, String message,int type,int referId) {
int icon = R.drawable.logo_v2;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
Log.i(TAG, "Generating Notification");
String title = context.getString(R.string.app_name);
if(GeneralManager.sessionManager.isLoggedIn())
{
if(type==2)
{
Log.i(TAG, "Type 2");
Intent notificationIntent = new Intent(context, PendingEventDetailsActivity.class);
SharedPreferences pref = context.getSharedPreferences(SessionManager.PREF_NAME, SessionManager.PRIVATE_MODE);
String userId = pref.getString(SessionManager.KEY_USER_ID,null);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
notificationIntent.putExtra("eventId", String.valueOf(referId));
notificationIntent.putExtra("userId", userId);
PendingIntent intent =
PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Play default notification sound
notification.defaults |= Notification.DEFAULT_SOUND;
//notification.sound = Uri.parse("android.resource://" + context.getPackageName() + "your_sound_file_name.mp3");
// Vibrate if vibrate is enabled
notification.defaults |= Notification.DEFAULT_VIBRATE;
notificationManager.notify(0, notification);
}
else
{
Log.i(TAG, "Other type");
Intent notificationIntent = new Intent(context, WelcomeActivity.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
notificationIntent.putExtra("notification", "true");
PendingIntent intent =
PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Play default notification sound
notification.defaults |= Notification.DEFAULT_SOUND;
//notification.sound = Uri.parse("android.resource://" + context.getPackageName() + "your_sound_file_name.mp3");
// Vibrate if vibrate is enabled
notification.defaults |= Notification.DEFAULT_VIBRATE;
notificationManager.notify(0, notification);
}
}
}
}
I know this answer is ver late,but hope it can help someone else.
This problem can be solved by two Methods :
Method 1 :
This problem is encountered when WakeLock is released incorrectly i.e. When library tries to release WakeLock that holds nothing (internal lock counter becomes negative).To avoid this you can add following line of code(catching the exception if the WakeLock is not active) on WakeLocker.release(); :
synchronized (LOCK) {
// sanity check for null as this is a public method
if (WakeLock != null) {
Log.v(TAG, "Releasing wakelocker");
try {
WakeLocker.release();
} catch (Throwable th) {
// ignoring this exception, probably wakeLock was already released
}
} else {
// should never happen during normal workflow
Log.e(TAG, "Reference of WakeLock is null");
}
}
Method 2 :
This is more convenient way of solving the problem, u can use WakeLocker.isHeld(); on WakeLocker.release(); i.e.
if (WakeLocker.isHeld())
WakeLocker.release();
Hope it helps anyone.
I am trying to get an android notification to show up at noon every day. The notification seems to show up once whenever the device is started, then somewhat sporadically afterwards.
Here is my service:
public class myService extends Service {
public static final String TAG = "LocationLoggerServiceManager";
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.v(TAG, "on onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LoginActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("App name")
.setContentText("Notification")
.setContentIntent(contentIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify("main", 1, mBuilder.build());
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
and Receiver:
public class MyBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "LocationLoggerServiceManager";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Broadcast Received");
handleMessage(context, intent);
}
private void handleMessage(Context context, Intent intent)
{
PendingIntent contentIntent = PendingIntent.getService(context, 0, new Intent(context, myService.class), 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(contentIntent);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 12);
calendar.set(Calendar.MINUTE, 00);
calendar.set(Calendar.SECOND, 00);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 24*60*60*1000 , contentIntent);
}
}
Any pointers are appreciated. Thank you.
I attempted to set up my own notification / alarm class. The only way I found to manage it was to extend the Android calendar.
If you would like to try it this way see this link for a start:
http://developer.android.com/guide/topics/providers/calendar-provider.html
I have an example of this approach however i am at work, I can provide my code later if you need it!
What may be happening is that the system kills your Service to free up memory and since the superclass's onStartCommand() returns START_STICKY, recreates it later, causing your notification to sporadically appear.
Really, if the Service's purpose is just to make a Notification consider moving that portion of code some sort of BroadcastReceiver or stop the Service after the Notification is created.