2010-07-14 21 views
8

Actualmente estoy desarrollando una aplicación que captura la acción NEW_OUTGOING_CALL con la ayuda de BroadcastReceiver. Estoy cancelando la llamada llamando al setResultData(null). Después de eso, le mostraré al usuario un cuadro de diálogo que le permite decidir si quiere usar mi aplicación para reescribir su número. Cuando ha ocurrido la decisión de los usuarios, realizo la nueva llamada según la decisión. Ahora mi receptor de radiodifusión es llamado una vez más.¿Cuál es la forma correcta de manejar la acción NEW_OUTGOING_CALL mientras buclea?

¿Cuál es la forma correcta de saber que ya he procesado el número? Obtuve una solución de trabajo que usa una marca de tiempo para adivinar si ya podría procesarse. Otra solución sería agregar un "+" al final del número procesado. Estos métodos funcionan bien para que mi aplicación sea la única que capture el evento NEW_OUTGOING_CALL. Pero, ¿qué debo hacer cuando otras aplicaciones (como Sipdroid o Google Voice) también están ahí esperando la transmisión NEW_OUTGOING_CALL abortándola y reiniciándola nuevamente? No veo la posibilidad de saber si todavía estamos en el mismo "flujo de llamadas" y si ya procesé el número.

¡Me encantaría conocer sus ideas sobre este problema!

+0

duplicado: http://stackoverflow.com/q/808645/165674 –

Respuesta

2

¿Con qué nivel de API estás trabajando? Si es> = 11, consulte la nueva función BroadcastReceiver.goAsync que le permite extender el procesamiento de la transmisión fuera de la función onReceive de su receptor. Esto podría pasar por alto la necesidad de unir por completo.

Si, como yo, estás atrapado tratando de hacer esto antes del nivel 11, es sorprendentemente complicado hacerlo con elegancia. También puede haber hecho esto, pero traté de incluir una bandera "procesada" como extra en el intento de ACTION_CALL generado por mi código, con la esperanza de que de alguna manera se incluyera en la transmisión ACTION_NEW_OUTGOING_CALL resultante, pero lamentablemente eso no funciona.

La mejor solución que he podido encontrar es incluir un fragmento en el URI para el intento de ACTION_CALL que generas. Este fragmento se incluirá para la transmisión ACTION_NEW_OUTGOING_CALL resultante, por lo que su receptor de difusión puede diferenciar entre la llamada original y la que genera, pero no interferirá con los controladores que no la estén buscando.

Aquí está el código básico.

En su BroadcastReceiver para la ACTION_NEW_OUTGOING_CALL

public class YourBroadcastReceiver extends BroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     // extract the fragment from the URI 
     String uriFragment = Uri.parse(
      intent.getStringExtra("android.phone.extra.ORIGINAL_URI")).getFragment(); 

     // if the fragment is missing or does not have your flag, it is new 
     if (uriFragment == null || !uriFragment.contains("your_flag")) { 

      // launch your activity, pass the phone number, etc. 
      // use getResultData to get the number in order to respect 
      // earlier broadcast receivers 
      ... 

      // abort the broadcast 
      this.setResultData(null); 
      this.abortBroadcast(); 
     } 
     // otherwise, your code is there, this call was triggered by you 
     else { 
      // unless you have a special need, you'll probably just let the broadcast 
      // go through here 

      // note that resultData ignores the fragment, so other receivers should 
      // be blissfully unaware of it 
     } 
    } 
} 

Cuando el primer usuario marca el número, el fragmento, o bien faltar por completo o su bandera no estará presente, por lo que abortar la emisión y puesta tu actividadEn su actividad, si decide realizar la llamada de nuevo, hacer algo como lo siguiente:

startActivity(new Intent(Intent.ACTION_CALL, 
         Uri.parse("tel:" + modified_number + "#your_flag"))); 

El fragmento "your_flag" A continuación tendrá presente en la posterior emisión NEW_OUTGOING_CALL y por lo tanto permite que usted resuelva este caso de manera diferente en tu receptor de emisión

Lo bueno de esto es que el fragmento se ignora por completo a menos que lo busque en ORIGINAL_URI, por lo que otros receptores de difusión pueden seguir funcionando. Si quieres ser realmente agradable, puedes buscar un fragmento existente y agregarle tu bandera (quizás con un separador de coma).

Espero que ayude. ¡Buena suerte!

+1

¿Es significativo el hash #? cuando analiza el URI para el nuevo intento de llamada "#your_flag" – scottyab

1

no veo la posibilidad de llegar a saber si estamos todavía en el mismo "llamar flujo" y si ya se procesó el número .

Técnicamente, no está en el mismo "flujo de llamadas" ya que la realización de una nueva llamada es asincrónica. Debe usar sugerencias (como una marca de tiempo) como parece estar haciendo ya.

Si está seguro de que otras aplicaciones no reescribirán el número, excepto para cambiar el prefijo o agregar un sufijo, es posible que desee agregar otra sugerencia de "verificación de proximidad" para evitar falsos positivos/negativos, pero me temo eso es todo lo que puedes hacer.

+0

Gracias por su comentario. –

0

El método onReceive() en el receptor de difusión recibe un intento como argumento. Extraiga el paquete de la intención usando Intent.getExtras(). Este paquete contiene 3 pares de valores clave de la siguiente manera:

  1. android.phone.extra.ALREADY_CALLED = null
  2. android.intent.extra.PHONE_NUMBER = 98xxxxxx98
  3. android.phone.extra. ORIGINAL_URI = tel: 98xxxxxx98

98xxxxxx98 es el número marcado por el usuario.

Cuando el OnReceive() se llama de nuevo, este número cambia a 98xxxxxx98 * o 0 * Al marcar el asterisco (*) al final del número marcado, se puede inferir si el OnReceive() se llama al método por primera vez o las siguientes veces posteriores.

0

Una de las respuestas sería rastrear el booleano extra en el intento. Se realiza de manera similar con la aplicación Google Phone. Puede consultar este BroadcastReceiver here (busque el uso ya canonizado)

La otra forma sería simplemente pasar ese número "reescrito" de su transmisión al siguiente receptor de transmisión más adelante (puede ser cualquier aplicación, como Sipdroid, Google Voz, o aplicación de VoIP personalizada) sin llamar a ACTION_CALL intento (es por eso que obtienes loop y tu receptor de broadcast vuelve a llamar) El siguiente código es un ejemplo de cómo manejo la llamada en mi aplicación de VoIP personalizada. Cuando intercepto NEW_OUTGOING_CALL en mi receptor de difusión, primero compruebo si hay conexión a Internet. Si el teléfono está conectado a internet, utilizo la acción de intención definida personalizada de mi actividad para realizar llamadas a través de mi aplicación VoIP. Si no hay conexión a Internet, simplemente configuro el número de teléfono original para los datos del resultado del receptor de difusión. Esto es utilizado por el próximo receptor de difusión (probablemente la aplicación de teléfono predeterminada, pero no tiene que serlo) en el flujo para hacer una llamada.

public class BHTTalkerCallReceiver extends BroadcastReceiver { 

    private static final String TAG = "BHTTalkerCallReceiver"; 

    @Override 
    public void onReceive(Context context, Intent intent) { 

     Log.d(TAG, "Broadcast successfull ... "); 

     // Extract phone number reformatted by previous receivers 
     String phoneNumber = getResultData(); 
     if (phoneNumber == null) { 
      // No reformatted number, use the original 
      phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); 
     } 

     if (isNetworkAvailable(context)) { // Make sure this app handles call only if there is internet connection 
      // My app will bring up the call, so cancel the broadcast 
      setResultData(null); 
      // Start my app to bring up the call 
      Intent voipCallIntent = new Intent(context, TalkerActivity.class); 
      voipCallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      voipCallIntent.putExtra(TalkerActivity.OUT_CALL_NUMBER, phoneNumber); 
      voipCallIntent.setAction(TalkerActivity.BHT_TALKER_OUT_CALL); 
      context.startActivity(voipCallIntent); 
     } else { //otherwise make a regular call... 
      // Forward phone data to standard phone call 
      setResultData(phoneNumber); 
     } 
    } 

    private boolean isNetworkAvailable(final Context context) { 
     final ConnectivityManager connectivityManager = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)); 
     return connectivityManager.getActiveNetworkInfo() != null && connectivityManager.getActiveNetworkInfo().isConnected(); 
    } 
} 
Cuestiones relacionadas