I'm writing an application that:
Intercepts an outgoing call
Shows a dialog asking whether the call is "personal" or "business" ("Aziendale" in italian)
- If "personal", makes the call with the given number
- If "business", prepends a suffix to the number (for example 4888 - just temporarily in my code)
The point is: as I don't know how to make the call wait for the user's choice, I:
Close the incoming call with
setResultData(null)
Show an alert dialog
After user press one button make the call
But, when it's time to make the call, nothing happens.
Let me describe the classes of my application:
MainActivity
(standard self-created activity for now without any function - will improve when calls work)OutgoingCallReceiver
(the class that extendsBroadcastReceiver
- intercept the outgoing calls)AlertActivity
(themed as an alert dialog, show the alert)CallActivity
(called byAlertActivity
- should make the call)
The manifest file is:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.simplecall"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<receiver android:name="OutgoingCallReceiver" >
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name="com.example.simplecall.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>
<activity
android:name="com.example.simplecall.AlertActivity"
android:theme="@android:style/Theme.Dialog" >
</activity>
<activity
android:name="com.example.simplecall.CallActivity" >
</activity>
</application>
</manifest>
Here is how I coded my classes:
MainActivity
:
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
String numero;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
OutgoingCallReceiver
:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class OutgoingCallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// il numero che si stava per chiamare
final String numero = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Intent in = new Intent(context,AlertActivity.class);
in.putExtra("com.example.simplecall.numero", numero);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
setResultData(null);
context.startActivity(in);
//Toast toast = Toast.makeText(context, "Chiamata verso: " + numero, 1500);
//toast.show();
}
}
AlertActivity
:
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.widget.Toast;
public class AlertActivity extends Activity {
String numero;
Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
numero = getIntent().getStringExtra("com.example.simplecall.numero");
Toast toast = Toast.makeText(this, "numero : " + numero, 5000);
toast.show();
showSettingsAlert();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* Mostra una finestra di dialogo
* Cliccando su Impostazioni si accede al menù di configurazione
* */
public void showSettingsAlert(){
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
// Titolo della finestra
alertDialog.setTitle("Tipo di chiamata");
// Mostra l'avvertimento
alertDialog.setMessage("Che tipo di chiamata effettuare?");
// Cliccando su Impostazioni ...
alertDialog.setPositiveButton("Aziendale", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
numero = "tel:4888"+numero;
/*
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse(numero));
//dialog.dismiss();
startActivity(callIntent);
*/
Intent in = new Intent(mContext,CallActivity.class);
in.putExtra("com.example.simplecall.numero", numero);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(in);
dialog.dismiss();
finish();
}
});
// Cliccando su Personale
alertDialog.setNegativeButton("Personale", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
numero = "tel:" + numero;
/*
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse(numero));
//dialog.dismiss();
startActivity(callIntent);
*/
Intent in = new Intent(mContext,CallActivity.class);
in.putExtra("com.example.simplecall.numero", numero);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(in);
dialog.dismiss();
finish();
}
});
// Mostra la finestra di alert
alertDialog.show();
}
private void makeCall(String number, DialogInterface dial) {
dial.dismiss();
try {
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:"+number));
startActivity(callIntent);
finish();
} catch (ActivityNotFoundException activityException) {
activityException.printStackTrace();
}
}
}
CallActivity
:
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
public class CallActivity extends Activity
{
String numero;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
numero = getIntent().getStringExtra("com.example.simplecall.numero");
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse(numero));
//finish();
startActivity(callIntent);
}
}
But the problem is that when I instantiate CallActivity
nothing happens ... any hints?
I created a new "application", just for testing if i'm doing all in the correct way, same permissions in the manifest file, but it have just a standard self created activity where i perform
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:xxx")); // xxx is a real number in the code
finish();
startActivity(callIntent);
and all works fine, don't understand where i fail.
I also noticed that if for any reason the application crash after pushing one of the two buttons(for example, if i make the call onDestroy() without calling the super.ondestroy()) , the call is correctly performed
The problem is actually quite simple once you figure it out.. You have a broadcast receiver for outgoing calls, which intercepts them and shows your dialog. After you choose if the call is private or business, you place the call with the modified number...and guess who intercepts the call? Your broadcast receiver, and so the loop goes. Tho prevent this infinite loop, the only way I know of, is to disable the broadcast receiver before placing the modified call, and enabling it again after the call ends.
I hope I was of help!
It is possible to intercept the outgoing call, and make alterations using specific BroadcastReceiver. See this entry from Android developer blog.
Now, the issue is BroadcastReceivers need to process it immediately. Here, we don't know how much time user is taking to respond to dialog.
As shown in example from blog entry above, cancel the broadcast, show dialog and dial after user responds. But this time, place an extra flag in intent, that this call has been already processed, so your BroadcastReceivers doesn't process it next time.