我有一个项目,我做了类似的事情,我创建了两个类,一个是 PhoneCallListener 和 PhoneCallReceiver。我已经删除了一些用于我需要的代码,但是如果你实现了这两个类,你应该没问题。我不是专家,但希望对您有所帮助。
jsonObject 只是作为一个例子来展示“做某事”。我还应该提一下,我不了解 Kotlin,但有人告诉我 Android Studio 可以将 Java 转换为 Kotlin,所以它可能会有所帮助,希望有经验的人知道 Kotlin 的使用方法。
PhoneCallListener.java
public class PhoneCallListener extends PhoneCallReceiver {
@Override
protected void onIncomingCallStarted(Context c, String number, Date start) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("Timestamp", App.getUTCTimestamp());
jsonObject.put("Direction", "incoming");
jsonObject.put("Number", number);
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
protected void onOutgoingCallStarted(Context c, String number, Date start) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("Timestamp", App.getUTCTimestamp());
jsonObject.put("Direction", "outgoing");
jsonObject.put("Number", number);
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
protected void onIncomingCallEnded(Context c, String number, Date start, Date end)
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("Timestamp", App.getUTCTimestamp());
jsonObject.put("Direction", "incoming call ended");
jsonObject.put("Number", number);
} catch (JSONException e) {
e.printStackTrace();
});
}
@Override
protected void onOutgoingCallEnded(Context c, String number, Date start, Date end) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("Timestamp", App.getUTCTimestamp());
jsonObject.put("Direction", "outgoing call ended");
jsonObject.put("Number", number);
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
protected void onMissedCall(Context c, String number, Date start) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("Timestamp", App.getUTCTimestamp());
jsonObject.put("Direction", "missed");
jsonObject.put("Number", number);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
PhoneCallReceiver.java
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.
try {
if (Objects.equals(intent.getAction(), "android.intent.action.NEW_OUTGOING_CALL")) {
savedNumber = Objects.requireNonNull(intent.getExtras()).getString("android.intent.extra.PHONE_NUMBER");
} else {
String stateStr = Objects.requireNonNull(intent.getExtras()).getString(TelephonyManager.EXTRA_STATE);
String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (number == null) {
number = "00000000000"; // Caller Withheld.
}
int state = 0;
assert stateStr != null;
if (!stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
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);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//Derived classes should override these to respond to specific events of interest
protected void onIncomingCallStarted(Context ctx, String number, Date start) {
}
protected void onOutgoingCallStarted(Context ctx, String number, Date start) {
}
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) {
}
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) {
}
protected 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;
onIncomingCallStarted(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);
}
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;
}
}