Automatic Call Blocking Using Android Telephony Tutorial
Last Updated: May 12, 2015
This tutorial will guide you how to block all unwanted incoming calls to your Android phone by using Android Telephony APIs. You will learn to create a simple Android application named “Auto Call Blocker”, which will store the unwanted phone numbers (spam) to the SQLite database of your phone and automatically disconnect the call which is coming from any of such phone numbers.
Tutorial
Requirements
The attached source code is a simple Android application named “Auto Call Blocker”. So, use cases of the applications are:
- Add Phone number to block list.
- View list of Spam Phone numbers stored into the db.
- Delete any such stored phone number.
- Block the unwanted incoming call.
Application Screens
There are 2 screens in this application as described below:
MainActivity – Launcher screen of the app, which displays the list of all spam phone numbers added by the user.
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center_horizontal" android:layout_marginBottom="20dip" android:text="Automatic Call Blocker" android:textSize="25sp" /> <TableLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="10dip" > <ListView android:id="@+id/listview" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </TableLayout> <Button android:id="@+id/add_blacklist_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:text="Add Phone Number to Auto Block " /> </LinearLayout>
list_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TableRow android:layout_width="fill_parent" android:background="#6f6c67" android:layout_gravity="center" android:layout_height="wrap_content" > <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginTop="10dip" android:text="Serial #" android:id="@+id/serial_tv" android:textColor="#980000" android:background="#e7e5d9" android:layout_margin="1dip" android:padding="3dip" android:gravity="center" android:layout_weight="2" android:textSize="15sp" /> <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginTop="10dip" android:text="Phone Number " android:id="@+id/phone_number_tv" android:textColor="#980000" android:background="#e7e5d9" android:layout_margin="1dip" android:padding="3dip" android:gravity="center" android:layout_weight="1" android:textSize="15sp" /> </TableRow> </LinearLayout>
Output:
AddToBlocklistActivity– To add a phone number to the block list stored into the database.
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center_horizontal" android:text="Add Phone Number" android:textSize="22sp" /> <TableLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="left" android:orientation="vertical" android:padding="10dip" > <TableRow android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="Country code " android:textSize="15sp" /> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="0dip" android:layout_weight="1" android:id="@+id/country_code_et" android:inputType="number" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="Phone Number " android:textSize="15sp" /> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="0dip" android:layout_weight="1" android:id="@+id/phone_et" android:inputType="number" /> </TableRow> </TableLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="20dip" > <Button android:id="@+id/reset_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_weight="1" android:text="Reset" /> <Button android:id="@+id/submit_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_weight="1" android:text="Submit" /> </LinearLayout> </LinearLayout>
Output:
Steps to Development
1. Create ITelephony.aidl class
Create a package in your src/ directory of the Android application and name it as “com.android.internal.telephony”.
Create a class in that package named: ITelephony.aidl and copy the below source into it.
ITelephony.aidl
package com.android.internal.telephony; // Need for Android Telephony // Please keep the package, class and method names as it is. interface ITelephony { boolean endCall(); }
2. Define Database Table structure
We have only one table in our application: i.e. blacklist with the below structure:
blacklist | |
id | int (auto) – PK |
phone_number | String |
3. Create Data Model
There is only one data model class: Blacklist
Blacklist.java
package com.androidbegin.callblocker; // Model class for database table blacklist public class Blacklist { // Two mapping fields for the database table blacklist public long id; public String phoneNumber; // Default constructor public Blacklist() { } // To easily create Blacklist object, an alternative constructor public Blacklist(final String phoneMumber) { this.phoneNumber = phoneMumber; } // Overriding the default method to compare between the two objects bu phone number @Override public boolean equals(final Object obj) { // If passed object is an instance of Blacklist, then compare the phone numbers, else return false as they are not equal if(obj.getClass().isInstance(new Blacklist())) { // Cast the object to Blacklist final Blacklist bl = (Blacklist) obj; // Compare whether the phone numbers are same, if yes, it defines the objects are equal if(bl.phoneNumber.equalsIgnoreCase(this.phoneNumber)) return true; } return false; } }
4. Create Database Helper
This class performs the database creation, table creation etc.
DatabaseHelper.java
package com.androidbegin.callblocker; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DatabaseHelper extends SQLiteOpenHelper { // Define the SQLite database name private static final String DATABASE_NAME = "call_blocker.db"; // Define the SQLite database version private static final int DATABASE_VERSION = 1; // Define the SQLite Table name to create public static final String TABLE_BLACKLIST = "blacklist"; // Table creation SQL statement private static final String TABLE_CREATE = "create table " + TABLE_BLACKLIST + "( id " + " integer primary key autoincrement, phone_number text not null);"; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } // This method will execute once in the application entire life cycle // All table creation code should put here @Override public void onCreate(SQLiteDatabase db) { db.execSQL(TABLE_CREATE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub } }
5. Create BlacklistDAO.java
This class acts as Data source for blacklist database table. It contains CRUD methods to access the same.
Blacklist.DAO
package com.androidbegin.callblocker; import java.util.ArrayList; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; public class BlacklistDAO { // SQLiteDatabase and DatabaseHelper objects to access SQLite database private SQLiteDatabase database; private DatabaseHelper dbHelper; // Constructor initiates the DatabaseHelper to make sure, database creation is done public BlacklistDAO(Context context) { dbHelper = new DatabaseHelper(context); open(); } private void open() throws SQLException { // Opens the database connection to provide the access database = dbHelper.getWritableDatabase(); } public void close() { // Close it, once done dbHelper.close(); } public Blacklist create(final Blacklist blackList) { // Steps to insert data into db (instead of using raw SQL query) // first, Create an object of ContentValues final ContentValues values = new ContentValues(); // second, put the key-value pair into it values.put("phone_number", blackList.phoneNumber); // thirst. insert the object into the database final long id = database.insert(DatabaseHelper.TABLE_BLACKLIST , null, values); // set the primary key to object and return back blackList.id = id; return blackList; } public void delete(final Blacklist blackList) { // Way to delete a record from database database.delete(DatabaseHelper.TABLE_BLACKLIST, "phone_number = '" + blackList.phoneNumber + "'", null); } public List<Blacklist> getAllBlacklist() { // Steps to fetch all records from a database table // first, create the desired object final List<Blacklist> blacklistNumbers = new ArrayList<Blacklist>(); // second, Query the database and set the result into Cursor final Cursor cursor = database.query(DatabaseHelper.TABLE_BLACKLIST, new String[]{"id","phone_number"}, null, null, null, null, null); // Move the Cursor pointer to the first cursor.moveToFirst(); //Iterate over the cursor while (!cursor.isAfterLast()) { final Blacklist number = new Blacklist(); // Fetch the desired value from the Cursor by column index number.id = cursor.getLong(0); number.phoneNumber = cursor.getString(1); // Add the object filled with appropriate data into the list blacklistNumbers.add(number); // Move the Cursor pointer to next for the next record to fetch cursor.moveToNext(); } return blacklistNumbers; } }
6. MainActivity
It is the launcher screen of the application which displays a list of all ‘Black listed” mobile numbers stored by the user.
User may add a new phone number to the black list by tapping the “Add phone number” button.
User may delete an existing number from the list by long pressing the same.
MainActivity.java
package com.androidbegin.callblocker; import java.util.List; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends ActionBarActivity implements OnClickListener, OnItemLongClickListener { // Declaration all on screen components of the Main screen private Button add_blacklist_btn; public ListView listview; // Object of BlacklistDAO to query to database private BlacklistDAO blackListDao; // It holds the list of Blacklist objects fetched from Database public static List<Blacklist> blockList; // This holds the value of the row number, which user has selected for further action private int selectedRecordPosition = -1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initialization of the button of the Main screen add_blacklist_btn = (Button) findViewById(R.id.add_blacklist_btn); // Attachment of onClickListner for it add_blacklist_btn.setOnClickListener(this); // Initialization of the listview of the Main screen to display black listed phone numbers listview = (ListView) findViewById(R.id.listview); // Set the header of the ListView final LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); final View rowView = inflater.inflate(R.layout.list_item, listview, false); listview.addHeaderView(rowView); // Attach OnItemLongClickListener to track user action and perform accordingly listview.setOnItemLongClickListener(this); } private void populateNoRecordMsg() { // If, no record found in the database, appropriate message needs to be displayed. if(blockList.size() == 0) { final TextView tv = new TextView(this); tv.setPadding(5, 5, 5, 5); tv.setTextSize(15); tv.setText("No Record Found !!"); listview.addFooterView(tv); } } @Override public void onClick(View v) { // Render AddToBlocklistActivity screen once click on "Add" Button if (v == add_blacklist_btn) { startActivity(new Intent(this, AddToBlocklistActivity.class)); } } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { // If the pressed row is not a header, update selectedRecordPosition and // show dialog for further selection if (position > 0) { selectedRecordPosition = position - 1; showDialog(); } return true; } @Override protected void onResume() { super.onResume(); // Initialize the DAO object blackListDao = new BlacklistDAO(this); // Fetch the list of Black listed numbers from Database using DAO object blockList = blackListDao.getAllBlacklist(); // Remove the footer view if(listview.getChildCount() > 1) listview.removeFooterView(listview.getChildAt(listview.getChildCount() - 1)); //Now, link the CustomArrayAdapter with the ListView listview.setAdapter(new CustomArrayAdapter(this, R.layout.list_item, blockList)); // If, no record found in the database, appropriate message needs to be displayed. populateNoRecordMsg(); } private void showDialog() { // Before deletion of the long pressed record, need to confirm with the user. So, build the AlartBox first final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); // Set the appropriate message into it. alertDialogBuilder.setMessage("Are you Really want to delete the selected record ?"); // Add a positive button and it's action. In our case action would be deletion of the data alertDialogBuilder.setPositiveButton("Delete", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { try { blackListDao.delete(blockList.get(selectedRecordPosition)); // Removing the same from the List to remove from display as well blockList.remove(selectedRecordPosition); listview.invalidateViews(); // Reset the value of selectedRecordPosition selectedRecordPosition = -1; populateNoRecordMsg(); } catch (Exception e) { e.printStackTrace(); } } }); // Add a negative button and it's action. In our case, just hide the dialog box alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); // Now, create the Dialog and show it. final AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } public class CustomArrayAdapter extends ArrayAdapter<String> { private LayoutInflater inflater; // This would hold the database objects i.e. Blacklist private List<Blacklist> records; @SuppressWarnings("unchecked") public CustomArrayAdapter(Context context, int resource, @SuppressWarnings("rawtypes") List objects) { super(context, resource, objects); this.records = objects; inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public View getView(int position, View convertView, ViewGroup parent) { //Reuse the view to make the scroll effect smooth if(convertView == null) convertView = inflater.inflate(R.layout.list_item, parent, false); // Fetch phone number from the database object final Blacklist phoneNumber = records.get(position); // Set to screen component to display results ((TextView)convertView.findViewById(R.id.serial_tv)).setText("" + (position +1)); ((TextView)convertView.findViewById(R.id.phone_number_tv)).setText(phoneNumber.phoneNumber); return convertView; } } }
7. AddToBlocklistActivity
This screen performs the addition of new phone number to the black list
AddToBlocklistActivity.java
package com.androidbegin.callblocker; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; public class AddToBlocklistActivity extends Activity implements OnClickListener { // Declaration all on screen components private EditText country_code_et, phone_et; private Button reset_btn, submit_btn; // Declaration of BlacklistDAO to interact with SQlite database private BlacklistDAO blackListDao; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_to_blocklist); // Initialization of the DAO object. blackListDao = new BlacklistDAO(this); country_code_et = (EditText) findViewById(R.id.country_code_et); phone_et = (EditText) findViewById(R.id.phone_et); reset_btn = (Button) findViewById(R.id.reset_btn); submit_btn = (Button) findViewById(R.id.submit_btn); reset_btn.setOnClickListener(this); submit_btn.setOnClickListener(this); } @Override public void onClick(View v) { if(v == submit_btn) { // All input fields are mandatory, so made a check if(country_code_et.getText().toString().trim().length() > 0 && phone_et.getText().toString().trim().length() > 0) { // Once click on "Submit", it's first creates the Blacklist object final Blacklist phone = new Blacklist(); // Then, set all the values from user input phone.phoneNumber = "+" + country_code_et.getText().toString() + phone_et.getText().toString(); // Insert the object to the database blackListDao.create(phone); // Show the success message to user showDialog(); } // Show a dialog with appropriate message in case input fields are blank else { showMessageDialog("All fields are mandatory !!"); } } else if(v == reset_btn) { reset(); } } // Clear the entered text private void reset() { country_code_et.setText(""); phone_et.setText(""); } private void showDialog() { // After submission, Dialog opens up with "Success" message. So, build the AlartBox first final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); // Set the appropriate message into it. alertDialogBuilder.setMessage("Phone Number added to block list successfully !!"); // Add a positive button and it's action. In our case action would be, just hide the dialog box , // and erase the user inputs. alertDialogBuilder.setPositiveButton("Add More", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { reset(); } }); // Add a negative button and it's action. In our case, close the current screen alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); // Now, create the Dialog and show it. final AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } private void showMessageDialog(final String message) { final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); alertDialogBuilder.setMessage(message); final AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } }
8. CallBarring.java
This java class actually does automatic disconnection. It extends the “android.content.BroadcastReceiver” and whenever there is an incoming call to the phone, it fetches the phone number through BroadcastReceiver and if the number matches any of the phone numbers stored in the database, it disconnects automatically.
CallBarring.java
package com.androidbegin.callblocker; import java.lang.reflect.Method; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.telephony.TelephonyManager; import com.android.internal.telephony.ITelephony; // Extend the class from BroadcastReceiver to listen when there is a incoming call public class CallBarring extends BroadcastReceiver { // This String will hold the incoming phone number private String number; @Override public void onReceive(Context context, Intent intent) { // If, the received action is not a type of "Phone_State", ignore it if (!intent.getAction().equals("android.intent.action.PHONE_STATE")) return; // Else, try to do some action else { // Fetch the number of incoming call number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); // Check, whether this is a member of "Black listed" phone numbers stored in the database if(MainActivity.blockList.contains(new Blacklist(number))) { // If yes, invoke the method disconnectPhoneItelephony(context); return; } } } // Method to disconnect phone automatically and programmatically // Keep this method as it is @SuppressWarnings({ "rawtypes", "unchecked" }) private void disconnectPhoneItelephony(Context context) { ITelephony telephonyService; TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); try { Class c = Class.forName(telephony.getClass().getName()); Method m = c.getDeclaredMethod("getITelephony"); m.setAccessible(true); telephonyService = (ITelephony) m.invoke(telephony); telephonyService.endCall(); } catch (Exception e) { e.printStackTrace(); } } }
9. AndroidManifest
Open your AndroidManifest.xml and declare the required activities:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidbegin.callblocker" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".CallBarring"> <intent-filter android:priority="100" > <action android:name="android.intent.action.PHONE_STATE" /> </intent-filter> </receiver> <activity android:name=".AddToBlocklistActivity" android:label="@string/app_name" /> </application> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> </manifest>
Test the App
Now to test the functionality, add a phone number to the blacklist and try to make phone call from the same number. You will see that, the phone is getting disconnected silently (or probably after one small ringing sound).
Known issues
- As, this functionality is purely dependent on the Phone hardware and Android Telephony APIs, there are few phones, which doesn’t respond as expected and fails to disconnect the incoming call.
- For dual SIM phones, it doesn’t work for incoming calls of secondary SIM card (works well for Primary one though).
Source Code
[purchase_link id=”8044″ text=”Purchase to Download Source Code” style=”button” color=”green”]
Dear CodeDrunk Team,Congrats for this great job. Friends, I need 1 more think. I need to take a phone call without do any thing by user. How this autoanswer facility can implement in this code (for not autoblocking numbers). Please advise .. I am looking this for 8 days ..ThanksAnes
Anes P.A
Automatic Call Blocking Using Android Telephony Tutorial
It works in several phones but i am using One Plus X api 23.In my phone it doesn't working. What can i do???
Aurthohin Pavel
Automatic Call Blocking Using Android Telephony Tutorial
how to disconnect call without using ITelephony ? Not able to import ITelephony. android studio is not to resolve ITelephony
Pradeep Kumar Reddy
Automatic Call Blocking Using Android Telephony Tutorial
WORKS PERFECTLY!! THANKS LOT!!....
parakh agarwal
Automatic Call Blocking Using Android Telephony Tutorial