Search code examples
androidserviceandroid-serviceandroid-screenandroid-background

Android: How to run service when screen is lock?


I m developing an android app in which I want to display a toast during incoming call my app is running fine when screen is unlocked. But its not displaying anything when home screen is locked, can anyone help me.

Here is my whole code

package com.example.lenovo.call_toast;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerManager;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;


public class MainActivity_service extends Activity {

    private boolean detectEnabled;

    private TextView textViewDetectState;
    private Button buttonToggleDetect;
    private Button buttonExit;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);
        PowerManager.WakeLock wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
        wakeLock.acquire();

        textViewDetectState = (TextView) findViewById(R.id.textViewDetectState);

        buttonToggleDetect = (Button) findViewById(R.id.buttonDetectToggle);
        buttonToggleDetect.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                setDetectEnabled(!detectEnabled);
            }
        });

        buttonExit = (Button) findViewById(R.id.buttonExit);
        buttonExit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                setDetectEnabled(false);
                MainActivity_service.this.finish();
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    private void setDetectEnabled(boolean enable) {
        detectEnabled = enable;

        Intent intent = new Intent(this, CallDetectService.class);
        if (enable) {
             // start detect service




            startService(intent);

            buttonToggleDetect.setText("Turn off");
            textViewDetectState.setText("Detecting");
        }
        else {
            // stop detect service
            stopService(intent);

            buttonToggleDetect.setText("Turn on");
            textViewDetectState.setText("Not detecting");
        }
    }

}

This is my service to detect call

 package com.example.lenovo.call_toast;

    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;


    public class CallDetectService extends Service {
        private CallHelper callHelper;

        public CallDetectService() {
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            callHelper = new CallHelper(this);

            int res = super.onStartCommand(intent, flags, startId);
            callHelper.start();
            return res;
        }

        @Override
        public void onDestroy() {
            super.onDestroy();

            callHelper.stop();
        }

        @Override
        public IBinder onBind(Intent intent) {
            // not supporting binding
            return null;
        }
    }

And this is another class

package com.example.lenovo.call_toast;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;


public class CallHelper {

    /**
     * Listener to detect incoming calls. 
     */
    private class CallStateListener extends PhoneStateListener {
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {

            switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                // called when someone is ringing to this phone

                Toast.makeText(ctx,
                        "Incoming: " +incomingNumber,
                        Toast.LENGTH_LONG).show();

                break;

            }
        }
    }

    /**
     * Broadcast receiver to detect the outgoing calls.
     */
    public class OutgoingReceiver extends BroadcastReceiver {
        public OutgoingReceiver() {
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
            Log.e( "onCallStateChanged: ",number );
            Toast.makeText(ctx,"Outgoing: "+number,
                    Toast.LENGTH_LONG).show();
        }

    }

    private Context ctx;
    private TelephonyManager tm;
    private CallStateListener callStateListener;

    private OutgoingReceiver outgoingReceiver;

    public CallHelper(Context ctx) {
        this.ctx = ctx;

        callStateListener = new CallStateListener();
        outgoingReceiver = new OutgoingReceiver();
    }

    /**
     * Start calls detection.
     */
    public void start() {
        tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
        tm.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);

        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
        ctx.registerReceiver(outgoingReceiver, intentFilter);

    }

    /**
     * Stop calls detection.
     */
    public void stop() {
        tm.listen(callStateListener, PhoneStateListener.LISTEN_NONE);
        ctx.unregisterReceiver(outgoingReceiver);
    }

}

And here is the manifest file

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.lenovo.call_toast">

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK"/>



    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity_service">
            <intent-filter>-->
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--<activity android:name=".MyCustomDialog"-->
            <!--android:theme="@android:style/Theme.Dialog"-->
            <!--android:noHistory="true"-->
            <!--/>-->
        <!--&lt;!&ndash;<receiver android:name=".CallReceiver" >&ndash;&gt;-->
            <!--&lt;!&ndash;<intent-filter>&ndash;&gt;-->
                <!--&lt;!&ndash;<action android:name="android.intent.action.PHONE_STATE" />&ndash;&gt;-->
            <!--&lt;!&ndash;</intent-filter>&ndash;&gt;-->
            <!--&lt;!&ndash;<intent-filter>&ndash;&gt;-->
                <!--&lt;!&ndash;<action android:name="android.intent.action.NEW_OUTGOING_CALL" />&ndash;&gt;-->
            <!--&lt;!&ndash;</intent-filter>&ndash;&gt;-->
        <!--</receiver>-->

        <service android:name=".CallDetectService"

            android:enabled="true"
            android:exported="false"/>

    </application>


</manifest>

Solution

  • The code you wrote will not work for new devices when the screen is locked because now android takes care of the battery drains. And so it will not allow a background service to run with the receiver. But still, if you want to do this, follow these steps:

    • Step 1) Make receiver
    • Step 2) Start the service/activity or any task on onReceive method rather than continuously running it as receivers are meant to do this task.

    Like:

        @Override
            public void onReceive(Context context, Intent intent) {
                // TODO Auto-generated method stub
        {
    
        Bundle bb = intent.getExtras();  
              String state = bb.getString(TelephonyManager.EXTRA_STATE);
              if ((state != null)&& (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)))     
              {
                  incommingNumber = bb.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
        blockCall(context, bb);
        }
        }
    
        public void blockCall(Context c, Bundle b)
        {
    
          TelephonyManager telephony = (TelephonyManager) 
          c.getSystemService(Context.TELEPHONY_SERVICE);  
          try {
           Class cls = Class.forName(telephony.getClass().getName());
           Method m = cls.getDeclaredMethod("getITelephony");
           m.setAccessible(true);
           telephonyService = (ITelephony) m.invoke(telephony);
           //telephonyService.silenceRinger();
           telephonyService.endCall();
    
              new SendValue(c,incommingNumber);
    
          } catch (Exception e) {
           e.printStackTrace();
          }
    }
    

    Where SendValue(Context c,String incomingNumber); is a constructor of other Java class to do the needful task when call is received and incommingNumber is a global String variable so that its value can be altered when call is received.