1 package com.example.xub3.speakerlocator;
4 * Created by xub3 on 4/14/16.
8 import android.content.BroadcastReceiver;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.telephony.TelephonyManager;
13 public abstract class PhonecallReceiver extends BroadcastReceiver {
15 //The receiver will be recreated whenever android feels like it. We need a static variable to remember data between instantiations
17 private static int lastState = TelephonyManager.CALL_STATE_IDLE;
18 private static Date callStartTime;
19 private static boolean isIncoming;
20 private static String savedNumber;
21 protected Helper helper = MainActivity.helper;
22 //because the passed incoming is only valid in ringing
26 public void onReceive(Context context, Intent intent) {
27 //We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number.
28 if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
29 savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
31 String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
32 String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
34 if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
35 state = TelephonyManager.CALL_STATE_IDLE;
36 } else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
37 state = TelephonyManager.CALL_STATE_OFFHOOK;
38 } else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
39 state = TelephonyManager.CALL_STATE_RINGING;
43 onCallStateChanged(context, state, number);
47 //Derived classes should override these to respond to specific events of interest
48 protected abstract void onIncomingCallReceived(Context ctx, String number, Date start);
49 protected abstract void onIncomingCallAnswered(Context ctx, String number, Date start);
50 protected abstract void onIncomingCallEnded(Context ctx, String number, Date start, Date end);
52 protected abstract void onOutgoingCallStarted(Context ctx, String number, Date start);
53 protected abstract void onOutgoingCallEnded(Context ctx, String number, Date start, Date end);
55 protected abstract void onMissedCall(Context ctx, String number, Date start);
57 //Deals with actual events
59 //Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
60 //Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
61 public void onCallStateChanged(Context context, int state, String number) {
62 if(lastState == state) {
63 //No change, debounce extras
67 case TelephonyManager.CALL_STATE_RINGING:
69 callStartTime = new Date();
71 onIncomingCallReceived(context, number, callStartTime);
74 case TelephonyManager.CALL_STATE_OFFHOOK:
75 //Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
76 if(lastState != TelephonyManager.CALL_STATE_RINGING) {
78 callStartTime = new Date();
79 onOutgoingCallStarted(context, savedNumber, callStartTime);
83 callStartTime = new Date();
84 onIncomingCallAnswered(context, savedNumber, callStartTime);
89 case TelephonyManager.CALL_STATE_IDLE:
90 //Went to idle- this is the end of a call. What type depends on previous state(s)
91 if(lastState == TelephonyManager.CALL_STATE_RINGING) {
92 //Ring but no pickup- a miss
93 onMissedCall(context, savedNumber, callStartTime);
94 } else if(isIncoming) {
95 onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
97 onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());