I'm trying to use an unstoppable background service so that I can get call detail for the new call in the alert dialog every time and notify the user with an alert dialog. The problem is that service is stopped after close app. I'm not entirely sure what I have wrong.
I've tested on my phone it's working fine even after closing the app
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jenya1.didbizdialer">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_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.NoActionBar">
<activity android:name=".activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".activity.DialerActivity"></activity>
<service android:name=".service.PhoneCallStatesService"
android:stopWithTask="false" />
<receiver android:name=".service.ReceiverCall">
<intent-filter>
<action android:name="com.android.techtrainner" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
The BootReceiver should start the Service
public class ReceiverCall extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("Service Stops", "Ohhhhhhh");
context.startService(new Intent(context, PhoneCallStatesService.class));;
}
}
The service PhoneCallStatesService is set to display a call details dialog
public class PhoneCallStatesService extends Service {
private static final String TAG = PhoneCallStatesService.class.getSimpleName();
private TelephonyManager telephonyManager;
private PhoneStateListener listener;
private boolean isOnCall;
private static boolean isIncoming;
private static int lastState = TelephonyManager.CALL_STATE_IDLE;
private static Date callStartTime;
private static String savedNumber; //because the passed incoming is only valid in ringing
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
showToast("service started");
isOnCall = false;
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
}
protected BroadcastReceiver stopReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "received stop broadcast");
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
listener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if(lastState == state){
//No change, debounce extras
return;
}
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
if(lastState == TelephonyManager.CALL_STATE_RINGING){
//Ring but no pickup- a miss
onMissedCall(getApplicationContext(), savedNumber, callStartTime);
}
else if(isIncoming){
onIncomingCallEnded(getApplicationContext(), savedNumber, callStartTime, new Date());
}
else{
onOutgoingCallEnded(getApplicationContext(), savedNumber, callStartTime, new Date());
}
if (isOnCall) {
showToast("Call state: idle");
isOnCall = false;
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(lastState != TelephonyManager.CALL_STATE_RINGING){
isIncoming = false;
callStartTime = new Date();
showToast("Outgoing start ");
onOutgoingCallStarted(getApplicationContext(), savedNumber, callStartTime);
}
else
{
isIncoming = true;
callStartTime = new Date();
showToast("Incoming answered ");
onIncomingCallAnswered(getApplicationContext(), savedNumber, callStartTime);
}
isOnCall = true;
break;
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
callStartTime = new Date();
savedNumber = incomingNumber;
onIncomingCallReceived(getApplicationContext(), incomingNumber, callStartTime);
showToast("call state: ringing");
break;
}
lastState = state;
}
};
// Register the listener with the telephony manager
telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
return START_STICKY;
}
protected void onIncomingCallReceived(Context ctx, String number, Date start)
{
Toast.makeText(ctx, "received", Toast.LENGTH_SHORT).show();
Log.e("received","received");
}
protected void onIncomingCallAnswered(Context ctx, String number, Date start)
{
Toast.makeText(ctx, "upadyo", Toast.LENGTH_SHORT).show();
Log.e("upadyo","upadyo");
}
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end)
{
Toast.makeText(ctx, "incoming call end", Toast.LENGTH_SHORT).show();
Log.e("incoming call end","incoming call end");
startactivity(ctx);
}
protected void onOutgoingCallStarted(Context ctx, String number, Date start)
{
Toast.makeText(ctx, "outcall call start", Toast.LENGTH_SHORT).show();
Log.e("outcall call start","outcall call start");
}
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end)
{
Toast.makeText(ctx, "Outgoing call end", Toast.LENGTH_SHORT).show();
Log.e("Outgoing call end","Outgoing call end");
startactivity(ctx);
}
protected void onMissedCall(Context ctx, String number, Date start)
{
Toast.makeText(ctx, "missed call", Toast.LENGTH_SHORT).show();
Log.e("missed call","missed call");
startactivity(ctx);
}
private void showToast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
public void startactivity(final Context ctx) {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ctx, R.style.myDialog);
LayoutInflater inflater = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View dialogView = inflater.inflate(R.layout.popupdialog, null);
dialogBuilder.setView(dialogView);
LinearLayout reminder=(LinearLayout)dialogView.findViewById(R.id.lnreminder);
LinearLayout savecontact=(LinearLayout)dialogView.findViewById(R.id.lnsavecontact);
LinearLayout contactblock=(LinearLayout)dialogView.findViewById(R.id.lnspam);
AlertDialog alertDialog = dialogBuilder.create();
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(alertDialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.BOTTOM;
lp.windowAnimations = R.style.DialogAnimation;
alertDialog.getWindow().setAttributes(lp);
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alertDialog.show();
reminder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(ctx, "reminder", Toast.LENGTH_SHORT).show();
}
});
savecontact.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(ctx, "Saved", Toast.LENGTH_SHORT).show();
}
});
contactblock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(ctx, "block", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onDestroy() {
try{
if(stopReceiver!=null)
unregisterReceiver(stopReceiver);
stopSelf();
}catch(Exception e)
{
Log.e("Service Destroy Error",e.getMessage());
}
}
}
Any help or example would be highly appreciated
In Redmi devices, the service gets killed after you close the app although you have written all the code to restart it after killing the app. You need to enable Autostart for this particular app. Apps such as WhatsApp etc have their services running because they have marked their apps with Xiaomi. But we can't do it. Or you can use JobScheduler or AlarmManager to make your service run.