here is my code :
public class MainActivity extends Activity {
private NotificationManager mNotifyManager;
private NotificationCompat.Builder mBuilder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
}
public void click(View view) {
noti();
}
private void noti() {
mBuilder.setContentTitle("Picture Download")
.setContentText("Download in progress")
.setSmallIcon(R.drawable.ic_launcher);
// Start a lengthy operation in a background thread
new Thread(
new Runnable() {
#Override
public void run() {
int incr;
// Do the "lengthy" operation 20 times
for (incr = 0; incr <= 100; incr+=5) {
// Sets the progress indicator to a max value, the
// current completion percentage, and "determinate"
// state
mBuilder.setProgress(100, incr, false);
// Displays the progress bar for the first time.
mNotifyManager.notify(0, mBuilder.build());
// Sleeps the thread, simulating an operation
// that takes time
try {
// Sleep for 5 seconds
Thread.sleep(1*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// When the loop is finished, updates the notification
mBuilder.setContentText("Download complete")
// Removes the progress bar
.setProgress(0,0,false);
mNotifyManager.notify(0, mBuilder.build());
}
}
// Starts the thread by calling the run() method in its Runnable
).start();
}
}
it works fine on android 4.2.2 device , but when I tried to run it on an android 2.2 device , the notification didn't show up,and I got the following logs:
RuntimeException in notify -
java.lang.Throwable: stack dump
at android.app.NotificationManager.notify(NotificationManager.java:118)
at android.app.NotificationManager.notify(NotificationManager.java:92)
at com.gyh.notitest.MainActivity$1.run(MainActivity.java:49)
at java.lang.Thread.run(Thread.java:1019)
can anyone help me ? how can I display a progress bar in a Notification on android 2.2 devices without custom layout?
thanks!
Never mind..
I change my code to:
public class MainActivity extends Activity {
private NotificationManager mNotifyManager;
private NotificationCompat.Builder mBuilder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent resultIntent = new Intent(this, MainActivity.class);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(
getApplicationContext()).setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setContentIntent(resultPendingIntent);
}
public void click(View view) {
noti();
}
private void noti() {
// Start a lengthy operation in a background thread
new Thread(
new Runnable() {
#Override
public void run() {
int incr;
// Do the "lengthy" operation 20 times
for (incr = 0; incr <= 100; incr+=5) {
// Sets the progress indicator to a max value, the
// current completion percentage, and "determinate"
// state
mBuilder.setProgress(100, incr, false);
// Displays the progress bar for the first time.
mNotifyManager.notify(0, mBuilder.build());
// Sleeps the thread, simulating an operation
// that takes time
try {
// Sleep for 5 seconds
Thread.sleep(1*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// When the loop is finished, updates the notification
mBuilder.setContentText("Download complete")
// Removes the progress bar
.setProgress(0,0,false);
mNotifyManager.notify(0, mBuilder.build());
}
}
// Starts the thread by calling the run() method in its Runnable
).start();
}
}
Then there came the Notification , But no progress T_T There is nothing I can do about it .. the only way I can think of right now is a custom layout with a progress bar...
Have you tried import the v4.jar library to your project? It supports features of new api version running on low api ( Android 2.2 for instance).
Cheers,
I re-wrote your code to enable multiple Notification Progress. Also updated to work on android Oreo+
class MainActivity : AppCompatActivity(){
private var mNotifyManager: NotificationManagerCompat? = null
private var mBuilder: NotificationCompat.Builder? = null
private var notificationId = 0
val CHANNEL_ID ="download_progress_notification"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mNotifyManager = NotificationManagerCompat.from(this)
mBuilder = NotificationCompat.Builder(this, CHANNEL_ID)
}
private fun noti(notficationId : Int) {
mBuilder?.setContentTitle("Picture Download")
?.setContentText("Download in progress")
?.setSmallIcon(R.mipmap.ic_launcher)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // you must create a notification channel for API 26 and Above
val name = "my channel2"
val description = "channel description2"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description)
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(channel)
}
// Start a lengthy operation in a background thread
Thread(object : Runnable{
override fun run() {
var incr: Int
// Do the "lengthy" operation 20 times
incr = 0
while (incr <= 100) {
// Sets the progress indicator to a max value, the
// current completion percentage, and "determinate"
// state
mBuilder?.setProgress(100, incr, false)
// Displays the progress bar for the first time.
mNotifyManager?.notify(notficationId, mBuilder!!.build())
// Sleeps the thread, simulating an operation
// that takes time
try {
// Sleep for 5 seconds
Thread.sleep((1 * 1000).toLong())
} catch (e: InterruptedException) {
e.printStackTrace()
}
incr += 5
}
// When the loop is finished, updates the notification
mBuilder?.setContentText("Download complete")
// Removes the progress bar
?.setProgress(0, 0, false)
mNotifyManager?.notify(notficationId, mBuilder!!.build())
}
}).start()
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
R.id.menu_option -> {
noti(notificationId++)
return true
}
}
return super.onOptionsItemSelected(item)
}
}
Related
I wrote service to watch ping devices connected to my wifi in order to turn off heating in apartment on/off.
I was about to buy raspberry pi, but I got idea to use my old android 10 phone running lineage os.
I did write the service. It runs fine, until I turn the screen off. Then it stops pinging the devices and controling the heating api.
Once I turn the screen back on, it starts by itself again.
This is how I start the service:
public void StartService()
{
var intent = new Intent(context, typeof(AutomationService));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
context.StartForegroundService(intent);
}
else
{
context.StartService(intent);
}
}
Notification:
public Notification GetNotification()
{
// Building intent
var intent = new Intent(context, typeof(MainActivity));
intent.AddFlags(ActivityFlags.SingleTop);
intent.PutExtra("Title", "Message");
var pendingIntent = PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.UpdateCurrent);
var notifBuilder = new NotificationCompat.Builder(context, foregroundChannelId)
.SetContentTitle("Netatmo automation")
.SetContentText("Running")
.SetSmallIcon(Resource.Drawable.abc_ab_share_pack_mtrl_alpha)
.SetOngoing(true)
.SetContentIntent(pendingIntent);
// Building channel if API verion is 26 or above
if (global::Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
NotificationChannel notificationChannel = new NotificationChannel(foregroundChannelId, "Title", NotificationImportance.High);
notificationChannel.Importance = NotificationImportance.High;
notificationChannel.EnableLights(true);
notificationChannel.EnableVibration(true);
notificationChannel.SetShowBadge(true);
notificationChannel.SetVibrationPattern(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 });
var notifManager = context.GetSystemService(Context.NotificationService) as NotificationManager;
if (notifManager != null)
{
notifBuilder.SetChannelId(foregroundChannelId);
notifManager.CreateNotificationChannel(notificationChannel);
}
}
return notifBuilder.Build();
}
And the service itself:
[Service]
public class AutomationService : Service
{
public AutomationService()
{
controlApplication = new ControlApplication();
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public const int ServiceRunningNotifID = 9000;
private readonly ControlApplication controlApplication;
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Notification notif = DependencyService.Get<INotificationHelper>().GetNotification();
StartForeground(ServiceRunningNotifID, notif);
controlApplication.StartApplication();
return StartCommandResult.Sticky;
}
public override void OnDestroy()
{
base.OnDestroy();
}
public override bool StopService(Intent name)
{
return base.StopService(name);
}
}
This part controlApplication.StartApplication(); is just starting while(true) loop in task doing the ping checks and sending http requests by logic.
Can someone help me how to keep the service alive when the screen turns off?
I opted to the phone first, since it will be more power efficient than the raspberry.
I will be glad for any input.
Cheers
EDIT--
This is StartApplication method... It doesn´t run on main thread.
public void StartApplication()
{
this.Log().Debug("Starting application");
_ = Task.Run(async () =>
{
await authorizationService.AuthorizeAsync(username, password).ConfigureAwait(false);
pingWatchService.Start();
});
}
The problem is the while(true) loop is run in the main thread. When the screen is off, the loop will block. So you service will be killed by the system. I have repeated your problem when I add a while(true) into the OnStartCommand method. And you can solve it just create a new thread to do the loop. Such as:
Thread thread = new Thread( controlApplication.StartApplication);
thread.Start();
Use the PowerManager Service:
Add the code to your service.
private PowerManager.WakeLock wakeLock;
PowerManager powerManager = (PowerManager)this.GetSystemService(Context.PowerService);
wakeLock = powerManager.NewWakeLock(WakeLockFlags.Partial,Class.Name);
wakeLock.Acquire();
And add the wakeLock.Release(); to the OnDestory method of the service.
Currently, if our device connected to WiFi, WhatsApp will perform sync to cloud, by showing a progress bar in notification area.
I was wondering, how can I achieve so using WorkManager? Currently, I know I can setup specific constraint, for WorkManager to run a background job.
Delayed time
Network constraint
But, how can we show a notification UI, via WorkManager?
Here is something which i have in my mind that can help.
The idea is to create a worker and put your logic to get the progress and show updates as a notification using handler.
NOTE : This code is not tested and i am using it just to explain the way
Worker Code
public class CompressWorker extends Worker {
public CompressWorker(#NonNull Context context, #NonNull WorkerParameters params) {
super(context, params);
}
#NonNull
#Override
public Result doWork() {
ProgressManager manager = new ProgressManager();
int i = 0;
while(i<100){
i++;
try {
Thread.sleep(1000);
manager.updateProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.i("Ansh", "worker's job is finished");
// Indicate success or failure with your return value:
return Result.success();
// (Returning Result.retry() tells WorkManager to try this task again
// later; Result.failure() says not to try again.)
}}
And there is another class using the handler to send the updates to the notification
public class ProgressManager {
Context context;
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(
context);
notificationBuilder.setProgress(100, msg.arg1, true);
Notification notification = notificationBuilder.build();
notificationManagerCompat.notify(1000, notification);
}
};
public void updateProgress(int val) {
Message msg = new Message();
msg.arg1 = val;
handler.sendMessageDelayed(msg, 1000);
}}
I am using foregroundService for playing audio in Background and show a notification with actions.
public NotificationHelper(ForegroundService service) {
mFG_Service = service;
mNotificationManager = (NotificationManager) mFG_Service.getSystemService(Context.NOTIFICATION_SERVICE);
}
public void showNotification(ChaptersBO chaptersBO, boolean isPlaying) {
Notification notification = createNotification(chaptersBO, isPlaying);
if (notification != null) {
if (isPlaying) {
mFG_Service.startForeground(NOTIFICATION_ID.FOREGROUND_SERVICE, notification);
} else {
mFG_Service.stopForeground(false);
mNotificationManager.notify(NOTIFICATION_ID.FOREGROUND_SERVICE, notification);
}
}
}
private Notification createNotification(ChaptersBO chapter, boolean isPlaying) {
if (chapter == null)
return null;
NotificationCompat.Builder builder = new NotificationCompat.Builder(mFG_Service);
try {
Bitmap sourceBitmap = BitmapFactory.decodeResource(mFG_Service.getResources(), R.drawable.notification_logo);
Bitmap resizedBitmap = Bitmap.createScaledBitmap(sourceBitmap, 300, 300, false);
if (resizedBitmap != sourceBitmap) {
sourceBitmap.recycle();
}
builder.setContentTitle("Audio")
.setContentText(chapter.getChapterNumber())
.setPriority(Notification.PRIORITY_DEFAULT)
.setSmallIcon(getSmallIcon(isPlaying))
.setLargeIcon(resizedBitmap)
.setShowWhen(false)
.setOngoing(isPlaying)
.setContentIntent(getPendingIntent())
.addAction(R.drawable.ic_notif_prev, "", getAction(ACTION.PREV_ACTION, REQ_CODE_PREVIOUS))
.addAction(getSmallIcon(isPlaying), "", getAction(ACTION.PLAY_PAUSE_ACTION, REQ_CODE_PLAY_OR_PAUSE))
.addAction(R.drawable.ic_notif_next, "", getAction(ACTION.NEXT_ACTION, REQ_CODE_NEXT))
.setDeleteIntent(getStopIntent())
.setStyle(new NotificationCompat.DecoratedCustomViewStyle());
} catch (Exception e) {
e.printStackTrace();
}
return builder.build();
}
I want to update notification small icon and center action icon on play/pause. For the first time it works fine but if I clear the notification and play another audio then these icons (Encircled in below screenshot) are not updating.
To pause audio I am calling this:
mNotificationManager.notify(NOTIFICATION_ID.FOREGROUND_SERVICE, notification);
If I replace it with this
mFG_Service.startForeground(NOTIFICATION_ID.FOREGROUND_SERVICE, notification);
then it works fine but in that case I can't clear notification.
Any suggestions to update these icons on Play/Pause and also make the notification removable when audio is paused will be appreciated.
I have followed tutorial in http://developer.android.com/training/notify-user/index.html
It works well. But what I want is : when I click ping, the old service will we stopped, and then create the service again. So if I clicked id multiple time, It will notify me only once.
Problem: If I set time 10, then I click "Ping" button. Then after 5 second, I click it again. It will notify me twice.
What I want : If I set time 10, then I click "Ping" button. Then after 5 second, I click it it will notify only once, 10 secondds after the last time I click the button.
public class MainActivity extends Activity {
private Intent mServiceIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Creates an explicit Intent to start the service that constructs and
// issues the notification.
mServiceIntent = new Intent(getApplicationContext(), PingService.class);
}
/*
* Gets the values the user entered and adds them to the intent that will be
* used to launch the IntentService that runs the timer and issues the
* notification.
*/
public void onPingClick(View v) {
stopCurrentService();
int seconds;
// Gets the reminder text the user entered.
EditText msgText = (EditText) findViewById(R.id.edit_reminder);
String message = msgText.getText().toString();
mServiceIntent.putExtra(CommonConstants.EXTRA_MESSAGE, message);
mServiceIntent.setAction(CommonConstants.ACTION_PING);
Toast.makeText(this, R.string.timer_start, Toast.LENGTH_SHORT).show();
// The number of seconds the timer should run.
EditText editText = (EditText) findViewById(R.id.edit_seconds);
String input = editText.getText().toString();
if (input == null || input.trim().equals("")) {
// If user didn't enter a value, sets to default.
seconds = R.string.seconds_default;
} else {
seconds = Integer.parseInt(input);
}
int milliseconds = (seconds * 1000);
mServiceIntent.putExtra(CommonConstants.EXTRA_TIMER, milliseconds);
// Launches IntentService "PingService" to set timer.
startService(mServiceIntent);
}
private void stopCurrentService() {
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> serviceList = activityManager
.getRunningServices(Integer.MAX_VALUE);
if (serviceList.size() <= 0) { }
int size = serviceList.size();
for (int i = 0; i < size; i++) {
RunningServiceInfo serviceInfo = serviceList.get(i);
ComponentName serviceName = serviceInfo.service;
if (serviceName.getClassName().equals(PingService.class.getName())) {
try {
Intent intentstop = new Intent();
intentstop.setComponent(serviceName);
getApplicationContext().stopService(intentstop);
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
}
}
PingService creates a notification that includes 2 buttons: one to snooze the
notification, and one to dismiss it.
public class PingService extends IntentService {
private NotificationManager mNotificationManager;
private String mMessage;
private int mMillis;
NotificationCompat.Builder builder;
private boolean status;
public PingService() {
// The super call is required. The background thread that IntentService
// starts is labeled with the string argument you pass.
super("com.example.android.pingme");
}
#Override
protected void onHandleIntent(Intent intent) {
// The reminder message the user set.
mMessage = intent.getStringExtra(CommonConstants.EXTRA_MESSAGE);
// The timer duration the user set. The default is 10 seconds.
mMillis = intent.getIntExtra(CommonConstants.EXTRA_TIMER,
CommonConstants.DEFAULT_TIMER_DURATION);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
String action = intent.getAction();
// This section handles the 3 possible actions:
// ping, snooze, and dismiss.
if (action.equals(CommonConstants.ACTION_PING)) {
issueNotification(intent, mMessage);
} else if (action.equals(CommonConstants.ACTION_SNOOZE)) {
nm.cancel(CommonConstants.NOTIFICATION_ID);
Log.d(CommonConstants.DEBUG_TAG, getString(R.string.snoozing));
// Sets a snooze-specific "done snoozing" message.
issueNotification(intent, getString(R.string.done_snoozing));
} else if (action.equals(CommonConstants.ACTION_DISMISS)) {
nm.cancel(CommonConstants.NOTIFICATION_ID);
}
}
private void issueNotification(Intent intent, String msg) {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Sets up the Snooze and Dismiss action buttons that will appear in the
// expanded view of the notification.
Intent dismissIntent = new Intent(this, PingService.class);
dismissIntent.setAction(CommonConstants.ACTION_DISMISS);
PendingIntent piDismiss = PendingIntent.getService(this, 0,
dismissIntent, 0);
Intent snoozeIntent = new Intent(this, PingService.class);
snoozeIntent.setAction(CommonConstants.ACTION_SNOOZE);
PendingIntent piSnooze = PendingIntent.getService(this, 0,
snoozeIntent, 0);
// Constructs the Builder object.
builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_stat_notification)
.setTicker("Ping ! ping ! PIng!")
.setContentTitle(getString(R.string.notification))
.setContentText(getString(R.string.ping))
.setDefaults(Notification.DEFAULT_ALL)
// requires VIBRATE permission
/*
* Sets the big view "big text" style and supplies the text (the
* user's reminder message) that will be displayed in the detail
* area of the expanded notification. These calls are ignored by
* the support library for pre-4.1 devices.
*/
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.addAction(R.drawable.ic_stat_dismiss,
getString(R.string.dismiss), piDismiss)
.addAction(R.drawable.ic_stat_snooze,
getString(R.string.snooze), piSnooze);
/*
* Clicking the notification itself displays ResultActivity, which
* provides UI for snoozing or dismissing the notification. This is
* available through either the normal view or big view.
*/
Intent resultIntent = new Intent(this, ResultActivity.class);
resultIntent.putExtra(CommonConstants.EXTRA_MESSAGE, msg);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
// Because clicking the notification opens a new ("special") activity,
// there's
// no need to create an artificial back stack.
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,
resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
startTimer(mMillis);
}
// Starts the timer according to the number of seconds the user specified.
private void startTimer(int millis) {
Log.d(CommonConstants.DEBUG_TAG, getString(R.string.timer_start));
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Log.d(CommonConstants.DEBUG_TAG, getString(R.string.sleep_error));
}
Log.d(CommonConstants.DEBUG_TAG, getString(R.string.timer_finished));
issueNotification(builder);
}
private void issueNotification(NotificationCompat.Builder builder) {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Including the notification ID allows you to update the notification
// later on.
mNotificationManager.notify(CommonConstants.NOTIFICATION_ID,
builder.build());
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
I have called stopService(), but the old notification shows up again.
What I want is it will notify me once, 10 seconds after the latest click.
You can use handler in order to stop/start your service.
Please look at my code. It's not exactly related to your code but you can get the idea.
Click this link
You can do checking in Run method of Runnable.
I am making an application in android using eclipse IDE and i want to implement a notification in my android i want to make the notification on button click example i want to notify saved data..i found this tutorial here i copied the code and paste it in my setOnClickListener code..but im getting error..i dont know how to start doing this because in the tutorial they just give you the code snippet..this is my code
UPDATE QUESTION
what is the difference between notification and push notification and which is better to use..
submit.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
mNotifyManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("Picture Download")
.setContentText("Download in progress")
.setSmallIcon(R.drawable.ic_notification);
// Start a lengthy operation in a background thread
new Thread(
new Runnable() {
#Override
public void run() {
int incr;
// Do the "lengthy" operation 20 times
for (incr = 0; incr <= 100; incr+=5) {
// Sets the progress indicator to a max value, the
// current completion percentage, and "determinate"
// state
mBuilder.setProgress(100, incr, false);
// Displays the progress bar for the first time.
mNotifyManager.notify(0, mBuilder.build());
// Sleeps the thread, simulating an operation
// that takes time
try {
// Sleep for 5 seconds
Thread.sleep(5*1000);
} catch (InterruptedException e) {
Log.d(TAG, "sleep failure");
}
}
// When the loop is finished, updates the notification
mBuilder.setContentText("Download complete")
// Removes the progress bar
.setProgress(0,0,false);
mNotifyManager.notify(ID, mBuilder.build());
}
}
// Starts the thread by calling the run() method in its Runnable
).start();
}
});
You should change this
mBuilder = new NotificationCompat.Builder(this);
to
mBuilder = new NotificationCompat.Builder(youractivity.this);
You need to pass current Context for creating mBuilder object.