I have read here
https://gist.github.com/ftvs/e61ccb039f511eb288ee
It works fine for me. Android version 5.0.
My task had consisted next.
My application must observer all calls events. And distinguish incoming, outgoing calls. Any time when the incoming call has finished it must create the new outgoing call. Phone number specified in settings number. This phone number is the number of gate controller. (https://www.pal-es.com/3g-eng)
It is cheating for opening automatic gates for users, not in the whitelist. This application works into a standalone smartphone and is used decided for this task only.
And some features you can find here too.
For example:
- how update textView value from Runnable thread
- I make outgoing
call not from BroadcastReceiver class, because it impossible. It
need make from MainActivity. Havy fun))) Try it.
MainActivity.java
package com.example.root.test02;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
https://androidexample.com/Introduction_To_Broadcast_Receiver_Basics/index.php?view=article_discription&aid=60&aaid=85
https://androidexample.com/Incomming_Phone_Call_Broadcast_Receiver__-_Android_Example/index.php?view=article_discription&aid=61
https://stackoverflow.com/questions/5990590/how-to-detect-phone-call-broadcast-receiver-in-android
https://stackoverflow.com/questions/1083527/how-to-block-calls-in-android
https://stackoverflow.com/questions/5571249/how-do-i-retrieve-the-incoming-phone-calls-number-while-ringing-and-store-it-in
https://gist.github.com/ftvs/e61ccb039f511eb288ee
*/
public class MainActivity extends AppCompatActivity {
public TextView textView;
public String MetallurgTelNumber = "+79091112233"; // need redirect calls to this phone number
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PhonecallReceiver rv = new PhonecallReceiver();
Thread myThread = new Thread(myRunnable);
myThread.start();
textView = (TextView) findViewById(R.id.incoming_calls_log);
textView.setText("Журнал входящих звонков:");
TextView version = (TextView) findViewById(R.id.tvVersion);
version.setText("v3.0");
}
public void CallToMetallurgGates()
{
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:" + MetallurgTelNumber));
startActivity(callIntent);
}
Runnable myRunnable = new Runnable() {
@Override
public void run()
{
while (true)
{
try
{
Thread.sleep(50); // Waits for 1 second (1000 milliseconds)
if (MyProperties.getInstance().NewIncomingCall)
{
CallToMetallurgGates();
MyProperties.getInstance().NewIncomingCall = false;
MyProperties.getInstance().CallId++;
String dbg_str = Integer.toString(MyProperties.getInstance().CallId) + " " + MyProperties.getInstance().PhoneNumber;
textView.post(new Runnable() {
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
String currentDateandTime = sdf.format(new Date());
textView.append("\n" + currentDateandTime);
textView.append("\n(" + Integer.toString(MyProperties.getInstance().CallId) + "): " + MyProperties.getInstance().PhoneNumber);
textView.append("\nЗвоню на ворота: " + MetallurgTelNumber);
}
});
Thread.sleep(5000); // Waits for 1 second (1000 milliseconds)
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
}
PhonecallReceiver.java
package com.example.root.test02;
import java.util.Date;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.util.Date;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import com.example.root.test02.MainActivity;
public class PhonecallReceiver extends BroadcastReceiver {
// как только происходит входящий звонок
protected void onIncomingCallStarted(Context ctx, String number, Date start) {
Log.d("onIncomingCallStarted",number);
}
// как только снимается (hook off) трубка и делается исходящий
protected void onOutgoingCallStarted(Context ctx, String number, Date start) {
Log.d("onOutgoingCallStarted",number);
}
// когда нажимается кнопка Завершить на входящем звонке
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) {
Log.d("onIncomingCallEnded",number);
MyProperties.getInstance().NewIncomingCall = true;
MyProperties.getInstance().PhoneNumber = number + " завершенный";
}
// когда нажимается кнопка Завершить на исходящем звонке
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) {
Log.d("onOutgoingCallEnded",number);
}
// когда не сняли трубку при входящем звонке (пропуск звонка)
protected void onMissedCall(Context ctx, String number, Date start) {
MyProperties.getInstance().NewIncomingCall = true;
MyProperties.getInstance().PhoneNumber = number + " пропущенный";
}
//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, savedNumber, 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;
}
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
public void onReceive(Context context, Intent intent) {
//We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number.
if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
}
else{
String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
state = TelephonyManager.CALL_STATE_IDLE;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
state = TelephonyManager.CALL_STATE_OFFHOOK;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
state = TelephonyManager.CALL_STATE_RINGING;
}
onCallStateChanged(context, state, number);
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.root.test02">
**<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.CALL_PHONE" />**
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
**<receiver android:name="com.example.root.test02.PhonecallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>**
</application>
</manifest>
MyProperties.java
package com.example.root.test02;
public class MyProperties {
private static MyProperties mInstance= null;
public boolean NewIncomingCall = false;
public int CallId = 0;
public String PhoneNumber = "";
protected MyProperties(){}
public static synchronized MyProperties getInstance() {
if(null == mInstance){
mInstance = new MyProperties();
}
return mInstance;
}
}