diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index 0c0c338..13cec1d 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -3,7 +3,20 @@ - + + + + + + + + + + + + + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a7ceea1..97a641b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ + - + diff --git a/app/src/main/java/com/app/simplitend/patient_dashboard/CallReceiver.java b/app/src/main/java/com/app/simplitend/patient_dashboard/CallReceiver.java index 8c569f8..25b43b6 100644 --- a/app/src/main/java/com/app/simplitend/patient_dashboard/CallReceiver.java +++ b/app/src/main/java/com/app/simplitend/patient_dashboard/CallReceiver.java @@ -1,18 +1,197 @@ package com.app.simplitend.patient_dashboard; +import static com.app.simplitend.callwhitelisting.CallUnBlockingWorker.CALL_BLOCKING_WORk; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.telecom.TelecomManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.telephony.TelephonyManager; +import android.util.Log; + +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; +import androidx.work.WorkRequest; + +import com.app.simplitend.apputils.AppUtil; +import com.app.simplitend.callwhitelisting.CallUnBlockingWorker; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.Phonenumber; + +import java.lang.reflect.Method; +import java.util.Date; +import java.util.Set; +import java.util.concurrent.TimeUnit; public class CallReceiver extends BroadcastReceiver { private static final String TAG = "CallReceiver"; + 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) { - TelecomManager telecomManager = (TelecomManager) context.getApplicationContext().getSystemService(TelecomManager.class); + if (intent.getExtras() == null) { + Log.d(TAG, "onReceive: EXTRAS ARE NULL"); + return; + } + +// logBundle(intent.getExtras()); + + String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE); + String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER); + + int state = 0; + if (TelephonyManager.EXTRA_STATE_IDLE.equals(stateStr)) { + state = TelephonyManager.CALL_STATE_IDLE; + } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(stateStr)) { + state = TelephonyManager.CALL_STATE_OFFHOOK; + } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(stateStr)) { + state = TelephonyManager.CALL_STATE_RINGING; + } + + onCallStateChanged(context, state, number); } -} + protected void logBundle(Bundle bundle) { + if (bundle != null) { + for (String key : bundle.keySet()) { + Log.e(TAG, key + " : " + (bundle.get(key) != null ? bundle.get(key) : "NULL")); + } + } + } + + //Derived classes should override these to respond to specific events of interest + protected void onIncomingCallStarted(Context ctx, String number, Date start) { + Log.d(TAG, "onIncomingCallStarted: " + number); + if (!AppUtil.isCallBlockingEnabled(ctx)) { + // senior has deactivated the call blocking feature + Log.d(TAG, "onIncomingCallStarted: CALL BLOCKING IS DEACTIVATED"); + return; + } + + try { + Phonenumber.PhoneNumber parsed_phone = PhoneNumberUtil.getInstance().parse(number, "US"); + number = "+" + parsed_phone.getCountryCode() + parsed_phone.getNationalNumber(); + } catch (Exception e) { + // do nothing + } + + Log.d(TAG, "AFTER FORMATTING PHONE NUMBER -> " + number); + + Set white_contacts = AppUtil.getWhiteListedContacts(ctx); + Log.d(TAG, "WHITE LISTED CONTACTS -> " + white_contacts); + + if (AppUtil.isUserSubscribed(ctx) && white_contacts != null && !white_contacts.contains(number)) { + disconnectCall(); + Log.d(TAG, "CALL ENDED"); + } + + } + + public void disconnectCall(){ + try { + String serviceManagerName = "android.os.ServiceManager"; + String serviceManagerNativeName = "android.os.ServiceManagerNative"; + String telephonyName = "com.android.internal.telephony.ITelephony"; + Class telephonyClass; + Class telephonyStubClass; + Class serviceManagerClass; + Class serviceManagerNativeClass; + Method telephonyEndCall; + Object telephonyObject; + Object serviceManagerObject; + telephonyClass = Class.forName(telephonyName); + telephonyStubClass = telephonyClass.getClasses()[0]; + serviceManagerClass = Class.forName(serviceManagerName); + serviceManagerNativeClass = Class.forName(serviceManagerNativeName); + Method getService = // getDefaults[29]; + serviceManagerClass.getMethod("getService", String.class); + Method tempInterfaceMethod = serviceManagerNativeClass.getMethod("asInterface", IBinder.class); + Binder tmpBinder = new Binder(); + tmpBinder.attachInterface(null, "fake"); + serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder); + IBinder retbinder = (IBinder) getService.invoke(serviceManagerObject, "phone"); + Method serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder.class); + telephonyObject = serviceMethod.invoke(null, retbinder); + telephonyEndCall = telephonyClass.getMethod("endCall"); + telephonyEndCall.invoke(telephonyObject); + + } catch (Exception e) { + Log.e(TAG, + "FATAL ERROR: could not connect to telephony subsystem"); + Log.e(TAG, "Exception object: " + e); + } + } + + protected void onOutgoingCallStarted(Context ctx, String number, Date start) { + Log.d(TAG, "onOutgoingCallStarted: " + number); + if ("911".equals(number)){ + Log.d(TAG, "CALLED 911"); + WorkManager.getInstance(ctx).cancelAllWorkByTag(TAG); + WorkRequest workRequest = new OneTimeWorkRequest.Builder(CallUnBlockingWorker.class) + .setInitialDelay(30, TimeUnit.MINUTES) + .addTag(CALL_BLOCKING_WORk) + .build(); + + WorkManager.getInstance(ctx).enqueue(workRequest); + + AppUtil.setIsCallBlockingEnabled(ctx, false); + Log.d(TAG, "CALL BLOCKING DISABLED"); + } + } + + 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, number, 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; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/app/simplitend/patient_dashboard/DashBoardActivity.java b/app/src/main/java/com/app/simplitend/patient_dashboard/DashBoardActivity.java index 9a935c9..a31400f 100644 --- a/app/src/main/java/com/app/simplitend/patient_dashboard/DashBoardActivity.java +++ b/app/src/main/java/com/app/simplitend/patient_dashboard/DashBoardActivity.java @@ -78,7 +78,6 @@ public class DashBoardActivity extends AppCompatActivity implements CgHomeContra }), null, null); } - requestPermissions(new String[]{Manifest.permission.CALL_PHONE}, 1212); }); registerForActivityResult(new ActivityResultContracts.RequestPermission(), @@ -94,6 +93,8 @@ public class DashBoardActivity extends AppCompatActivity implements CgHomeContra RoleManager roleManager = getSystemService(RoleManager.class); Intent i = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING); startActivityForResult(i, 1214, null); + }else{ + requestPermissions(new String[]{Manifest.permission.CALL_PHONE, Manifest.permission.READ_PHONE_STATE, Manifest.permission.ANSWER_PHONE_CALLS}, 1212); } } }).launch(Manifest.permission.READ_CONTACTS); diff --git a/app/src/main/java/com/app/simplitend/patient_dashboard/PatSettingsActivity.java b/app/src/main/java/com/app/simplitend/patient_dashboard/PatSettingsActivity.java index 252fdad..1f4b865 100644 --- a/app/src/main/java/com/app/simplitend/patient_dashboard/PatSettingsActivity.java +++ b/app/src/main/java/com/app/simplitend/patient_dashboard/PatSettingsActivity.java @@ -1,8 +1,10 @@ package com.app.simplitend.patient_dashboard; +import static com.app.simplitend.callwhitelisting.CallUnBlockingWorker.CALL_BLOCKING_WORk; import static com.app.simplitend.caregiverdashboard.activities.deactivateacc.DeActivateAccountActivity.IS_PATIENT_KEY; import androidx.appcompat.app.AppCompatActivity; +import androidx.work.WorkManager; import android.app.ProgressDialog; import android.content.Context; @@ -74,6 +76,9 @@ public class PatSettingsActivity extends AppCompatActivity implements CgHomeCont binding.callBlockCheck.setOnCheckedChangeListener(null); binding.callBlockCheck.setChecked(true); binding.callBlockCheck.setOnCheckedChangeListener(this); + + WorkManager.getInstance(PatSettingsActivity.this) + .cancelAllWorkByTag(CALL_BLOCKING_WORk); }), "Turn off", ((dialogInterface, i) -> { AppUtil.setIsCallBlockingEnabled(PatSettingsActivity.this, false);