I want to react to calls (incoming and outgoing ) on a device. The main issue is that the Broadcast receiver that monitors the Phone.State never receives notifications about calls both incoming and outgoing so the code for recording call information in a log never executes. I have also tried most of the links on stackoverflow relating to broadcast receivers but none of them seems to work. Here is my current source code;
[assembly: UsesPermission(Manifest.Permission.ReadCallLog)]
[assembly: UsesPermission(Manifest.Permission.ReadPhoneNumbers)]
[assembly: UsesPermission(Manifest.Permission.ReadPhoneState)]
[assembly: UsesPermission(Manifest.Permission.ProcessOutgoingCalls)]
[assembly: UsesPermission(Manifest.Permission.ReadExternalStorage)]
[assembly: UsesPermission(Manifest.Permission.WriteExternalStorage)]
namespace IncomingOutgoingCall
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
#region Private Properties
IncomingOutgoingBroadcastReceiver callReceiver;
int REQUEST_PERMISSION_CODE = 1003;
#endregion
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
RequestPermission(Manifest.Permission.ReadPhoneState, Manifest.Permission.ProcessOutgoingCalls, Manifest.Permission.ReadPhoneNumbers, Manifest.Permission.WriteExternalStorage, Manifest.Permission.ReadExternalStorage);
callReceiver = new IncomingOutgoingBroadcastReceiver();
var callMonitorIntent = new Intent(ApplicationContext, typeof(IncomingOutgoingBroadcastReceiver));
// SendBroadcast(callMonitorIntent);
}
public void RequestPermission(params string[] permissions)
{
// Request required permission
ActivityCompat.RequestPermissions(this, permissions, REQUEST_PERMISSION_CODE);
}
}
[BroadcastReceiver(Name = "com.callmonitor.app.IncomingOutgoingBroadcastReceiver", Enabled = true, Exported = false)]
[IntentFilter(new[] { TelephonyManager.ActionPhoneStateChanged, "android.intent.action.PHONE_STATE", "android.intent.action.NEW_OUTGOING_CALL" }, Priority = (int)IntentFilterPriority.HighPriority)]
public class IncomingOutgoingBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
string dirPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/" + AppInfo.Name;
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
string filePath = Path.Combine(dirPath, "logFile.txt");
if (!File.Exists(filePath))
File.Create(filePath);
using (StreamWriter sw = new StreamWriter(filePath))
{
// Code to register call information omitted
}
}
}
}
}
And this is my android manifest file
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.callmonitor" android:installLocation="auto">
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="27" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:label="CallMonitor"></application>
</manifest>
If anyone have a link/suggestion of a TESTED AND WORKING SOLUTION on how to get my Broadcast Receiver to work each time a call is in progress, I will like to try it.
It seems it is NOT that easy to read phone call logs from the BroadcastReceiver, the best way to read phone call logs is from the Android Database through Cursor.
public IEnumerable<CallLogModel> GetCallLogs()
{
var phoneContacts = new List<CallLogModel>();
// filter in desc order limit by no
string querySorter = String.Format("{0} desc ", CallLog.Calls.Date);
using (var phones = Android.App.Application.Context.ContentResolver.Query(CallLog.Calls.ContentUri, null, null, null, querySorter))
{
if (phones != null)
{
while (phones.MoveToNext())
{
try
{
string callNumber = phones.GetString(phones.GetColumnIndex(CallLog.Calls.Number));
string callDuration = phones.GetString(phones.GetColumnIndex(CallLog.Calls.Duration));
long callDate = phones.GetLong(phones.GetColumnIndex(CallLog.Calls.Date));
string callName = phones.GetString(phones.GetColumnIndex(CallLog.Calls.CachedName));
int callTypeInt = phones.GetInt(phones.GetColumnIndex(CallLog.Calls.Type));
string callType = Enum.GetName(typeof(CallType), callTypeInt);
var log = new CallLogModel();
log.CallName = callName;
log.CallNumber = callNumber;
log.CallDuration = callDuration;
log.CallDateTick = callDate;
log.CallType = callType;
phoneContacts.Add(log);
}
catch (Exception ex)
{
//something wrong with one contact, may be display name is completely empty, decide what to do
}
}
phones.Close();
}
// if we get here, we can't access the contacts. Consider throwing an exception to display to the user
}
return phoneContacts;
}
This is the sample that you can take a look: