wake-up-neo.net

Wie erkennt man eingehende Anrufe auf einem Android-Gerät?

Ich versuche eine App zu machen, wenn ein Anruf zum Telefon kommt, möchte ich die Nummer erkennen. Unten habe ich versucht, aber es werden keine eingehenden Anrufe erkannt. 

Ich möchte meine MainActivity im Hintergrund ausführen. Wie kann ich das machen?

Ich hatte die Erlaubnis in manifest Datei gegeben.

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

Gibt es noch etwas, was ich im Manifest angeben muss?

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_layout);
   }

   public class myPhoneStateChangeListener extends PhoneStateListener {
       @Override
       public void onCallStateChanged(int state, String incomingNumber) {
           super.onCallStateChanged(state, incomingNumber);
           if (state == TelephonyManager.CALL_STATE_RINGING) {
               String phoneNumber =   incomingNumber;
           }
       }
   }
}
109
Jesbin MJ

Folgendes mache ich dazu:

Manifest:

<uses-permission Android:name="Android.permission.READ_PHONE_STATE" />
<uses-permission Android:name="Android.permission.PROCESS_OUTGOING_CALLS"/>

<!--This part is inside the application-->
    <receiver Android:name=".CallReceiver" >
        <intent-filter>
            <action Android:name="Android.intent.action.PHONE_STATE" />
        </intent-filter>
        <intent-filter>
            <action Android:name="Android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
    </receiver>

Mein wiederverwendbarer Anrufdetektor

package com.gabesechan.Android.reusable.receivers;

import Java.util.Date;

import Android.content.BroadcastReceiver;
import Android.content.Context;
import Android.content.Intent;
import Android.telephony.TelephonyManager;

public abstract class PhonecallReceiver extends BroadcastReceiver {

    //The receiver will be recreated whenever Android feels like it.  We need a static variable to remember data between instantiations

    private static int lastState = TelephonyManager.CALL_STATE_IDLE;
    private static Date callStartTime;
    private static boolean isIncoming;
    private static String savedNumber;  //because the passed incoming is only valid in ringing


    @Override
    public void onReceive(Context context, Intent intent) {

        //We listen to two intents.  The new outgoing call only tells us of an outgoing call.  We use it to get the number.
        if (intent.getAction().equals("Android.intent.action.NEW_OUTGOING_CALL")) {
            savedNumber = intent.getExtras().getString("Android.intent.extra.PHONE_NUMBER");
        }
        else{
            String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
            String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
            int state = 0;
            if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
                state = TelephonyManager.CALL_STATE_IDLE;
            }
            else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
                state = TelephonyManager.CALL_STATE_OFFHOOK;
            }
            else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
                state = TelephonyManager.CALL_STATE_RINGING;
            }


            onCallStateChanged(context, state, number);
        }
    }

    //Derived classes should override these to respond to specific events of interest
    protected abstract void onIncomingCallReceived(Context ctx, String number, Date start);
    protected abstract void onIncomingCallAnswered(Context ctx, String number, Date start);
    protected abstract void onIncomingCallEnded(Context ctx, String number, Date start, Date end);

    protected abstract void onOutgoingCallStarted(Context ctx, String number, Date start);      
    protected abstract void onOutgoingCallEnded(Context ctx, String number, Date start, Date end);

    protected abstract void onMissedCall(Context ctx, String number, Date start);

    //Deals with actual events

    //Incoming call-  goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
    //Outgoing call-  goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
    public void onCallStateChanged(Context context, int state, String number) {
        if(lastState == state){
            //No change, debounce extras
            return;
        }
        switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                isIncoming = true;
                callStartTime = new Date();
                savedNumber = number;
                onIncomingCallReceived(context, number, callStartTime);
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                //Transition of ringing->offhook are pickups of incoming calls.  Nothing done on them
                if(lastState != TelephonyManager.CALL_STATE_RINGING){
                    isIncoming = false;
                    callStartTime = new Date();
                    onOutgoingCallStarted(context, savedNumber, callStartTime);                     
                }
                else
                {
                    isIncoming = true;
                    callStartTime = new Date();
                    onIncomingCallAnswered(context, savedNumber, callStartTime); 
                }

                break;
            case TelephonyManager.CALL_STATE_IDLE:
                //Went to idle-  this is the end of a call.  What type depends on previous state(s)
                if(lastState == TelephonyManager.CALL_STATE_RINGING){
                    //Ring but no pickup-  a miss
                    onMissedCall(context, savedNumber, callStartTime);
                }
                else if(isIncoming){
                    onIncomingCallEnded(context, savedNumber, callStartTime, new Date());                       
                }
                else{
                    onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());                                               
                }
                break;
        }
        lastState = state;
    }
}

Um es zu verwenden, leiten Sie einfach eine Klasse davon ab und implementieren Sie einige einfache Funktionen, je nachdem, welche Anrufarten Sie interessieren:

public class CallReceiver extends PhonecallReceiver {

    @Override
    protected void onIncomingCallReceived(Context ctx, String number, Date start)
    {
        //
    }

    @Override
    protected void onIncomingCallAnswered(Context ctx, String number, Date start)
    {
        //
    }

    @Override
    protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end)
    {
        //
    }

    @Override
    protected void onOutgoingCallStarted(Context ctx, String number, Date start)
    {
        //
    } 

    @Override 
    protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end)
    {
        //
    }

    @Override
    protected void onMissedCall(Context ctx, String number, Date start)
    {
        //
    }

}

Außerdem können Sie einen Bericht darüber lesen, warum der Code so ist, wie er auf meinem blog steht. Hauptlink: https://Gist.github.com/ftvs/e61ccb039f511eb288ee

BEARBEITEN: Auf einfacheren Code aktualisiert, da ich die Klasse für meinen eigenen Gebrauch überarbeitet habe

310
Gabe Sechan
private MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();

registrieren

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

und die Registrierung aufheben

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
19
stinepike

dies kann Ihnen helfen und erfordert auch eine Erlaubnis

public class PhoneListener extends PhoneStateListener
{
    private Context context;
    public static String getincomno;

    public PhoneListener(Context c) {
        Log.i("CallRecorder", "PhoneListener constructor");
        context = c;
    }

    public void onCallStateChanged (int state, String incomingNumber)
    {

        if(!TextUtils.isEmpty(incomingNumber)){
        // here for Outgoing number make null to get incoming number
        CallBroadcastReceiver.numberToCall = null;
        getincomno = incomingNumber;
        }

        switch (state) {
        case TelephonyManager.CALL_STATE_IDLE:

            break;
        case TelephonyManager.CALL_STATE_RINGING:
            Log.d("CallRecorder", "CALL_STATE_RINGING");
            break;
        case TelephonyManager.CALL_STATE_OFFHOOK:

            break;
        }
    }
}
5

Mit Android P - Api Level 28: Sie müssen die Berechtigung READ_CALL_LOG erhalten

Eingeschränkter Zugriff auf Anrufprotokolle

Android P verschiebt die Berechtigungen CALL_LOG, READ_CALL_LOG, WRITE_CALL_LOG und PROCESS_OUTGOING_CALLS von der Berechtigungsgruppe PHONE in die neue Berechtigungsgruppe CALL_LOG. Diese Gruppe bietet Benutzern eine bessere Kontrolle und Sichtbarkeit von Apps, die Zugriff auf vertrauliche Informationen zu Telefonanrufen benötigen, z. B. das Lesen von Telefonanrufaufzeichnungen und das Identifizieren von Telefonnummern.

Um Zahlen aus der Absichtsaktion PHONE_STATE zu lesen, benötigen Sie sowohl die Berechtigung READ_CALL_LOG als auch die Berechtigung READ_PHONE_STATE . Zum Lesen von Zahlen aus onCallStateChanged() benötigen Sie nur noch die Berechtigung READ_CALL_LOG. Sie benötigen die READ_PHONE_STATE-Berechtigung nicht mehr.

5
atasoyh

UPDATE: Der wirklich fantastische Code von Gabe Sechan funktioniert nicht mehr, wenn Sie den Benutzer nicht ausdrücklich auffordern, die erforderlichen Berechtigungen zu erteilen. Hier ist ein Code, den Sie in Ihre Hauptaktivität einfügen können, um diese Berechtigungen anzufordern:

    if (getApplicationContext().checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
            != PackageManager.PERMISSION_GRANTED) {
        // Permission has not been granted, therefore Prompt the user to grant permission
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.READ_PHONE_STATE},
                MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
    }

    if (getApplicationContext().checkSelfPermission(Manifest.permission.PROCESS_OUTGOING_CALLS)
            != PackageManager.PERMISSION_GRANTED) {
        // Permission has not been granted, therefore Prompt the user to grant permission
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS},
                MY_PERMISSIONS_REQUEST_PROCESS_OUTGOING_CALLS);
    }

AUCH: Wie in einem Kommentar unter Gabe's Post erwähnt, müssen Sie dem Empfänger ein kleines Code-Code-Code (Android:enabled="true) hinzufügen, um eingehende Anrufe zu erkennen, wenn die App derzeit nicht im Vordergrund ausgeführt wird:

    <!--This part is inside the application-->
    <receiver Android:name=".CallReceiver" Android:enabled="true">
        <intent-filter>
            <action Android:name="Android.intent.action.PHONE_STATE" />
        </intent-filter>
        <intent-filter>
            <action Android:name="Android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
    </receiver>
4
topherPedersen

Nur um die Antwort von Gabe Sechan zu aktualisieren. Wenn Ihr Manifest nach Berechtigungen für READ_CALL_LOG und READ_PHONE_STATE fragt, wird onReceive ZWEIMAL aufgerufen. In einer ist EXTRA_INCOMING_NUMBER enthalten, in der anderen nicht. Sie müssen testen, welche es hat und es kann in beliebiger Reihenfolge auftreten.

https://developer.Android.com/reference/Android/telephony/TelephonyManager.html#ACTION_PHONE_STATE_CHANGED

1
Jaitnium

Hier ist eine einfache Methode, mit der PhonestateListener und andere Komplikationen vermieden werden können.
Wir empfangen hier also die 3 Ereignisse von Android wie RINGING, OFFHOOK und IDLE. Und um den möglichen Status eines Anrufs zu erhalten, müssen wir unsere eigenen Zustände definieren, wie RINGING, OFFHOOK, IDLE, FIRST_CALL_RINGING, SECOND_CALL_RINGING..__, die alle Zustände eines Telefonanrufs verarbeiten können.
Denken Sie bitte so, dass wir Ereignisse von Android empfangen, und wir definieren unseren Bereitschaftsstatus. Siehe den Code.

public class CallListening  extends BroadcastReceiver {
    private static final String TAG ="broadcast_intent";
    public static String incoming_number;
    private String current_state,previus_state,event;
    public static Boolean dialog= false;
    private Context context;
    private SharedPreferences sp,sp1;
    private SharedPreferences.Editor spEditor,spEditor1;
    public void onReceive(Context context, Intent intent) {
        //Log.d("intent_log", "Intent" + intent);
        dialog=true;
        this.context = context;
        event = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
        incoming_number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
        Log.d(TAG, "The received event : "+event+", incoming_number : " + incoming_number);
        previus_state = getCallState(context);
        current_state = "IDLE";
        if(incoming_number!=null){
            updateIncomingNumber(incoming_number,context);
        }else {
            incoming_number=getIncomingNumber(context);
        }
        switch (event) {
            case "RINGING":
                Log.d(TAG, "State : Ringing, incoming_number : " + incoming_number);
            if((previus_state.equals("IDLE")) || (previus_state.equals("FIRST_CALL_RINGING"))){
                    current_state ="FIRST_CALL_RINGING";
                }
                if((previus_state.equals("OFFHOOK"))||(previus_state.equals("SECOND_CALL_RINGING"))){
                    current_state = "SECOND_CALL_RINGING";
                }

                break;
            case "OFFHOOK":
                Log.d(TAG, "State : offhook, incoming_number : " + incoming_number);
                if((previus_state.equals("IDLE")) ||(previus_state.equals("FIRST_CALL_RINGING")) || previus_state.equals("OFFHOOK")){
                    current_state = "OFFHOOK";
                }
                if(previus_state.equals("SECOND_CALL_RINGING")){
                    current_state ="OFFHOOK";
                    startDialog(context);
                }
                break;
            case "IDLE":
                Log.d(TAG, "State : idle and  incoming_number : " + incoming_number);
                if((previus_state.equals("OFFHOOK")) || (previus_state.equals("SECOND_CALL_RINGING")) || (previus_state.equals("IDLE"))){
                    current_state="IDLE";
                }
                if(previus_state.equals("FIRST_CALL_RINGING")){
                    current_state = "IDLE";
                    startDialog(context);
                }
                updateIncomingNumber("no_number",context);
                Log.d(TAG,"stored incoming number flushed");
                break;
        }
        if(!current_state.equals(previus_state)){
            Log.d(TAG, "Updating  state from "+previus_state +" to "+current_state);
            updateCallState(current_state,context);

        }
    }
    public void startDialog(Context context) {
        Log.d(TAG,"Starting Dialog box");
        Intent intent1 = new Intent(context, NotifyHangup.class);
        intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent1);

    }
    public void updateCallState(String state,Context context){
        sp = PreferenceManager.getDefaultSharedPreferences(context);
        spEditor = sp.edit();
        spEditor.putString("call_state", state);
        spEditor.commit();
        Log.d(TAG, "state updated");

    }
    public void updateIncomingNumber(String inc_num,Context context){
        sp = PreferenceManager.getDefaultSharedPreferences(context);
        spEditor = sp.edit();
        spEditor.putString("inc_num", inc_num);
        spEditor.commit();
        Log.d(TAG, "incoming number updated");
    }
    public String getCallState(Context context){
        sp1 = PreferenceManager.getDefaultSharedPreferences(context);
        String st =sp1.getString("call_state", "IDLE");
        Log.d(TAG,"get previous state as :"+st);
        return st;
    }
    public String getIncomingNumber(Context context){
        sp1 = PreferenceManager.getDefaultSharedPreferences(context);
        String st =sp1.getString("inc_num", "no_num");
        Log.d(TAG,"get incoming number as :"+st);
        return st;
    }
}
1
ARUNBALAN NV

Bitte verwenden Sie den untenstehenden Code. Es hilft Ihnen, die eingehende Nummer mit anderen Anrufdetails zu erhalten.

activity_main.xml

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context=".MainActivity" >

<TextView
    Android:id="@+id/call"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:layout_centerHorizontal="true"
    Android:layout_centerVertical="true"
    Android:text="@string/hello_world" />

</RelativeLayout>

Hauptaktivität.Java

public class MainActivity extends Activity {

private static final int MISSED_CALL_TYPE = 0;
private TextView txtcall;

@Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    txtcall = (TextView) findViewById(R.id.call);

    StringBuffer sb = new StringBuffer();
    Cursor managedCursor = managedQuery(CallLog.Calls.CONTENT_URI, null,
            null, null, null);
    int number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER);
    int type = managedCursor.getColumnIndex(CallLog.Calls.TYPE);
    int date = managedCursor.getColumnIndex(CallLog.Calls.DATE);
    int duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION);
    sb.append("Call Details :");
    while (managedCursor.moveToNext()) {
        String phNumber = managedCursor.getString(number);
        String callType = managedCursor.getString(type);
        String callDate = managedCursor.getString(date);
        Date callDayTime = new Date(Long.valueOf(callDate));
        String callDuration = managedCursor.getString(duration);
        String dir = null;
        int dircode = Integer.parseInt(callType);
        switch (dircode) {

        case CallLog.Calls.OUTGOING_TYPE:
            dir = "OUTGOING";
            break;

        case CallLog.Calls.INCOMING_TYPE:
            dir = "INCOMING";
            break;

        case CallLog.Calls.MISSED_TYPE:
            dir = "MISSED";
            break;
        }
        sb.append("\nPhone Number:--- " + phNumber + " \nCall Type:--- "
                + dir + " \nCall Date:--- " + callDayTime
                + " \nCall duration in sec :--- " + callDuration);
        sb.append("\n----------------------------------");
    }
    managedCursor.close();
    txtcall.setText(sb);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

} 

<uses-permission Android:name="Android.permission.READ_CONTACTS"/>
<uses-permission Android:name="Android.permission.READ_LOGS"/>
0
user2173696

@ Gabe Sechan, danke für deinen Code. Es funktioniert gut, außer der onOutgoingCallEnded(). Es wird niemals ausgeführt. Test-Handys sind Samsung S5 & Trendy. Ich denke, es gibt 2 Bugs. 

1: ein Paar Klammern fehlt. 

case TelephonyManager.CALL_STATE_IDLE: 
    // Went to idle-  this is the end of a call.  What type depends on previous state(s)
    if (lastState == TelephonyManager.CALL_STATE_RINGING) {
        // Ring but no pickup-  a miss
        onMissedCall(context, savedNumber, callStartTime);
    } else {
        // this one is missing
        if(isIncoming){
            onIncomingCallEnded(context, savedNumber, callStartTime, new Date());                       
        } else {
            onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());                                               
        }
    }
    // this one is missing
    break;

2: lastState wird von der state nicht aktualisiert, wenn sie sich am Ende der Funktion befindet. Es sollte in der ersten Zeile dieser Funktion durch ersetzt werden

public void onCallStateChanged(Context context, int state, String number) {
    int lastStateTemp = lastState;
    lastState = state;
    // todo replace all the "lastState" by lastStateTemp from here.
    if (lastStateTemp  == state) {
        //No change, debounce extras
        return;
    }
    //....
}

Zusätzlich habe ich lastState und savedNumber in die gemeinsame Einstellung gesetzt, wie Sie vorgeschlagen haben. 

Habe es gerade mit den oben genannten Änderungen getestet. Fehler zumindest auf meinen Handys behoben. 

0
Diiiiii