Forum Xamarin.Android

Xamarin.Android: React to all incoming and outgoing calls.

emilekeen15emilekeen15 Member ✭✭
edited February 12 in Xamarin.Android

I want to create custom list of all calls (incoming and outgoing ) on phone using a Xamarin.Android app. But I can't get this solution to work as required. The main issue is that the Broadcast receiver that monitors the Phone.State never receives notifications about calls both incoming and outgoing. I have also tried most of the links on stackoverflow relating to this question to no avail, so please if anyone has a WORKING SOLUTION that they have tested, help.
If anyone have a link/suggestion of a TESTED AND WORKING SOLUTION, I will like to try it.

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 the 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>

Answers

  • JarvanJarvan Member, Xamarin Team Xamurai

    All the call activities on your phone are logged in the call_log content provider. Therefore, if you want details about all the incoming, outgoing, or missed calls, you can query the content provider to get them.

    To get the call log details, query the call_log content provider, iterating through the results by using a Cursor object.

    Retrieves all the call details

    public void GetCallLogs()
    {
        string querySorter = String.Format("{0} desc ", CallLog.Calls.Date);
    
        // CallLog.Calls.ContentUri is the path where data is saved
        Android.Database.ICursor queryData = ContentResolver.Query(CallLog.Calls.ContentUri, null, null, null, querySorter);
    
        while (queryData.MoveToNext())
        {
            //---phone number---
            string callNumber = queryData.GetString(queryData.GetColumnIndex(CallLog.Calls.Number));
    
            //---date of call---
            string callDate = queryData.GetString(queryData.GetColumnIndex(CallLog.Calls.Date));
    
            //---1-incoming; 2-outgoing; 3-missed---
            String callType = queryData.GetString(queryData.GetColumnIndex(CallLog.Calls.Type));
        }
    }
    

    For Getting only Incoming Call logs:

    string queryFilter = String.Format ("{0}={1}", CallLog.Calls.Type, (int)CallType.Incoming);
    

    For Getting only outcoming Call logs:

    string queryFilter = String.Format ("{0}={1}", CallLog.Calls.Type, (int)CallType.Outgoing);
    

    Tutorial:
    http://revansiddappa.blogspot.com/p/post-6-xamarin-displaying-call-log.html

  • emilekeen15emilekeen15 Member ✭✭

    Thank you Jarvan. Any suggestions on how to get the Broadcast Receiver to work? For now, it's not even receiving call notifications, so I can't get to the part of reading call logs

  • emilekeen15emilekeen15 Member ✭✭
    edited February 12

    @emilekeen15 said:
    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;
    If anyone have a link/suggestion of a TESTED AND WORKING SOLUTION on how to get Broadcast Receiver to work, I will like to try it.

    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 the 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>
    
  • JarvanJarvan Member, Xamarin Team Xamurai

    Any suggestions on how to get the Broadcast Receiver to work? For now, it's not even receiving call notifications

    To use the Broadcast Receiver:
    First, creating a Broadcast Receiver

    [BroadcastReceiver(Enabled = true, Exported = false)]
    public class SampleReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            // Do stuff here.
    
            String value = intent.GetStringExtra("key");
        }
    }
    

    Then, register the Broadcast Receiver

    [Activity(Label = "MainActivity", MainLauncher = true, Icon = "@mipmap/icon")]
    public class MainActivity: Activity 
    {
        MySampleBroadcastReceiver receiver;
    
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            receiver = new MySampleBroadcastReceiver();
        }
    
        protected override void OnResume() 
        {
            base.OnResume();
            RegisterReceiver(receiver, new IntentFilter("com.xamarin.example.TEST"));
        }
    
        protected override void OnPause() 
        {
            UnregisterReceiver(receiver);
            base.OnPause();
        }
    }
    

    For more details, check the Tutorial:
    https://docs.microsoft.com/en-us/xamarin/android/app-fundamentals/broadcast-receivers

Sign In or Register to comment.