Android : Run service when my app is not in use - android

In my application I'am using BroadcastReceiver to track telephone state.
There are 3 states available in TelephonyManager.
EXTRA_STATE_IDLE
EXTRA_STATE_OFFHOOK
EXTRA_STATE_RINGING
In my scenario I want to show simple ui which shows some details about the caller while the phone is ringing and i want to close that ui when the call attended by user or call ended.
I'am calling my service when the phone state is Ringing. If my app is in use then I can see my ui part while the phone is ringing. If my app is not in use then I cant see the ui part.
I have checked in my background. The service is not running. I think my service is running only when my app is in use and it is not running when my app is not in use.
To overcome this what I should do?
This is my code.
#Override
public void onReceive(Context context, Intent intent) {
LoginActivity.login.finish();
MainActivity.main.finish();
telephonyRegister(context,intent);
}
public void telephonyRegister(final Context context, Intent intent)
{
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String imeiSIM1= telephony.getDeviceId();
System.out.println("IMEI NUMBER"+imeiSIM1);
ctx=context;
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_IDLE)) {
try
{
ProjectDailogActivity.projdialog.finish();
}catch(Exception e)
{
e.printStackTrace();
}
}
else if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_OFFHOOK))
{
try{
ProjectDailogActivity.projdialog.finish();
}catch(Exception e)
{
e.printStackTrace();
}
}
else if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_RINGING)){
phoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
isringing=true;
Intent intent11 = new Intent(ctx,ProjectDailogActivity.class);
intent11.putExtra("incoming_number",phoneNumber);
intent11.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent11);
}
}
Manifest.xml
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<receiver android:name="com.domyhome.broadcastreceiver.IncomingCallInterceptor" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
I got the window like truecaller.
Just the values which i mentioned are default one.
But the same window is not coming when my app is not in use.
Please give me an idea.

that is why android developers invented the BroadcastReciever - it allows you to hook your code as a service in response for system events (such as boot, airplane mode, etc)
Vogella covers it very well: http://www.vogella.com/tutorials/AndroidBroadcastReceiver/article.html
and for your situation (send commands as a response for the phone state) you can also use this article which provide a fully working example: http://androidexample.com/Incomming_Phone_Call_Broadcast_Receiver__-_Android_Example/index.php?view=article_discription&aid=61&aaid=86
article hightlights:
<!-- Manifest.xml -->
<receiver android:name=".IncomingCall">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
and in java - add these classes
//your Listener class:
private class MyPhoneStateListener extends PhoneStateListener
{
public void onCallStateChanged(int state, String incomingNumber)
{
// state = 1 means when phone is ringing
if (state == 1)
{
// do something
}
}
}
//Reciever class:
public class IncomingCall extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent)
{
// TELEPHONY MANAGER class object to register one listner
TelephonyManager tmgr = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
//Create Listner
MyPhoneStateListener PhoneListener = new MyPhoneStateListener();
// Register listener for LISTEN_CALL_STATE
tmgr.listen(PhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}
}

No need to run it in a service just in the xml of your application in the reciever section use with phone ringing action and in your recieve implement your UI. and have a different reciever for your app to listen to when the phone is cut.

#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.e("onStartCommand", "onStartCommand");
return Service.START_STICKY;
}
http://developer.android.com/reference/android/app/Service.html

Use AlarmManager to activate service after a specific time and stop service and also kill AlarmManager when call came.

try like this,
AlarmManager am = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
intent.putExtra(ONE_TIME, Boolean.FALSE);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 5 , pi);
it will repeating while you manually not stopped it...may this helps you...

Related

BroadcastReceiver on Android P

Since Android 9 is online and I am having a troubles to send a notification with my JobIntentService, which launched using the BroadcastReceiver .
It works great on other devices with Android <= 8.1 and I can get the notification in no time .
Sometimes It works on Android P too, but sometimes the System doesn't fire the registered services with the AlarmManager ! OR I am not able to receive it.
What is going wrong ?
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
private static final String TAG = "AlarmReceiver";
#Override
public void onReceive(Context context, Intent intent) {
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
onBoot(context);
}
Log.d("action", "i recieved an action");
try {
Bundle bundle = intent.getExtras();
String message = bundle.getString("Push_Message", "No Content");
int type = bundle.getInt("Push_Type", -1);
Intent newIntent = new Intent(context, AppJobService.class);
newIntent.putExtra("Push_Message", message);
newIntent.putExtra("Push_Type", type);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
AppJobService.enqueueWork(context, AppJobService.class, AppJobService.JOB_ID, newIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
permissions in AndroidManifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
Here I've added the Receiver to the AndroidManifest.xml
<receiver
android:name=".notifications.AlarmReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
And I am registering the Service with the AlarmManager in this way inside a class, that inherits from JobIntentService
AppJobService.java
public void sendTimedNotification(String message, int type, long timeInMillis) {
Intent intent = new Intent(this, AlarmReceiver.class);
intent.putExtra("Push_Message", message);
intent.putExtra("Push_Type", type);
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timeInMillis);
PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, timeInMillis, sender);
}
As Per Document:
Alarms do not fire when the device is idle in Doze mode. Any scheduled
alarms will be deferred until the device exits Doze. If you need to
ensure that your work completes even when the device is idle there are
several options available. You can use setAndAllowWhileIdle() or
setExactAndAllowWhileIdle() to guarantee that the alarms will execute.
Another option is to use the new WorkManager API, which is built to
perform background work either once or periodically. For more
information, see Schedule tasks with WorkManager.
Take a look at https://developer.android.com/training/scheduling/alarms

AlarmManager Stops after removing app from recents apps

I am new to this part of android, and here I aim to use alarm manager to run a code snippet every 2 minute which will poll a server (using the website's api) and based on the returned JSON generate notification.
After a looking up the web I thought one of the best option in my case will be using intent service and android.
Manifest of Services and Recievers
<service
android:name=".NotifyService"
android:enabled="true"
android:exported="false" >
</service>
<receiver
android:name=".TheReceiver"
android:enabled="true"
android:exported="true" >
</receiver>
<receiver
android:name=".OnOffReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Part in the flash screen activity where I call the intent service which is responsible for polling for notification:
Intent msgIntent = new Intent(this, NotifyService.class);
startService(msgIntent);
The receiver to start the alarm on device start:
public class OnOffReceiver extends BroadcastReceiver
{
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
public OnOffReceiver(){}
#Override
public void onReceive(Context context, Intent intent)
{
Intent service = new Intent(context, NotifyService.class);
service.setAction(NotifyService.CREATE);
context.startService(service);
}
}
The IntentService Class
public class NotifyService extends IntentService
{
public NotifyService()
{
super("NotifyService");
}
public static final int STATUS_RUNNING = 0;
public static final int STATUS_FINISHED = 1;
public static final int STATUS_ERROR = 2;
#Override
protected void onHandleIntent(Intent intent)
{
if (intent != null)
{
final String action = intent.getAction();
}
StartStuff();
}
public void StartStuff()
{
Intent intent = new Intent(this, TheReceiver.class);
PendingIntent pend_intent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,1200,1200, pend_intent);
//1200ms to make it easier to test
}
}
The receiver class which sets notification, for testing pupose I am not doing any network related work here just making a simple notification to check if the app is running in all situations
public class TheReceiver extends BroadcastReceiver
{
public TheReceiver(){}
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, " Success ", Toast.LENGTH_SHORT).show();
Log.d("Notification", "The Receiver Successful");
showNotification(context);
}
private void showNotification(Context context)
{
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context).setContentTitle("My notification").setContentText("Hello World!");
mBuilder.setDefaults(Notification.DEFAULT_SOUND);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
}
}
However the notification come only when the app is running or in the recent apps tray.
It does not start notifying when the phone reboots, nor does it notify after the app is removes from the recent apps tray.
The app needs Notify users like other apps (like gmail, whatsapp) do, even if they are swiped out of the recent apps tray.
Timeliness and punctuality are not very big issue as delay up to 5 to 10 minutes are tolerable. (I intend to poll ever 2 minutes though.)
Where am I going wrong? Also, is there a better way to go about the problem?
To keep a receiver active after closing the app is to use
android:process=":remote"
in the manifest file for the receiver that needs to be kept alive.
<receiver
android:name=".TheAlarmReceiver"
android:process=":remote">
</receiver>
in the manifest for the receiver (TheReceiver in this case) that we need to keep active after the app closes.
P.S. : I also changed the way I use IntentsService and AlarmManager for the application, as my previous(above) implementation is not a very good way to go around it.
If an App is killed from recent apps or from "force stop" it won't restart by itself. The user has to start the app again in order to make it run again. There is no way to prevent this. It's just the way android works.
However there is a way to make your app run oon boot. Check out this link.

Need code example on how to run an Android service forever in the background even when device sleeping, like Whatsapp?

I have tried various ways to achieve this, but my service eventually gets killed.
I want to use AlarmManager to trigger a class every one hour. Even if the device is sleeping, it should sent a flashing LED alert, vibration or sound. In any case, it should run forever.
I have noticed that Whatsapp is always running, even though I kill all the running apps and clear the memory, put the device to sleep, and still Whatsapp receive messages and alerts me. How are they doing it? I want to do the same with my app.
NOTE: NOW THIS ANSWER IS ONLY VALID FOR ANDROID 7 AND BELOW. SINCE ANDROID 8 GOOGLE HAS CHANGED HOW BACKGROUND TASKS ARE HANDLED
Since I posted this question, I have implemented two different approaches to this solution into multiple apps.
APPROACH 1
This extract is from an app where I use push notifications, which need instant wake up calls for the device. Here what I do is
use WAKE_LOCK permission and
use a Wakelocker abstract class
use it in an Activity as needed:
Manifest:
<uses-permission android:name="android.permission.WAKE_LOCK" />
WakeLocker class:
public abstract class WakeLocker {
private static PowerManager.WakeLock wakeLock;
public static void acquire(Context context) {
if (wakeLock != null) wakeLock.release();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, "WakeLock");
wakeLock.acquire();
}
public static void release() {
if (wakeLock != null) wakeLock.release(); wakeLock = null;
}
}
Activity class example:
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Waking up mobile if it is sleeping
WakeLocker.acquire(getApplicationContext());
// do something
WakeLocker.release();
}
APPROACH 2
Best when you want to give Android control over wake up, and can live with periodically waking up your code. Simply use an AlarmManager to invoke a Service class at regular intervals. Here is some code from my LifeLog24 app:
MainActivity
Intent ll24 = new Intent(context, AlarmReceiverLifeLog.class);
PendingIntent recurringLl24 = PendingIntent.getBroadcast(context, 0, ll24, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarms.setRepeating(AlarmManager.RTC_WAKEUP, first_log.getTime(), AlarmManager.INTERVAL_HOUR, recurringLl24); // Log repetition
Alarm Class
public class AlarmReceiverLifeLog extends BroadcastReceiver {
private static final String TAG = "LL24";
static Context context;
#Override
public void onReceive(Context context, Intent intent) {
Log.v(TAG, "Alarm for LifeLog...");
Intent ll24Service = new Intent(context, LifeLogService.class);
context.startService(ll24Service);
}
}
and LifeLogService.class is where I do my stuff. Alarm wakes up every hour in this case and triggers the BroadcastReceiver which in return runs the service. There is more to it, to make sure service is not run twice and so on, but you get the point how it is done. And AlarmManager is actually the best way to do it since you don't worry about battery usage, etc. and Android takes care of waking up your Service at regular intervals.
It is very simple.
steps:
1.create a Service class.
2.create a BroadcastReceiver class
3.call BroadReceiver in onDestroy method of service
4.In onReceive method of BroadReceiver class start service once again.
Here's the code
Manifest file:`
<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=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".utilities.NotificationService"
android:enabled="true">
</service>
<receiver
android:name=".utilities.RestartService"
android:enabled="true"
android:exported="true"
android:label="RestartServiceWhenStopped"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="RestartService" />
</intent-filter>
</receiver>
</application>
`
Service class
public class NotificationService extends Service {
public NotificationService() {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Intent restartService = new Intent("RestartService");
sendBroadcast(restartService);
}
}
BroadcastReceiver class
public class RestartService extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context,NotificationService.class));
}
}
Follow these easy steps to keep servce alive forever in android device.
1. Call a service by using alarm manager.
2. return START_STICKY in onStart method.
3. In on destroy call the alarm manager and restart service by using startService method.
4.(Optional)Repeat the point number 3 in onTaskRemoved method.
Request partial WakeLock.
<uses-permission android:name="android.permission.WAKE_LOCK" />
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "My Tag");
mWakeLock.acquire();
onStartCommand retrun START_STICKY :
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
You can use a function startForeground(int, Notification) see here and here
A started service can use the startForeground(int, Notification) API
to put the service in a foreground state, where the system considers
it to be something the user is actively aware of and thus not a
candidate for killing when low on memory. (It is still theoretically
possible for the service to be killed under extreme memory pressure
from the current foreground application, but in practice this should
not be a concern.)

AlarmManager in background

I have a list of alarms, I put the first and when it sounds the alarm I put the next....
This's works.
But if the application is in background enough time, the alarms don't work.
I put in the manifest:
<receiver android:name=".Alertas_Broadcast" >
<intent-filter>
<action android:name="com.pack.pack.Alertas" />
<category android:name="com.pack.pack" />
</intent-filter>
</receiver>
And the broadcast and the function that put the new alarm:
public class Alertas_Broadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String mensaje = "";
if (extras != null)
mensaje = extras.getString("mensaje");
if (!mensaje.equals("")){
Utilidades.generateNotification(context, mensaje, Main.class, null);
// I put the next alarm calling setNextAlarm with the new parameters
}
}
}
public void setNextAlarm (long milisegundos, String mensaje){
Bundle extras = new Bundle();
extras.putString("mensaje", mensaje);
Intent i = new Intent("com.pack.pack.Alertas");
i.putExtras(extras);
PendingIntent pintent = PendingIntent.getBroadcast(InfoApp.miContexto, (int) milisegundos, i, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager)InfoApp.miContexto.getSystemService(Context.ALARM_SERVICE);
if (milisegundos != 0){
alarm.setRepeating(AlarmManager.RTC_WAKEUP, milisegundos, 99999999, pintent);
}
else{
alarm.cancel(pintent);
}
}
Where is the problem? I imagine the problem is the action of the receiver, but I don't know how resolve it.
I read that is not a good idea to have a service listening all the time beacause many resources are spent.
Sorry for my english and thank you!
If your Activity has been in the background long enough it may have been killed by the system. You can try using a Service and setForeground() to achieve your goal.
How are you setting the next alarm? If you are doing it through a service, you need to acquire a wakelock.
When the phone is in a sleep state and you receive an alarm, the phone will only stay awake while the BroadcastReceiver is in the onReceive() method, after which it falls asleep again. So there is no guarantee that your "setNextAlarm" is called.

How to disconnect a outgoing call programatically

I've used the following code to disconnect a call programatically but It's not working.
private void callDisconnect(){
try{
TelephonyManager manager = (TelephonyManager)this.getSystemService(this.TELEPHONY_SERVICE);
Class c = Class.forName(manager.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
ITelephony telephony = (ITelephony)m.invoke(manager);
telephony.endcall();
} catch(Exception e){
Log.d("",e.getMessage());
}
}
Can anybody help me with this?? Do I need to change the code or something...??
For disconnecting a call programmatically you must add ITelephony.AIDL file in your project. If you have added it, then your package name must be com/android/internal/telephony/ITelephony.AIDL: for more information see Blocking Incoming call. Download the AIDL file from here.
To disconnect a call use endCall(); method of ITelephony
Simply use this broadcastreceiver. I tested it in one of my application and it works perfectly.
public class MyBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, final Intent intent)
{
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL))
{
String phoneNumber = intent.getExtras().getString(Intent.EXTRA_PHONE_NUMBER);
if (phoneNumber.equals("123456"))
{
if (getResultData() != null)
{
setResultData(null);
}
}
}
}
}
It is not possible anymore in newer versions of android. The user decides when to end the call if it has already started. You can however block calls from happening.
You can block the outgoing call using the setResultData(null) function in the onReceive method of the Broadcast receiver.
public class BlockOutgoing extends BroadcastReceiver
{
String number;
#Override
public void onReceive(Context context, Intent intent)
{
Log.d("12280", "asdasNumber is-->> " + number);
number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
setResultData(null);
Toast.makeText(context, "Outgoing Call Blocked" , 5000).show();
}
}
<receiver
android:name=".BlockOutgoing"
android:label="#string/app_name" >
<intent-filter android:priority="1">
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
You cannot end a call like that in android 2.3+... using your code... I think only user can end his call...and for earlier versions You can see this link and This one

Categories

Resources