I have a general question about setting up a daily data check from my app (giving a notification when some event occurs).
My current approach is:
From the app (onCreate) I start a service
From the service I set an alarm using AlarmManager after checking if there already is a matching PendingIntent (in which case I don't
need to set a new alarm)
The service checks the data from SharedPreferences and eventually shows a notification
For testing purposes I set the alarm to +1 minute ... but it didn't work that way. Maybe I'm doing something wrong conceptionally?
Some code
AndroidManifest.xml
<application
<activity
android:name=".OverviewActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar"
android:configChanges="orientation"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="xxxxx.CheckDaysMonths" >
</service>
</application>
Service CheckDaysMonths
public class CheckDaysMonths extends Service {
private static int ALARM_ID = 131313;
private static String DECLARED_ACTION = "xxxxx.CheckDaysMonths";
#Override
public void onCreate() {
super.onCreate();
PendingIntent alarmIntent = AlarmHelper.getPendingIntentFromAlarm(this, ALARM_ID, DECLARED_ACTION);
if(alarmIntent == null) {
if(someConditionIsMet)
sendNotification(" my notification text ");
// Set an alarm for the next time this service should run:
setAlarm();
}
stopSelf();
}
public void setAlarm() {
AlarmHelper.setAlarm(this, ALARM_ID, DECLARED_ACTION, 8);
}
public void sendNotification(String notifyText) {
Intent mainIntent = new Intent(this, OverviewActivity.class);
#SuppressWarnings("deprecation")
Notification noti = new Notification.Builder(this)
.setAutoCancel(true)
.setContentIntent(PendingIntent.getActivity(this, 131314, mainIntent,
PendingIntent.FLAG_UPDATE_CURRENT))
.setContentTitle("Gratuliere!")
.setContentText("Du bist seit " + notifyText + " rauchfrei!")
.setDefaults(Notification.DEFAULT_ALL)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker("Du bist seit " + notifyText + " rauchfrei!")
.setWhen(System.currentTimeMillis())
.getNotification();
NotificationManager notificationManager
= (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(131315, noti);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Inside the main activity (OverviewActivity.java)
EDIT: Changed service call from implicit to explicit
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_overview);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
startService(new Intent(this, CheckDaysMonths.class));
// additional stuff happening on the activity of my app goes here:
...
}
AlarmHelper.java
public class AlarmHelper {
public static PendingIntent getPendingIntentFromAlarm(Context context, int alarmId, String declaredAction) {
return (PendingIntent.getService(context, alarmId,
new Intent(declaredAction),
PendingIntent.FLAG_NO_CREATE));
}
public static void setAlarm(Context context, int alarmId, String declaredAction, int hourOfDay) {
Intent serviceIntent = new Intent(declaredAction);
PendingIntent pi = PendingIntent.getService(context, alarmId, serviceIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// How long until tomorrow to its hourOfDay?
//DateTime tomorrow = (new DateTime()).plusDays(1);
//DateTime tomorrowAtHourOfDay = new DateTime(tomorrow.getYear(), tomorrow.getMonthOfYear(), tomorrow.getDayOfMonth(), hourOfDay, 0);
DateTime tomorrowAtHourOfDay = (new DateTime()).plusHours(3);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, tomorrowAtHourOfDay.getMillis(), pi);
}
}
I fixed it by introducing another "middle tier" service
So now I have
The app GUI starting service 1
Service 1 will check if there is already an alarm with the correct signature running. If not, it will start an alarm
The alarm will fire at 2am and start service 2
Service 2 will check the data (SharedPreferences) and eventually send a notification. Then it will start the alarm again
A BroadcastReceiver for BOOT starts Service 2
This works quite well
Related
i set two different alarms that should make 2 notifications
8:34:0 pm create notification 1 with title and msg..
8:34:10 pm create notification 2 with title and msg...
the problem is they both appear together at 8:34:00 pm
(at the first alarm time (both))!!!
what i did:-
1- i made a broadcast class with notification manager to build notification
2- main activity created alarmManager and calendar instance to set time for alarm.
public class MainActivity extends AppCompatActivity {
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Creating alarm method(requestcode,hours,min,seconds)
setAlarmo(1,20,34,0);
setAlarmo(2,20,34,10);
}
// the Alarm Method
public void setAlarmo(int reqcode, int hour,int minute,int second){
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY,hour);
calendar.set(Calendar.MINUTE,minute);
calendar.set(Calendar.SECOND,second);
long timeinMillis = calendar.getTimeInMillis();
Intent intent = new Intent(getApplicationContext(),AlertRec.class);
intent.putExtra("reqcode",reqcode);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),reqcode,intent,PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.set(alarmManager.RTC_WAKEUP,timeinMillis,pendingIntent);
}
}
#
// AlertClass receiver extending broadcastReceiver
public class AlertRec extends BroadcastReceiver {
#Override
public void onReceive( final Context context, Intent intent) {
// Creating receiveAlarm method(requestCode,Context,intent,title,text for notification)
//receiving first Alarm from MainActivity.Class
recAlarmo(1, context,intent,"title 1","im msg 1");
//receiving Second Alarm from MainActivity.Class
recAlarmo(2,context,intent,"title 2","im msg 2");
}
// receiving Alarms Method and Creating Notifications
public void recAlarmo(int reqcode , Context context,Intent intent,String title,String msg){
intent = new Intent(context,MainActivity.class);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
PendingIntent pendingIntent = PendingIntent.getActivity(context.getApplicationContext(),reqcode,intent,PendingIntent.FLAG_ONE_SHOT);
builder.setContentTitle(title);
builder.setSmallIcon(android.R.drawable.star_on);
builder.setContentText(msg);
builder.setAutoCancel(true);
builder.setContentIntent(pendingIntent);
builder.setDefaults(NotificationCompat.DEFAULT_SOUND);
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(reqcode,builder.build());
}
}
#
<uses-permission android:name="android.permission.SET_ALARM"></uses-permission>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".AlertRec"></receiver>
</application>
i solved it !
------------------------------
in MainActivity
1-create a method that takes int number
and inside the method make a pending intent and within the intent of the pending intent
pass the int number as intent.putExtra("id",number);
public void Method(int id ,int hour , int minute, int seconds){
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY,hour);
calendar.set(Calendar.MINUTE,minute);
calendar.set(Calendar.SECOND,second);
Intent alertIntent = new Intent(getApplicationContext(), AlertRec.class);
alertIntent.putExtra("id",id);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),PendingIntent.getBroadcast(getApplicationContext(),id,alertIntent,PendingIntent.FLAG_UPDATE_CURRENT));
}
----------------------------------------------------
2- at the Receiver class
//override the OnReceive method
onReceive(Context context,Intent intent ){
int Checker =intent.getExtras.getInt("id");
if(Checker == 1 ) {
// do anything you want for the intent of the pending intent at MainActivity that have int id = 1;
//your method here
}else if(Checker == 2) {
// do anything you want for the intent of the pending intent at MainActivity that have int id = 2;
// your method here
}else{
}
}
I'm trying to make an app that monitors the users phone usage by tracking time of screen lock and unlock. I tried to setup a BroadcastReceiver which works fine when the app is running the background. But won't work when I close the app. Is there a solution for this.
The code I'm using now is as follows :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, ScreenListenerService.class);
startService(intent);
}
}
ScreenListenerService class is as follows..
public class ScreenListenerService extends Service {
private BroadcastReceiver mScreenStateBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// Save something to the server
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// Save something to the server
}
}
};
#Override
public void onCreate() {
super.onCreate();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenStateBroadcastReceiver, intentFilter);
}
#Override
public void onDestroy() {
unregisterReceiver(mScreenStateBroadcastReceiver);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
My AndroidManifest file is as follows :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.abbinvarghese.calculu">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<service android:name=".ScreenListenerService" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
To overcome the imposed limitations of 8.0 you could run a foreground service. Just like a service but a notification is posted to the foreground.
Then the service code would be like this (remember to unregister the receiver onDestory):
BroadcastReceiver screenReceiver;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startRunningInForeground();
detectingDeterminateOfServiceCall(intent.getExtras());
registerBroadcastReceivers();
return START_STICKY;
}
private void startRunningInForeground() {
//if more than or equal to 26
if (Build.VERSION.SDK_INT >= 26) {
//if more than 26
if(Build.VERSION.SDK_INT > 26){
String CHANNEL_ONE_ID = "sensor.example. geyerk1.inspect.screenservice";
String CHANNEL_ONE_NAME = "Screen service";
NotificationChannel notificationChannel = null;
notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (manager != null) {
manager.createNotificationChannel(notificationChannel);
}
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.background_running);
Notification notification = new Notification.Builder(getApplicationContext())
.setChannelId(CHANNEL_ONE_ID)
.setContentTitle("Recording data")
.setContentText("ActivityLog is logging data")
.setSmallIcon(R.drawable.background_running)
.setLargeIcon(icon)
.build();
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
startForeground(101, notification);
}
//if version 26
else{
startForeground(101, updateNotification());
}
}
//if less than version 26
else{
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Activity logger")
.setContentText("data recording on going")
.setSmallIcon(R.drawable.background_running)
.setOngoing(true).build();
startForeground(101, notification);
}
}
private Notification updateNotification() {
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
return new NotificationCompat.Builder(this)
.setContentTitle("Activity log")
.setTicker("Ticker")
.setContentText("recording of data is on going")
.setSmallIcon(R.drawable.activity_log_icon)
.setContentIntent(pendingIntent)
.setOngoing(true).build();
}
private void detectingDeterminateOfServiceCall(Bundle b) {
if(b != null){
Log.i("screenService", "bundle not null");
if(b.getBoolean("phone restarted")){
storeInternally("Phone restarted");
}
}else{
Log.i("screenService", " bundle equals null");
}
documentServiceStart();
}
private void documentServiceStart() {
Log.i("screenService", "started running");
}
private void registerBroadcastReceivers() {
screenReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
switch (Objects.requireNonNull(intent.getAction())){
case Intent.ACTION_SCREEN_ON:
//or do something else
storeInternally("Screen on");
break;
case Intent.ACTION_SCREEN_OFF:
//or do something else
storeInternally("Screen off");
break;
}
}
};
IntentFilter screenFilter = new IntentFilter();
screenFilter.addAction(Intent.ACTION_SCREEN_ON);
screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(screenReceiver, screenFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(screenReceiver);
}
and call it from the main activity:
private void startServiceRunning() {
if(!isMyServiceRunning(Background.class)){
if(Build.VERSION.SDK_INT >25){
startForegroundService(new Intent(this, Background.class));
}else{
startService(new Intent(this, Background.class));
}
}
}
As Background Execution Limit imposes on Android 8.0 (API level 26) so now it's not possible to listen SCREEN_OFF and SCREEN_ON action in background by running the service.
I have found a work around for same with the help of JobScheduler which works fine for listen broadcast in background without running any service.
Please check on this: Screen OFF/ON broadcast listener without service on Android Oreo
Instead of creating a new service for broadcast receiver, you can directly create a broadcast receiver class that will listen to system broadcasts even when the app is not running.
Create a new class which extends BroadcastReceiver.
public class YourReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Do your stuff
}
}
And register it in manifest.
<receiver
android:name=".YourReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_SCREEN_ON" />
<action android:name="android.intent.action. ACTION_SCREEN_OFF" />
<category android:name="android.intent.category.DEFAUL" />
</intent-filter>
</receiver>
Read about Manifest-declared receivers here.
Above solution won't work, here is the reason why. Problem is that your service is getting killed when the app is killed, so your receiver instance is removed from memory. Here is a little trick to re-start the service in background. Add the following code to your service.
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
Although this is not the right way to do it. Also in Android 26+ you won't be able to do this and you'd go for foreground service. https://developer.android.com/about/versions/oreo/background
I'm working on app which test state on server every 15 min and push notification , i used Alarm Manager , broadcast receiver & Intent Service .
every thing worked fine and i get this state from server perfectly when app is running or in background , until i removed it from recent apps, every thing stops and can't get that state from server.
I searched ... and get nothing , but my friend tell me that I must register my broadcast receiver in on create of class extend from application.
I don't know how to do this .. so I need help please
Main Activity Class
public class MainActivity extends AppCompatActivity {
static TextView TvText;
Button Btn11, Btn22;
AlarmManager alarm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
TvText = (TextView) findViewById(R.id.tv_Text);
Btn11 = (Button) findViewById(R.id.btn_11);
Btn22 = (Button) findViewById(R.id.btn_22);
Btn22.setEnabled(false);
}
public void Btn11OC(View view) {
scheduleAlarm();
Btn11.setEnabled(false);
Btn22.setEnabled(true);
}
public void Btn22OC(View view) {
if (alarm!= null) {
cancelAlarm();
}
Btn11.setEnabled(true);
Btn22.setEnabled(false);
}
// Setup a recurring alarm every half hour
public void scheduleAlarm() {
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(getApplicationContext(), broadtest.class);
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(this, broadtest.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every 5 seconds
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(),
900000L, pIntent);
}
public void cancelAlarm() {
Intent intent = new Intent(getApplicationContext(), broadtest.class);
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
final PendingIntent pIntent = PendingIntent.getBroadcast(this, broadtest.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarm.cancel(pIntent);
}
}
Broad Cast Receiver
public class broadtest extends WakefulBroadcastReceiver {
public static final int REQUEST_CODE = 12345;
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MyService.class);
context.startService(i);
}
}
AppController Class
public class AppController extends Application {
#Override
public void onCreate() {
super.onCreate();
}
}
MyService class
public class MyService extends IntentService {
static int NOTIFICATION_ID = 0;
public MyService() {
super("MyService");
}
#Override
protected void onHandleIntent(Intent intent) {
String url = "http://test.com/testts.php";
// Tag used to cancel the request
String tag_string_req = "string_req";
StringRequest strReq = new StringRequest(Request.Method.GET,
url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("Volley Log", response);
Toast.makeText(MyService.this, response, Toast.LENGTH_SHORT).show();
if (response.equals("0")){
sendNotification("Titel Test 1111", "Body Test 1111");
}else if (response.equals("1")){
sendNotification("Titel Test 2222", "Body Test 2222");
}else {
sendNotification("Titel Test 3333", "Body Test 3333");
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MyService.this, error.toString(), Toast.LENGTH_SHORT).show();
VolleyLog.d("Volley Log", "Error: " + error.getMessage());
}
});
// Adding request to request queue
int socketTimeout = 30000;//30 seconds - change to what you want
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
strReq.setRetryPolicy(policy);
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
// Setup periodic alarm every 5 seconds
}
private void sendNotification(String title, String messageBody) {
long[] pattern = {500,500,500,500,500,500,500,500,500};
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(alarmSound)
.setLights(Color.BLUE, 500, 500)
.setVibrate(pattern);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (NOTIFICATION_ID > 1073741824) {
NOTIFICATION_ID = 0;
}
notificationManager.notify(NOTIFICATION_ID++, notificationBuilder.build());
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.gih.testmass">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:name=".AppController"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".broadtest"
android:process=":remote">
</receiver>
<service
android:name=".MyService"
android:exported="false">
</service>
</application>
You need to start the service as a foreground service. When you clear app from recents it kills the service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.drawable.ic_notification)
.setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(),
R.mipmap.ic_launcher))
.setContentTitle("WhatsApp Reminder Service.")
.setContentText("Touch to configure.");
Intent startIntent = new Intent(getApplicationContext(), MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 965778, startIntent, 0);
builder.setContentIntent(pendingIntent);
startForeground(965778, builder.build());
return START_REDELIVER_INTENT;
}
It is necessary to build a notification when you use foreground service.
Hope it helps.
I see you have used IntentService
see answer to this question
Using startForeground() with an Intent Service
To run a process on a device when users are not particularly interacting with your application.
The steps will involve:
1.Updating your android manifest xml
2.Setting up broadcast receivers to listen to relevant events
3.Set up a background service for context when your application isn’t running
Android menifest.xml
<?xml version="1.0" encoding="utf-8"?>
<uses-permission ... />
<application
android:name=".MyApplication"
... >
<receiver android:name=".receivers.PeriodicTaskReceiver">
<intent-filter>
<action android:name="com.example.app.PERIODIC_TASK_HEART_BEAT" />
</intent-filter>
</receiver>
<service android:name=".services.BackgroundService" />
...
</application>
Now for the Broadcast receiver
public class PeriodicTaskReceiver extends BroadcastReceiver {
private static final String TAG = "PeriodicTaskReceiver";
private static final String INTENT_ACTION = "com.example.app.PERIODIC_TASK_HEART_BEAT";
#Override
public void onReceive(Context context, Intent intent) {
if (!Strings.isNullOrEmpty(intent.getAction())) {
MyApplication myApplication = (MyApplication) context.getApplicationContext();
SharedPreferences sharedPreferences = myApplication.getSharedPreferences();
if (intent.getAction().equals("android.intent.action.BATTERY_LOW")) {
sharedPreferences.edit().putBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, false).apply();
stopPeriodicTaskHeartBeat(context);
} else if (intent.getAction().equals("android.intent.action.BATTERY_OKAY")) {
sharedPreferences.edit().putBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, true).apply();
restartPeriodicTaskHeartBeat(context, myApplication);
} else if (intent.getAction().equals(INTENT_ACTION)) {
doPeriodicTask(context, myApplication);
}
}
}
private void doPeriodicTask(Context context, MyApplication myApplication) {
// Periodic task(s) go here ...
}
public void restartPeriodicTaskHeartBeat(Context context, MyApplication myApplication) {
SharedPreferences sharedPreferences = myApplication.getSharedPreferences();
boolean isBatteryOk = sharedPreferences.getBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, true);
Intent alarmIntent = new Intent(context, PeriodicTaskReceiver.class);
boolean isAlarmUp = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_NO_CREATE) != null;
if (isBatteryOk && !isAlarmUp) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmIntent.setAction(INTENT_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
}
}
public void stopPeriodicTaskHeartBeat(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(context, PeriodicTaskReceiver.class);
alarmIntent.setAction(INTENT_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
alarmManager.cancel(pendingIntent);
}
}
here com.example.app.PERIODIC_TASK_HEART_BEAT is application’s own broadcast, created and sent from our restartPeriodicTaskHeartBeat method.
your Alarmmanager should have this line
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
Now for your background service class:
public class BackgroundService extends Service {
private static final String TAG = "BackgroundService";
PeriodicTaskReceiver mPeriodicTaskReceiver = new PeriodicTaskReceiver();
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
MyApplication myApplication = (MyApplication) getApplicationContext();
SharedPreferences sharedPreferences = myApplication.getSharedPreferences();
IntentFilter batteryStatusIntentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatusIntent = registerReceiver(null, batteryStatusIntentFilter);
if (batteryStatusIntent != null) {
int level = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPercentage = level / (float) scale;
float lowBatteryPercentageLevel = 0.14f;
try {
int lowBatteryLevel = Resources.getSystem().getInteger(Resources.getSystem().getIdentifier("config_lowBatteryWarningLevel", "integer", "android"));
lowBatteryPercentageLevel = lowBatteryLevel / (float) scale;
} catch (Resources.NotFoundException e) {
Log.e(TAG, "Missing low battery threshold resource");
}
sharedPreferences.edit().putBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, batteryPercentage >= lowBatteryPercentageLevel).apply();
} else {
sharedPreferences.edit().putBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, true).apply();
}
mPeriodicTaskReceiver.restartPeriodicTaskHeartBeat(BackgroundService.this);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
startSelf();
}
}
Here the Backgroundservice tries to find the device’s low battery threshold and set our battery control flag appropriately before it attempts to restart the Broadcast receiver.
And START_STICKY will try to re-create your service after it is killed and call onStartCommand() again with a null intent.
Finally for your Application class start the Background service:
public class MyApplication extends Application {
private static final String TAG = "MyApplication";
#Override
public void onCreate() {
super.onCreate();
// Initialize the singletons so their instances
// are bound to the application process.
...
Intent startServiceIntent = new Intent(context, BackgroundService.class);
startService(startServiceIntent);
}
}
For detail implementation see this:https://technology.jana.com/2014/10/28/periodic-background-tasks-in-android/
be sure to make you service like this in your Mainifest
<service
android:name=".service.youservice"
android:exported="true"
android:process=":ServiceProcess" />
then your service will run on other process named ServiceProcess
if you want make your service never die :
onStartCommand() return START_STICKY
onDestroy() -> call startself
if nothing works use startForeground() service..
I have a BroadcastReceiver that starts my service, this service it uses async to make an HTTP request and then display a notification, but I'm not getting the service to be run every time the system starts automatically, and then every 1 minute.
Here is my AndroidManifest:
<receiver android:name=".notificar.InicializarServico" android:exported="false">
<intent-filter>
<action android:name="INICIALIZAR_SERVICO"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<service android:enabled="true" android:name=".notificar.ServicoNotificar">
<intent-filter>
<action android:name="SERVICO_ATUALIZAR"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
The code of BroadcastReceiver is here:
public class InicializarServico extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.v("NAMURA LANCHES", "O SISTEMA FOI INICIADO");
Log.v("NAMURA LANCHES", "Iniciando o serviço de atualização");
// Preparar Intent para inicializar o serviço
agendar(context, 5);
Log.v("NAMURA LANCHES", "O Serviço sera iniciado em 15 segundos");
}
private void agendar(Context context, int i) {
Intent myIntent = new Intent(context, ServicoNotificar.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, i); // first time
long frequency= i * 1000; // in ms
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), frequency, pendingIntent);
}
}
And here is my service class:
public class ServicoNotificar extends Service{
private String RequestURL = "http://sandbox.omeuprofissional.com/requests/meus_pedidos.php";
private final int duration = 3000;
private static final String ACTION_RESCHEDULE =
"br.com.namuralanches.android.intent.action.SERVICE_RESCHEDULE";
Handler myHandler;
#Override
public IBinder onBind(Intent intent) {
return null;
}
Thread testThread;
boolean threadRunning = false;
#Override
public void onCreate() {
super.onCreate();
myHandler = new Handler();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("NAMURA LANCHES", "Service started");
myHandler.postDelayed(new Runnable() {
#Override
public void run() {
SharedPreferences preferencias = getSharedPreferences("mesa", MODE_PRIVATE);
String registro = preferencias.getString("REGISTRO_MESA", null);
String hashMesa = preferencias.getString("HASH_MESA", null);
if ((registro != null) || (hashMesa != null)) {
new ListarCompras().execute(RequestURL, hashMesa, registro);
}
}
}, 10000);
stopSelf(startId);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
Log.v("NAMURA LANCHES", "SERVICO DESTRUIDO");
super.onDestroy();
threadRunning = false;
}
}
I made some changes now I'm lost, I'm not even see the log that the service was created, only the log BroadcastReceiver
You will have to use AlarmManager to start your service. To use AlarmManager, you need a pending Intent which you want the alarm to fire.
like so:
First, create a Receiver that will will be fired by an Intent,
in your activity, create the intent that fires the Receiver,
create a pending intent for the intent that fires the receiver, finally 4. use alarm manager to fire the pending intent.
Remember, your Receiver will fire your service via Intent when it receives content from your alarm manager. You can use the setRepeating method of alarmManager to set the repeat time.
Look at this stack overflow post for example How to start Service using Alarm Manager in Android?.
For details, checkout this link(Using with AlarmManager for Periodic Tasks)
https://guides.codepath.com/android/Starting-Background-Services
Hope this help.
What I am trying to do here is to raised a notification after a certain time by using BroadcastReceiver.With the following set of code i am able to achieve that also. But I want even the application is closed it will raised the notification.
MainActivity.java
public class MainActivity extends Activity {
IntentFilter ii;
TimeReciever tr;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ii=new IntentFilter("android.intent.action.TIME_TICK");
tr=new TimeReciever();
registerReceiver(tr, ii);
}
}
=================================
TimeReciever.java
public class TimeReciever extends BroadcastReceiver{
int a=0;
public void onReceive(Context ctx, Intent in) {
System.out.println("On reciever");
a+=a;
a++;
System.out.println("value of a="+a);
if(a==31){
Toast.makeText(ctx,"Reciver Executed ", 40).show();
showNotification(ctx);
}
}
private void showNotification(Context context) {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Log Reminder")
.setContentText("It's time to log the Breakfast !");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, MainActivity.class);
// 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);
mBuilder.setContentIntent(resultPendingIntent);
mBuilder.setDefaults(Notification.DEFAULT_SOUND);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(1, mBuilder.build());
a=0;
}
}
===============================
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.notificationbybroadcastre"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name="com.example.notificationbybroadcastre.TimeReciever">
<intent-filter>
<action android:name="android.intent.action.TIME_TICK"/>
</intent-filter>
</receiver>
<activity
android:name="com.example.notificationbybroadcastre.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Here The Answer.I have done It Through AlaramManager.
Main Activity
===============
public class MainActivity extends Activity
{
private PendingIntent pendingIntent;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent,0);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);
// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
1000 * 60 * 480, pendingIntent);
} //end onCreate
}
================================================================
MyAlarmService.java
================================
public class MyAlarmService extends Service
{
private NotificationManager mManager;
#Override
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate()
{
// TODO Auto-generated method stub
super.onCreate();
}
#SuppressWarnings("static-access")
#Override
public void onStart(Intent intent, int startId)
{
showNotification(this);
}
private void showNotification(Context context) {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Meal Log Reminder")
.setContentText("It's time to log Your Meal!");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, MainActivity.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(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);
mBuilder.setContentIntent(resultPendingIntent);
mBuilder.setDefaults(Notification.DEFAULT_ALL);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(1, mBuilder.build());
}
#Override
public void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
}
}
===================================================
MyReceiver.java
=========================
public class MyReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Intent service1 = new Intent(context, MyAlarmService.class);
context.startService(service1);
}
}