BroadcastReceiver (TIME_TICK) dies every night? - java

I want to write some kind of background-live-ticker app for sports-web-services...
I would like my app to be able to call the TIME_TICK all the time.
Btw: I also tried to use the AlarmManager, but the problem is the same.
But now my problem...
I use a Receiver with a Service for the execution part.
The Receiver is called every minute correctly after register.
But every night the service is terminated and will never be called again.
On Android 2.x everything works fine but Android 4.x will stop the Receiver every day...
Is there any posibility to keep the app alive on Android 4.x?
The Reveiver is registered in my Main-Activity:
registerReceiver(new MyReceiver(), new IntentFilter(Intent.ACTION_TIME_TICK));
Manifest-entries:
<service android:name="de.pepdev.MyService" />
<receiver android:name="de.pepdev.MyReceiver">
<intent-filter>
<action android:name="android.intent.action.TIME_TICK" />
</intent-filter>
</receiver>
Receiver-class:
public class MyReceiver extends BroadcastReceiver
{
public static long nextExecTime = 0;
public static Calendar currentTime = Calendar.getInstance();
#Override
public void onReceive(Context context, Intent intent)
{
currentTime = Calendar.getInstance();
if(nextExecTime <= currentTime.getTimeInMillis())
{
Intent service = new Intent(context, MyService.class);
context.startService(service);
}
}
}

I also tried to use the AlarmManager, but the problem is the same
AlarmManager is a far better answer than ACTION_TIME_TICK, particularly if you let the user configure the polling frequency (including an option for "never poll, please, as I like my battery and bandwidth usage to stay low").
Please feel free to ask a separate StackOverflow question regarding whatever problems you feel your are experiencing with it.
But every night the service is terminated and will never be called again
Android can and will terminate your process at any point, either by user request or due to old age.
Manifest-entries:
The <receiver> is pointless, as you cannot register for ACTION_TIME_TICK via the manifest.

Related

How to detect incoming and outgoing calls?

I am working on a client app. He want to give android cellphones to his employees. With our app already installed. In our app he wanted to get the record of every phone call.
I know how to do it, I made the BoradcastReceiver. But it is only working in the older version. New Version like Android Nougat and Pie has restriction on it. And I do not any working solution of catching call event.
So Here is what I am doing in my app that is working on older version.
<receiver android:name=".MyCallReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"></action>
</intent-filter>
</receiver>
public class MyCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"Call Event",Toast.LENGTH_LONG).show();
}
}
Solution I found:
So on older version I am watching this toast. but same code not
working on the new versions. I Have read that we need to declare same
broadcast in code.
So on above R&D I have some confusion
Confusion: When declaring in code, will it work even my app is not running at all?
Another Question:
Also we want to track the other calls? is it possible like call of
whatsapp and viber?
Please give me detail answer of what to do in case 1 and is it even possible to track calls of whatsapp and viber andother apps like this?

Keep a service running all the time even after a reboot

I have implelemented the START_STICKY command but the service is killed after a few hours. What I want to do is keep a service running always in the background and restart even when the device is rebooted. Can I restart the service in the onDestroy method like this? or is there a more convenient approach to it?
#Override
public void onDestroy() {
Stop();
Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
Intent i= new Intent(getApplicationContext(), MyService.class);
startService(i);
}
For ensuring that your service is running even after some hours of starting it, then you will have to use AlarmManager which will run recurringly for a specified periodicity even if the app is killed. What will you do is register a PendingIntent for the AlarmManager to fire which will be received by a BroadcastReceiver and in the BroadcastReceiver you will check that if your Service is running or not. If running, do nothing and if not then start the service.
What I want to do is keep a service running always in the background and restart even when the device is rebooted.
In order to do this you will have to give this permission in the manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
and then you will have to make a custom BroadcastReceiver which will check for an intent to be fired which is Action.BOOT_COMPLETED.
You should declare your BroadcastReceiver to catch the above mentioned intent in the Android Manifest like this:
<receiver android:name="com.example.MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Now either you can initialise your AlarmManager in BroadcastReceiver class or you can write the code to start the service straightaway.
Info on AlarmManager can be found here.
Disclaimer:
Starting from Android O, Google will stop supporting Unbound Background Service and calling startService() will become Illegal(Android will throw IllegalStateException) when calling this function.

Locations updates stay active when Android app is not longer active

I have the following problem: I send in regular interval GPS data from the mobile to a server. In fact I want this background service only running as long the user is willing to submit data. There should be some sort of confirmation dialog that from now on data are submitted and then these submissions should be active - event if the App is shutdown meanwhile - until the user again confirms that data should be no longer sended:
Here is my current entry in the AndroidManifest.xml:
....
<receiver
android:name="ch.bbcag.jumpin.app.receiver.gps.ConnectivityReceiver"
android:process=":gps_process" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
<receiver
android:name="ch.bbcag.jumpin.app.service.LocationUpdaterService"
android:process=":gps_process" />
<service
android:name="ch.bbcag.jumpin.app.service.LocationUpdaterService"
android:process=":gps_process" />
....
GcmIntentService.java:
public class ConnectivityReceiver extends BroadcastReceiver {
private static final int EXEC_INTERVAL = AppConstants.GPS_REPEAT_SECONDS * 1000;
private final static String TAG = "ch.bbcag.jumpin.app.receiver.gps.ConnectivityReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received event");
final AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
final PendingIntent wakeupIntent = PendingIntent.getService(context, 0,
new Intent(context, LocationUpdaterService.class),
PendingIntent.FLAG_UPDATE_CURRENT);
final boolean hasNetwork = !intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (hasNetwork) {
context.startService(new Intent(context,LocationUpdaterService.class));
Calendar now = Calendar.getInstance();
now.add(Calendar.SECOND, AppConstants.GPS_REPEAT_SECONDS);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, now.getTimeInMillis(), EXEC_INTERVAL, wakeupIntent);
} else {
alarmManager.cancel(wakeupIntent);
}
}
}
The problem with this approach is that event the user is not using the App events are sent to the server. A simple solution would be in the class LocationUpdaterService to check in preferences if app should really send events. But the fact stays that LocationsUpdaterService is called regularly even if I don't use it (and Android wastes time to call this service).
How I can figure this out? Articles? Code examples are welcome!
How I can figure this out?
Only schedule your alarms when you need them. If you no longer need them, cancel the alarms.
Also, if you are going to use RTC_WAKEUP, either use WakefulBroadcastReceiver or my WakefulIntentService, otherwise your alarms will not be reliable.
Also also, your manifest is malformed. Either ch.bbcag.jumpin.app.service.LocationUpdaterService is a <receiver> or it is a <service>, but it cannot be both.
And also also also, dump the android:process=":gps_process" unless you have a clear understanding of why you are using it and its costs to you and the users.
I just have to read the documentation from Google to get aware how things are really working:
1) I don't want to start the Alarm when the device boots:
Solution:
(AndroidManifest.xml)
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name=".SampleBootReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
Notice that in the manifest, the boot receiver is set to
android:enabled="false"
This means that the receiver will not be called unless the application explicitly enables it. This prevents the boot receiver from being called unnecessarily. Once you have started the your App you can:
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
From this point on the GPS locations are send in regular intervals to the server. Once you have done this, the next time the receiver will start on boot up. This is what i want to prevent.
2) Prevent automatically starting BootReceiver from boot:
For this purpose I'm looking for a possibility to get the shutdown event of the Android system:
<uses-permission android:name="android.permission.DEVICE_POWER" />
<receiver android:name=".ShutdownReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
</intent-filter>
</receiver>
public class ShutdownReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);
}
}
This has the effect that next time the mobile boots it will not start automatically the SampleBootReceiver until you explicitly specify this with the code:
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
3) Conclusions:
a) Once your App is started the Receiver is activated: GPS coordinates go in regular intervals to the server
b) In your App you can make a setting to terminated the receiver or to enable it.
c) Finally if the handy shut down it's time to remove the receiver.
d) The next time you can restart with a)

Service crashing and restarting

There are several questions about it but I always read the same thing: "the service will be killed if the system need resources" or "you can't build an service that runs forever because the more it runs in background, more susceptible it is to the system kills it" and etc.
The problem I'm facing is: My service runs fine and as it is expected, if I run my app then exit it my service is still running, but when I kill my app (by going to the "recent apps" and swype it away) the service stops. In this moment, if I go to the Settings >> aplications >> running I'll see that the service is restarting. After a while, it goes back and my Service run with no problem.
I google it and I find some things I could do but lets see my code first:
I start my service by this way (after a button click):
Intent intent = new Intent (MainActivity.this, MyService.class);
startService(intent);
I also have 3 Integers I put in extra, so I have something like this:
final Integer i, i2, i3;
i = 5; //for example
i2 = 10; //for example
i3 = 15; //for example
final Intent intent = new Intent (MainActivity.this, MyService.class);
intent.putExtra("INTEGER1", i);
intent.putExtra("INTEGER2", i2);
intent.putExtra("INTEGER3", i3);
startService(intent);
In MyService I have the folloywing:
public class MyService extends Service
{
AlarmManager am;
BroadcastReceiver br;
PendingIntent pi;
Integer i, i2, i3;
#Override
public void onCreate()
{
super.onCreate();
am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
pi = PendingIntent.getBroadcast(this, 0, new Intent("anyany"); 0) //Why those zeros?
br = new BroadcastReceiver ()
{
public void onReceive (Context context, Intent i) {
new thread(new Runnable()
{
public void run()
{
//do something
}
}).start();
}
};
}
#Override
public void onStartCommand(Intent intent, int flags, int startId)
{
super.onStartCommand(intent, flags, startId);
try
{
i = intent.getIntExtra("INTENT1", 0) // I don't understant yet why this zero are here
i2 = intent.getIntExtra("INTENT2", 0)
i3 = intent.getIntExtra("INTENT3", 0);
}
catch(NullPointerException e) {}
this.registerReceiver(br, new IntentFilter("anyany"));
new thread(new Runnable()
{
public void run()
{
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock. elapsedRealtime() + i*1000, i2*1000, pi);
}
}).start();
return START_REDELIVER_INTENT; //so I can get my Extra even with my Activity closed
}
My onDestroy:
#Override
public void onDestroy()
{
unregisterReceiver(br);
super.onDestroy();
}
I also have onBind() method (without #Override), but it returns null.
I google a lot and I tried to run the service in foreground, so I did this (inside de onStartCommand):
Notification n = new Notification(R.drawable.ic_laucher), getText(R.string.app_name), System.currentTimeMillis());
PendingIntent npi = PendingIntent.getActivity(this, MainActivity.class);
n.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), npi);
startForeground(3563, n);
My notification appears and when I click on it my app runs, but the problem with my service wasn't fixed (I believe it still not run on foreground). The notification is restarted too.
I also deleted the Try catch and I define a value for the integers (so I didn't use the getIntExtra() method), but nothing changed
After several tests I tried to see the logs, when I kill my App I have the following message: Scheduling restart of crashed service.
So, for some reason my service crash when my MainActivity dies, why? The intention here is not to transform the service in a god that can not be killed (I don't think it is impossible at all, the WhatsApp are running for 105 hours !) but prevent my Service to not being crashed after my App dies.
I don't know if this'll help but this is what I add on my Manifest.xml
<Activity android:name = ".MyService"/>
<service android:name ="Myservice" android:enabled="true" android: exported="false"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
Min API = 9, target API = 17.
Size of the Service when running: about 3MB.
Hope I was clear and sorry for my English.
PS: the entire code are running as expected, so if you see any sintax error fell free to edit it.
EDIT
If I add android:isolatedProcess="true" in the <service> in AndroidManifest.xml I receive this error in logCat: java.lang.RuntimeException: Unable to create a service in com.mycompany.myapp.myservice: java.lang.SecurityException: Isolated process not allow ed to call getIntentSender
When I start my service using this, the MainActivity does not show any erros, only the service crashes.
I finally found the solution ! I removed the AlarmManager from the Service and the service does not cashed anymore, but I have to use it
The problem is the service crash after the user swype away the app from Recent App, so what I did was prevent the app to appear in that window. Add the following to your AndroidManifest.xml as a child of <activity>
android:excludeFromRecents="true"
Now when the user exit from your app it wil not appear in the recent apps window, what means the system kills the Activity right after you exit it, so it'll not waste any resources.
PS: don't forget to set the service to run in a separate process, add the following to your AndroidManifest.xml, as a child of <service>
android:process=":remote"
EDIT - REAL SOLUTION FOUND
After a lot of research and study (months of study) I took a deep look at android APIs and here is what a found, this is na expected behaviour that occours only at API 16+, a change at android arquiteture changed the way that PendingIntents are broadcasted by the system, so Google added the flag FLAG_RECEIVER_FOREGROUND, you must pass this flag to the intent you are using as a parameter on the PendingIntent.getBroadcast(), here is na example:
if(Build.VERSION.SDK_INT >= 16) //The flag we used here was only added at API 16
myIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
//use myIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); if you want to add more than one flag to this intent;
PendingIntent pi = PendingIntent.getBroadcast(context, 1, myIntent, 0); // the requestCode must be different from 0, in this case I used 1;
Android versions older than API 16 will work as expected, the service won't crash if you swype away the app from Recent Apps page.
As the documentation says, a Service runs in the main thread of its callee, that usually is the UI Thread. So what is happening is that when you kill your application, you kill your application process and thus the service is killed too.
You can workaround this behavior by creating your Service in a different process by using android:process in your <service> tag in the Manifest.xml file.
Usually, though, you start a Service in its own process if the Service needs to be independent from the callee and if it may be used by different application. If your Service is for your own application use only, then stick with the default behavior and simply don't kill you application.
EDIT 1:
The documentation for android:isolatedProcess says:
If set to true, this service will run under a special process that is
isolated from the rest of the system and has no permissions of its
own. The only communication with it is through the Service API
(binding and starting).
From another SO answer (Link), this is the expected behavior. But surely, someone here will have a workaround or a solution.
Your questions from code:
pi = PendingIntent.getBroadcast(this, 0, new Intent("anyany"); 0)
//Why those zeros?
The first zero you see is mentioned as a requesCode and decribed as not being used presently:
requestCode: Private request code for the sender (currently not used).
The second zero should actually be one of the flags given (here).
i = intent.getIntExtra("INTENT1", 0) // I don't understant yet why
this zero are here
The getIntExtra(String, int) method of Intent doesn't need to have 0 as its second argument: it can be any integer. getIntExtra(String, int) returns an integer corresponding to the String key you provide. In the event that this key no long exists(or never did), getIntExtra(String, int) returns the integer we pass as the second argument. It is the default value when the key fails.

Broadcast Receiver on Nexus 7

I am trying to write a service that runs on phone boot, and must read data off the SD card. At first I was using a reciever for android.intent.action.BOOT_COMPLETED but switched to the intent below to make sure that the SD card has been loaded.
My Issue is that on a my Nexus 7, it doesn't appear to receive the MEDIA_MOUNTED intent. The Nexus 7 doesn't have an SD card (but it has separate SD card partition). I also tried the BOOT_COMPLETED intent, with the same luck. I have tested the same code on the emulator and my Thunderbolt, and both intents work.
Manifiest:
<receiver
android:name=".StartupReceiver"
android:enabled="true"
android:exported="true"
android:label="Start the NFS Automounter Service">
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED"></action>
<data android:scheme="file"/>
<!-- <action android:name="android.intent.action.BOOT_COMPLETED"></action>-->
</intent-filter>
</receiver>
The BroadcastReceiver class:
public class StartupReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
//if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction()))
//if ("android.intent.action.MEDIA_MOUNTED".equals(intent.getAction()))
//{
Log.d("NFS_Automounter", "Recieved Mount");
Intent serviceIntent = new Intent("com.ancantus.nfsautomounter.AutomountService");
context.startService(serviceIntent);
//}
}
}
I commented out the intent matching just to try and log if the class is executed at all.
My only hunch is that the Nexus 7 doesn't broadcast a MEDIA_MOUNTED because it doesn't have a real SD card; but I can't receive the BOOT_COMPLETED intent either.
And to forstall the question; yes I do have the BOOT_COMPLETED permission.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
How many times must I type in this answer before it starts coming up in enough search results that people will find it? Maybe boldface caps will work:
STARTING WITH ANDROID 3.1, NO BroadcastReceiver WILL WORK, AT ALL, UNTIL SOMETHING HAS MANUALLY RUN ONE OF THE APPLICATION'S OTHER COMPONENTS, SUCH AS A USER RUNNING AN ACTIVITY.
This is in the documentation (albeit not well located), in blog posts, and in many StackOverflow answers, such as:
https://stackoverflow.com/a/9084771/115145
https://stackoverflow.com/a/11865858/115145
https://stackoverflow.com/a/11744499/115145
So, add an activity to your app. You need some activities anyway, for settings to control your background operation, for your documentation, for your license agreement, for your privacy policy, etc.
(note: I'm not really yelling at you -- I am just frustrated that this keeps coming up despite efforts to get the word out...)
Please note that many Android devices emulate SD card in the way it does not affect access to the SD card even when desktop accesses it. Therefore it may be that Nexus 7 simply exposes all memory that way, so as it does not really mount anything, it'd not broadcast MEDIA_MOUNTED. If you want to do some tasks on boot, listening to BOOT_COMPLETED is the only correct approach.

Categories

Resources