Outgoing call don't start

2019-07-21 06:52发布

问题:

I'm writing an application that:

  1. Intercepts an outgoing call

  2. 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:

  1. Close the incoming call with setResultData(null)

  2. Show an alert dialog

  3. 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 extends BroadcastReceiver - intercept the outgoing calls)

  • AlertActivity (themed as an alert dialog, show the alert)

  • CallActivity (called by AlertActivity - 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

回答1:

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.

private void makeCall1(String number)  {
    PackageManager pm = mContext.getPackageManager();
    ComponentName componentName = new ComponentName(mContext, OutgoingCallReceiver.class);
    pm.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
    Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse(number));
    startActivity(callIntent);
    // Now wait for the call to end somehow and afterwards ->
    // pm.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}

I hope I was of help!



回答2:

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.