How to restart sticky service after power saver kills it on android - android

I tried by setting android:isolatedProcess="true" but it's not working
actually I want to show a permanent notification all time
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), resourceIcon/*R.mipmap.ic_launcher*/))
.setSmallIcon(R.drawable.ic_icon_flo_not)
.setContentTitle(title)
.setOngoing(onGoing)
.setAutoCancel(autoCancelable)
.setPriority(priority)
.setContentText(message);
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
if (playSound)
mBuilder.setSound(soundUri);
if (remoteViews == null) {
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, resultClass);
resultIntent.setAction(action);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
} else {
mBuilder.setContent(remoteViews);
}

Override onTaskRemoved() in your service and use alarm manager to start the service again. Below is code .
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.d(TAG, "TASK REMOVED");
PendingIntent service = PendingIntent.getService(
getApplicationContext(),
1001,
new Intent(getApplicationContext(), MyService.class),
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
}

Service.START_STICKY service are those which are restarted if they are terminated due to some reason.You just need to return Service.START_STICKY from onStartCommand
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
You just need to do above, There is no separate thing that you have to do

The service does get re-created, not re-started.
If you override the onCreate and do a Log.d or a Toast, you will see that onCreate gets called after your activity and app is destroyed.
So the trick to keep it running after it is re-created is to do your code on the onCreate method and use the onStartCommand just to return START_STICKY.
Another thing to notice (and since I can't comment, I'd like to add to Abdul Kawee answer with the AlarmManager):
It is SOLVED on api27: all you have to do is move your super.onTaskRemoved(rootIntent) to be the last line of code.
I have found that destructive methods should only call super in the end of the overriden method, otherwise some resources are no longer available in runtime.

Related

Why must you use Intent.setAction and Intent.AddCategory to use singleTop with PendingIntent?

I'm using example code to create a notification, which I then want to handle in onNewIntent() if my App is already running. However, onNewIntent() was not being called. I searched for a few hours and no one seemed to have a proper answer--just some workarounds.
I had to search forever to find the solution here: Android OnNewIntent not called and the answer is not actually explained.
Question
Can anyone explain why we need the lines:
resultIntent.setAction(Intent.ACTION_MAIN);
resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);
in order to receive the notification through onNewIntent()? The App launches just fine without them, but will always go through onCreate() instead.
Example Code
public void createNotification(String s){
// The id of the channel.
String CHANNEL_ID = "my_channel_01";
NotificationCompat.Builder mBuilder =
(NotificationCompat.Builder) new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.icon_missing)
.setContentTitle(getString(R.string.notification_channel_name))
.setContentText(R.string.text);
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.setAction(Intent.ACTION_MAIN);
resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your app to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mNotificationId is a unique integer your app uses to identify the
// notification. For example, to cancel the notification, you can pass its ID
// number to NotificationManager.cancel().
Notification n = mBuilder.build();
n.flags = n.flags | Notification.FLAG_AUTO_CANCEL;
mNotificationManager.notify(1, n);
}

Android service gets killed on swiping out the application

I have an Android Service class the code for which is as follows:
public class LoginService extends Service {
BroadcastReceiver wifiStateChangeReciever;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("AndroidLearning", "Service onStartCommand Started.");
return Service.START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
Log.i("AndroidLearning", "Service Started.");
final IntentFilter intentFilter = new IntentFilter();
// intentFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
intentFilter.addAction("android.net.wifi.STATE_CHANGE");
wifiStateChangeReciever = new WifiStateChangeReciever();
this.registerReceiver(wifiStateChangeReciever, intentFilter, null, null);
Log.i("AndroidLearning", "Reciever Registered.");
}
#Override
public void onDestroy() {
Log.i("AndroidLearning", "Service Destroyed.");
this.unregisterReceiver(wifiStateChangeReciever);
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.w("AndroidLearning", "On Task Remove: FLAG_STOP_WITH_TASK - "
+ ServiceInfo.FLAG_STOP_WITH_TASK);
this.unregisterReceiver(wifiStateChangeReciever);
Intent restartServiceIntent = new Intent(getApplicationContext(),
this.getClass()); restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(
getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
alarmService.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 1000, restartServicePendingIntent);
Log.w("AndroidLearning", "End on task removed");
super.onTaskRemoved(rootIntent);
}
}
It registers a BroadcastReciever. The Activity which starts this service has the following code:
Intent intent = new Intent(this, LoginService.class);
startService(intent);
However whenever the Activity is swiped out from the task list (recent) the service is also stopped. I over rode the onTaskRemoved to remedy it but it still does not seem to work and the AlarmManager never starts the pendingIntent. I have tries using both method: set and setExact for the AlarmManager.
I also tried adding the following options to <service> tags
android:stopWithTask="false"
android:process=":remote"
but to no avail.
What am I doing wrong here? Thanks for the help.
I finally found the answer to my own problem. It seems this was a problem with the particular flavor of android that I was running on my phone (Mi UI). There was a separate setting regarding each application whether it needed to be allowed to be restarted or not.
Unless this setting is configured no amount of changing permissions and setting Alarms helped me.
This is a different approach from you but I recently fixed this by adding a notification when the service was running
private void showNotification(){
NotificationCompat.Builder builer = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.logo)
.setContentTitle("Service active")
.setContentText("Your service keeps running")
.setOngoing(true);
mNotificationManager.notify(NOTIFICATION_ID, builer.build());
}
The notification is shown in onStartCommand and dismissed in the service ondestroy method.
You need to start service in foreground if you don't want android to shut it down.
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
http://developer.android.com/guide/components/services.html#Foreground
If you try this on some devices, sadly, it won't work.
Some OEMs decided to change the normal behavior of what happens when you remove an app from the recent tasks, so they become semi-disabled:
https://issuetracker.google.com/issues/122098785
https://dontkillmyapp.com/

Android: Service starts after parent activity is finished.

I have the following scheme:
Activity A -which can start Activity B.
Activity B has a background Service it uses which is triggered by an Alarm as follows:
alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
serviceSaveSample = new Intent(getApplicationContext(),
SaveSampleService.class);
alarmSaveSample = PendingIntent.getService(getApplicationContext(),
9988766, serviceSaveSample, PendingIntent.FLAG_UPDATE_CURRENT);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (secondsToSample * 1000), secondsToSample * 1000,
alarmSaveSample);
The service implementation:
public class SaveSampleService extends Service { ...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, RunActivity.class), 0);
Notification notif = new NotificationCompat.Builder(
getApplicationContext()).setAutoCancel(true)
.setContentText("message").setSmallIcon(R.drawable.logo)
.setAutoCancel(true)
.setSmallIcon(R.drawable.logo)
.setContentIntent(contentIntent)
.build();
startForeground(startId, notif);
// some work...
return START_STICKY;
}
the problem is that if i move the app to the background when Activity B is at the top of the stack and the service is running, the service restarts itself after i have closed Activity B explicitly.
i have tried any, if not all flags and still this problem persists.
tried setting the launchMode to any of the values and still not working.
any suggestions?
You need to call the cancel method of AlarmManager, and stopService in your activity onStop.
Check the Services life cycle http://developer.android.com/guide/components/services.html#StartingAService

Trying to restore state of activity upon starting it via a notification

I am implementing a webview loading the URL of an web-application that dynamically adds content to the DOM based on user-action via a socket.
As I am closing the App and a user adds another element in the web-application the app-user gets a notification.
If I re-open the App via manually starting it again, I can easily restore the webview and see the new content as well.
My problem: I want to achieve the same when re-opening the App via the notification. Currently I do not get savedInstanceState in onCreate().
launchMode is set to singleTop
Code in WebAppInterface.java:
System.out.println("WebAppInterface:" + MainActivity.MY_ACTIVITY_STATUS);
if (!MainActivity.MY_ACTIVITY_STATUS) {
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Neue Nachricht")
.setContentText(username + " hat dir geschrieben!")
.setAutoCancel(true)
.setSound(alarmSound)
.setVibrate(new long[] { 0, 1000, 1000, 1000, 1000 });
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
Intent intent= new Intent(mContext, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
stackBuilder.addNextIntent(intent);
PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
mBuilder.setContentIntent(resultPendingIntent);
// Sets an ID for the notification
int mNotificationId = 001;
// Gets an instance of the NotificationManager service
NotificationManager mNotifyMgr = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE);
// Builds the notification and issues it.
mNotifyMgr.notify(mNotificationId, mBuilder.build());
Code for restoring in my MainActivity:
if (savedInstanceState != null) {
myWebView.restoreState(savedInstanceState);
} else {
myWebView.loadUrl(URL_TO_WEB_APP);
}
So far I'Ve testes various combinations of Intent.FLAGS/launchMode as well as saving savedInstanceState to a private static variable and trying to restore the webview based on this variable (getting tons of "nativeOnDraw failed; clearing to background color." in LogCat).
Upon starting the App via notification:
private static variable "myWebView" (in which I store the webview) is set
onCreate() parameter Bundle savedInstanceState is null
private static variable "savedState" (above mentioned attempt to safe savedInstanceState and use it) is set
I'd be happy for every hint and/or even a solution, as I am currently completely clueless.
Even though I'm sure I had this combination tested dozens of times, the working combination - in order to restore the state of the WebView - is:
In WebAppInterface.java:
Intent intent= new Intent(mContext, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
stackBuilder.addNextIntent(intent);
PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
In AndroidManifest.xml:
<activity
...
android:launchMode="singleTask" >
Furthermode there was no code needed for onResume()/onNewIntent() in the MainActivity.

Android Local Notifications

What I am looking at doing is implementing local notifications. The idea is that dates are stored in an SQL file on the phone and when the current date reaches the date before the date in the SQL file i am looking at notifying the user with a message.
I have done a lot of research into this and have found things relating to Alarms and services. I am now really confused and have no idea which root to take. Could someone please help?
Thanks
What you want to do is use an AlarmManager for this that broadcasts a notification. You won't need to set the date in a database and manage it...just set the date in the AlarmManager. I've created a class for this which has a function for setting the time the alarm should go off, as well as receiving the broadcast then building the notification.
public class MyAlarmManager extends BroadcastReceiver {
private Context mContext;
private AlarmManager mAlarmManager;
public MyAlarmManager() {}
public MyAlarmManager(Context context) {
mContext = context;
mAlarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
}
#Override
public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "YOUR TAG");
//Acquire the lock
wl.acquire();
//You can do the processing here.
buildNotification(context);
//Release the lock
wl.release();
}
public void setReminder(long time) {
Intent intent = new Intent(mContext, MyAlarmManager.class);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, time, pi); //time is in milliseconds
}
public void buildNotification(Context context) {
long[] vibrate = { 0, 100, 200, 300 };
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setVibrate(vibrate)
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, YourLaunchActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(ConferencesActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
int randomId = 1000303;
mNotificationManager.notify(randomId, mBuilder.build());
}
}
Then be sure to add this in your manifest and use whatever your app package name is:
<receiver android:name="com.example.myapp.MyAlarmManager"></receiver>
Hope that helps!

Categories

Resources