¿Cómo eliminar un SMS de la bandeja de entrada en Android mediante programación?

98

En los teléfonos Android, los mensajes SMS registrados en las aplicaciones también se envían a la bandeja de entrada del dispositivo. Sin embargo, para evitar el desorden, sería bueno poder eliminar los mensajes SMS específicos de la aplicación de la bandeja de entrada para reducir el desbordamiento potencial de esos mensajes.

Las preguntas sobre otros grupos de Google sobre cómo obtener una respuesta definitiva sobre una forma programática de eliminar mensajes SMS de la bandeja de entrada de Android no parecen ser urgentes.

Entonces el escenario:

  • Inicio de la aplicación Android.
  • registrar los tipos de mensajes SMS X, Y y Z
  • los mensajes P, Q, X, Y, Z se transmiten a lo largo del tiempo, todos depositados en la bandeja de entrada
  • La aplicación de Android detecta la recepción de X, Y, Z (presumiblemente como parte del evento de interrupción del programa)
  • proceso X, Y, Z
  • Deseo !!! X, Y, Z se eliminan de la bandeja de entrada de Android

¿Se ha hecho? Se puede hacer?

dmyung
fuente
4
He descubierto que hacer algo útil con las capacidades telefónicas de Android es una experiencia muy desagradable.
BobbyShaftoe
1
buena pregunta amigo. Estaba buscando algo similar: D cheers
Harsha MV
3
Lo mejor sería evitar que los SMS lleguen a la bandeja de entrada en primer lugar: stackoverflow.com/questions/1741628/…
Christopher Orr

Respuestas:

87

"A partir de Android 1.6, las transmisiones de mensajes SMS entrantes ( android.provider.Telephony.SMS_RECEIVED) se entregan como una" transmisión ordenada ", lo que significa que puede decirle al sistema qué componentes deben recibir la transmisión primero".

Esto significa que puede interceptar el mensaje entrante y cancelar su transmisión más adelante.

En su AndroidManifest.xmlarchivo, asegúrese de tener la prioridad establecida en la más alta:

<receiver android:name=".receiver.SMSReceiver" android:enabled="true">
    <intent-filter android:priority="1000">
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

En su BroadcastReceiver, en onReceive()método, antes de realizar cualquier cosa con su mensaje, simplemente llameabortBroadcast();

EDITAR: A partir de KitKat, aparentemente esto ya no funciona.

EDIT2: Más información sobre cómo hacerlo en KitKat aquí:

Eliminar SMS de Android en 4.4.4 (filas afectadas = 0 (cero), después de eliminarlas)

Viktor Fonic
fuente
3
Y asegúrese de ver stackoverflow.com/questions/1741628/…
Michael Levy
¿Puedes ver aquí stackoverflow.com/questions/25988574/… ?
Gangadhar Nimballi
La mejor respuesta para esto = D
Mike Brian Olivera
27

Usando sugerencias de otros, creo que lo hice funcionar:

(usando SDK v1 R2)

No es perfecto, ya que necesito eliminar toda la conversación, pero para nuestros propósitos, es un compromiso suficiente ya que al menos sabremos que todos los mensajes serán revisados ​​y verificados. Nuestro flujo probablemente necesitará escuchar el mensaje, capturar el mensaje que queremos, hacer una consulta para obtener el thread_id del mensaje recién ingresado y hacer la llamada delete ().

En nuestra Actividad:

Uri uriSms = Uri.parse("content://sms/inbox");
Cursor c = getContentResolver().query(uriSms, null,null,null,null); 
int id = c.getInt(0);
int thread_id = c.getInt(1); //get the thread_id
getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id),null,null);

Nota: No pude eliminar contenido: // sms / inbox / o content: // sms / all /

Parece que el hilo tiene prioridad, lo cual tiene sentido, pero el mensaje de error solo me animó a estar más enojado. Cuando intente eliminar en sms / inbox / o sms / all /, probablemente obtendrá:

java.lang.IllegalArgumentException: Unknown URL
    at com.android.providers.telephony.SmsProvider.delete(SmsProvider.java:510)
    at android.content.ContentProvider$Transport.delete(ContentProvider.java:149)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:149)

También para referencia adicional, asegúrese de poner esto en su manifiesto para su receptor de intención:

<receiver android:name=".intent.MySmsReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
    </intent-filter>
</receiver>

Tenga en cuenta que la etiqueta del receptor no se ve así:

<receiver android:name=".intent.MySmsReceiver" 
    android:permission="android.permission.RECEIVE_SMS">

Cuando tuve esa configuración, Android me dio algunas excepciones de permisos locas que no permitían que android.phone entregara los SMS recibidos a mi intención. Por lo tanto, ¡NO ponga ese atributo de permiso RECEIVE_SMS en su intención! Ojalá alguien más sabio que yo pueda decirme por qué fue así.

dmyung
fuente
¿Puedes ver aquí stackoverflow.com/questions/25988574/… ?
Gangadhar Nimballi
24

Entonces, tuve una jugada y es posible eliminar un SMS recibido. Desafortunadamente, no todo es sencillo :(

Tengo un receptor que recibe los mensajes SMS entrantes. Ahora, la forma en que funciona el enrutamiento entrante de SMS de Android es que el fragmento de código responsable de decodificar los mensajes envía una transmisión (utiliza el sendBroadcast()método, que desafortunadamente NO es la versión que le permite simplemente llamar abortBroadcast()) cada vez que llega un mensaje.

Mi receptor puede o no ser llamado antes que el receptor de SMS de Systems y, en cualquier caso, la transmisión recibida no tiene ninguna propiedad que pueda reflejar la _idcolumna en la tabla de SMS.

Sin embargo, al no ser alguien que pueda ser detenido tan fácilmente, me publico (a través de un controlador) un mensaje retrasado con el SmsMessage como objeto adjunto. (Supongo que también podrías publicar un Runnable ...)

handler.sendMessageDelayed(handler.obtainMessage(MSG_DELETE_SMS, msg), 2500);

La demora está ahí para asegurar que para cuando llegue el mensaje, todos los receptores de transmisión habrán terminado sus cosas y el mensaje estará instalado de manera segura en la mesa de SMS.

Cuando se recibe el mensaje (o Runnable), esto es lo que hago:

case MSG_DELETE_SMS:
    Uri deleteUri = Uri.parse("content://sms");
    SmsMessage msg = (SmsMessage)message.obj;

    getContentResolver().delete(deleteUri, "address=? and date=?", new String[] {msg.getOriginatingAddress(), String.valueOf(msg.getTimestampMillis())});

Utilizo la dirección de origen y el campo de marca de tiempo para garantizar una probabilidad muy alta de eliminar SOLO el mensaje que me interesa. Si quisiera ser aún más paranoico, podría incluir el msg.getMessageBody()contenido como parte de la consulta.

Sí, el mensaje ES eliminado (¡hurra!). Desafortunadamente, la barra de notificaciones no está actualizada :(

Cuando abras el área de notificación, verás el mensaje allí para ti ... pero cuando lo toques para abrirlo, ¡desaparecerá!

Para mí, esto no es lo suficientemente bueno; quiero que desaparezca todo rastro del mensaje; no quiero que el usuario piense que hay un TXT cuando no lo hay (eso solo causaría informes de errores).

Internamente, en el sistema operativo, el teléfono llama MessagingNotification.updateNewMessageIndicator(Context), pero esa clase se ha ocultado a la API, y no quería replicar todo ese código solo para que el indicador sea preciso.

Doug
fuente
Doug, esto es genial. A modo de pregunta, ¿sabes si es necesario hacerle el post al Handler? Me pregunto si el SMS se inserta en la base de datos de SMS del sistema antes y se llama a los receptores de difusión. Probablemente tendré que buscar en el sistema operativo para ver dónde ocurre la inserción, pero supongo que la inserción del SMS en alguna base de datos ocurre antes de que se informe a los receptores de transmisión. ¿Tiene alguna idea de esto o ya lo comprobó?
Hamy
¿Puedes ver aquí stackoverflow.com/questions/25988574/… ?
Gangadhar Nimballi
11
public boolean deleteSms(String smsId) {
    boolean isSmsDeleted = false;
    try {
        mActivity.getContentResolver().delete(Uri.parse("content://sms/" + smsId), null, null);
        isSmsDeleted = true;

    } catch (Exception ex) {
        isSmsDeleted = false;
    }
    return isSmsDeleted;
}

use este permiso en AndroidManifiest

<uses-permission android:name="android.permission.WRITE_SMS"/>
Atif Mahmood
fuente
1
¿Cómo obtenemos la identificación de SMS?
Dev01
sabiduríaitsol.com
Atif Mahmood
@ Dev01si desea eliminar un sms en particular, debe tener su identificación, ¿verdad? y si no, debe consultar la identificación con la dirección o smsbody
Dr. aNdRO
6

Es mejor usar _id y thread_id para eliminar un mensaje.

Thread_id es algo que se asigna a los mensajes que provienen del mismo usuario. Entonces, si usa solo thread_id, todos los mensajes del remitente serán eliminados.

Si usa la combinación de _id, thread_id, entonces se eliminará el mensaje exacto que desea eliminar.

Uri thread = Uri.parse( "content://sms");
int deleted = contentResolver.delete( thread, "thread_id=? and _id=?", new String[]{String.valueOf(thread_id), String.valueOf(id)} );
Naresh Kavali
fuente
¿Puedes ver aquí stackoverflow.com/questions/25988574/… ?
Gangadhar Nimballi
5

Deberá encontrar el URI del mensaje. Pero una vez que lo haga, creo que debería poder android.content.ContentResolver.delete (...) it.

Aquí hay más información .

Neil
fuente
2

Creo que esto no se puede hacer perfectamente por el momento. Hay 2 problemas básicos:

  1. ¿Cómo puede asegurarse de que el sms ya esté en la bandeja de entrada cuando intenta eliminarlo?
    Tenga en cuenta que SMS_RECEIVED no es una transmisión ordenada.
    Así que la solución de dmyung es probar suerte por completo; incluso la demora en la respuesta de Doug no es una garantía.

  2. El SmsProvider no es seguro para subprocesos (consulte http://code.google.com/p/android/issues/detail?id=2916#c0 )
    El hecho de que más de un cliente soliciten eliminarlo e insertarlo en el Al mismo tiempo, se producirán daños en los datos o incluso una excepción de tiempo de ejecución inmediata.

an0
fuente
2

No pude hacer que funcionara usando la solución de dmyung, me dio una excepción al obtener la identificación del mensaje o la identificación del hilo.

Al final, utilicé el siguiente método para obtener la identificación del hilo:

private long getThreadId(Context context) {
    long threadId = 0;

    String SMS_READ_COLUMN = "read";
    String WHERE_CONDITION = SMS_READ_COLUMN + " = 0";
    String SORT_ORDER = "date DESC";
    int count = 0;

    Cursor cursor = context.getContentResolver().query(
                    SMS_INBOX_CONTENT_URI,
          new String[] { "_id", "thread_id", "address", "person", "date", "body" },
                    WHERE_CONDITION,
                    null,
                    SORT_ORDER);

    if (cursor != null) {
            try {
                count = cursor.getCount();
                if (count > 0) {
                    cursor.moveToFirst();
                    threadId = cursor.getLong(1);                              
                }
            } finally {
                    cursor.close();
            }
    }


    return threadId;
}

Entonces podría borrarlo. Sin embargo, como dijo Doug, la notificación sigue ahí, incluso el mensaje se muestra al abrir el panel de notificaciones. Solo al tocar el mensaje pude ver que estaba vacío.

Así que supongo que la única forma en que esto funcionaría sería interceptar de alguna manera el SMS antes de que se entregue al sistema, incluso antes de que llegue a la bandeja de entrada. Sin embargo, dudo mucho que esto sea factible. Por favor corrígeme si estoy equivocado.

Stelian Iancu
fuente
Bueno, usted está equivocado acerca de la interceptación de los mensajes antes de que la bandeja de entrada: puede recibir una emisión android.provider.Telephony.SMS_RECEIVED, sólo es necesario un android.permission.RECEIVE_SMS permssion. Incluso puede evitar fácilmente que el mensaje llegue a la bandeja de entrada llamando a abortBroadcast () ya que es una transmisión ordenada. PD Debe ser divertido para ser corregido 2 años después :)
lapis
2

Utilice esta función para eliminar un hilo de mensajes específico o modificarlo según sus necesidades:

public void delete_thread(String thread) 
{ 
  Cursor c = getApplicationContext().getContentResolver().query(
  Uri.parse("content://sms/"),new String[] { 
  "_id", "thread_id", "address", "person", "date","body" }, null, null, null);

 try {
  while (c.moveToNext()) 
      {
    int id = c.getInt(0);
    String address = c.getString(2);
    if (address.equals(thread)) 
        {
     getApplicationContext().getContentResolver().delete(
     Uri.parse("content://sms/" + id), null, null);
    }

       }
} catch (Exception e) {

  }
}

Llame a esta función simplemente a continuación:

delete_thread("54263726");//you can pass any number or thread id here

No olvide agregar el permiso principal de Android a continuación:

<uses-permission android:name="android.permission.WRITE_SMS"/>
Ashish Sahu
fuente
1

Simplemente apague las notificaciones de la aplicación de SMS predeterminada. ¡Procese sus propias notificaciones para todos los mensajes de texto!

Noah Seidman
fuente
1

Solo prueba el siguiente código, eliminará todos los sms que están en el teléfono (Recibidos o Enviados)

Uri uri = Uri.parse("content://sms");

ContentResolver contentResolver = getContentResolver();

Cursor cursor = contentResolver.query(uri, null, null, null,
  null);



while (cursor.moveToNext()) {

 long thread_id = cursor.getLong(1);
 Uri thread = Uri.parse("content://sms/conversations/"
   + thread_id);
 getContentResolver().delete(thread, null, null);
}
Rajamohan Sugumaran
fuente
1

También actualice el archivo de manifiesto para eliminar un sms que necesita permisos de escritura.

<uses-permission android:name="android.permission.WRITE_SMS"/>
Wasif Kirmani
fuente
1

Ahora abortBroadcast();se puede usar el método para restringir que el mensaje entrante vaya a la bandeja de entrada.

Arun Badole
fuente
0

Ejemplo para eliminar un SMS, no una conversación:

getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadID), "_id = ?", new String[]{id});
embo
fuente
0
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    SMSData sms = (SMSData) getListAdapter().getItem(position);
    Toast.makeText(getApplicationContext(), sms.getBody(),
            Toast.LENGTH_LONG).show();
    Toast.makeText(getApplicationContext(), sms.getNumber(),
            Toast.LENGTH_LONG).show();

    deleteSms(sms.getId());

}

public boolean deleteSms(String smsId) {
    boolean isSmsDeleted = false;
    try {
        MainActivity.this.getContentResolver().delete(
                Uri.parse("content://sms/" + smsId), null, null);
        isSmsDeleted = true;

    } catch (Exception ex) {
        isSmsDeleted = false;
    }
    return isSmsDeleted;
}
sharma_kunal
fuente
0

Pruebe esto, estoy 100% seguro de que esto funcionará bien: - // simplemente coloque la dirección de conversión aquí para eliminar toda la conversión por dirección (no se olvide de agregar el permiso de lectura y escritura en mainfest) Aquí está el código:

String address="put address only";

Cursor c = getApplicationContext().getContentResolver().query(Uri.parse("content://sms/"), new String[] { "_id", "thread_id", "address", "person", "date", "body" }, null, null, null);

try {
    while (c.moveToNext()) {
        int id = c.getInt(0);
        String address = c.getString(2);
        if(address.equals(address)){
        getApplicationContext().getContentResolver().delete(Uri.parse("content://sms/" + id), null, null);}
    }
} catch(Exception e) {

}
Ashish Sahu
fuente
0

Utilice uno de estos métodos para seleccionar el último SMS recibido y eliminarlo, aquí, en este caso, obtengo la mayoría de los SMS principales y voy a eliminar usando el hilo y el valor de identificación de sms,

try {
    Uri uri = Uri.parse("content://sms/inbox");
    Cursor c = v.getContext().getContentResolver().query(uri, null, null, null, null);
    int i = c.getCount();

    if (c.moveToFirst()) {
    }
} catch (CursorIndexOutOfBoundsException ee) {
    Toast.makeText(v.getContext(), "Error :" + ee.getMessage(), Toast.LENGTH_LONG).show();
}
Pir Fahim Shah
fuente