Telephony.Sms.Inbox.PERSON utiliza Contacts.People._ID obsoletos

Premio Bounty – La recompensa se otorgará a una respuesta que obtiene de un valor poblado de Telephony.Sms.Inbox.PERSON , al Contact asociado usando sólo las tablas ContractsContact .

Desde que comencé la recompensa, he resuelto cómo hacer esto, pero pensé que dejaría la recompensa abierta para darle a alguien una oportunidad de ganarla, antes de publicar la solución.


Estoy leyendo mensajes SMS de la manera estándar en mi aplicación:

  final String[] projection = {Telephony.Sms.Inbox.BODY, Telephony.Sms.Inbox.ADDRESS, Telephony.Sms.Inbox.READ, Telephony.Sms.Inbox.DATE, Telephony.Sms.Inbox.PERSON}; final Cursor cursor = ctx.getContentResolver().query(Telephony.Sms.Inbox.CONTENT_URI, projection, null, null, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER); 

Cuando se rellena, el id devuelto desde el índice Telephony.Sms.Inbox.PERSON relaciona con el identificador de la Contacts.People._ID obsoleto y se puede utilizar para consultar información de contacto adicional de la siguiente manera:

  final String[] projection = {Contacts.People.DISPLAY_NAME}; final String[] selectionArgs = {contactId}; final Cursor cursor = ctx.getContentResolver().query(Contacts.People.CONTENT_URI, projection, Contacts.People._ID + " = ?", selectionArgs, null); 

¿Por qué la relativamente nueva API de telefonía utiliza tablas obsoletas , en lugar de ContactsContract ?

La documentación de Telephony.Sms.Inbox.PERSON establece:

Tipo: INTEGER (referencia al elemento en el contenido: // contactos / personas)

He intentado sin éxito (pero no es de esperar?) Para encontrar una asignación a la identificación en cualquiera de los campos de ID ContactsContract , por lo que estoy dejando tener que usar APIs obsoletas con el fin de resolver las consultas que tengo que realizar rápidamente.

Tales consultas incluyen la búsqueda de mensajes por un contacto en particular, para lo cual sólo tengo el nombre. El contacto puede tener varios números, que pueden no estar en el formato correcto para coincidir con las entradas de Telephony.Sms.Inbox.ADDRESS …..

La solución de usar Telephony.Sms.Inbox.ADDRESS y ContactsContract.PhoneLookup no es el fin del mundo cuando va desde el número al contacto, pero sigo sintiendo que debo estar perdiendo algo aquí ?

Este es el proceso que estoy usando para obtener los mensajes de 'Joe Bloggs'.

1) Consulta la tabla ContactsContract para confirmar que existe un contacto con el nombre de Joe Bloggs en el dispositivo o para obtener una coincidencia cercana si el contacto aparece en la lista de ' Blogs de Joe'.

2) Utilizando el nombre confirmado, consulta la tabla de Contact.People obsoleta para obtener todos los identificadores asociados para el contacto de la siguiente manera:

  final String selection = Contacts.People.DISPLAY_NAME + " LIKE ?"; final String[] projection = {Contacts.People.DISPLAY_NAME, Contacts.People._ID}; final String[] selectionArgs = {contactName}; final Cursor cursor = ctx.getContentResolver().query(Contacts.People.CONTENT_URI, projection, selection, selectionArgs, null); 

3) Usando la lista de identificadores de contacto obsoletos, consulta la tabla de mensajes de la siguiente manera:

  final String[] referredArgs = new String[contactIdArray.size()]; for (int i = 0; i < contactIdArray.size(); i++) { referredArgs[i] = contactIdArray.get(i); } final String referredSelection = Telephony.Sms.Inbox.PERSON + " IN " + "(" + TextUtils.join(",", referredArgs) + ")"; final String[] projection = {Telephony.Sms.Inbox.BODY, Telephony.Sms.Inbox.ADDRESS, Telephony.Sms.Inbox.READ, Telephony.Sms.Inbox.DATE, Telephony.Sms.Inbox.PERSON}; final Cursor cursor = ctx.getContentResolver().query(Telephony.Sms.Inbox.CONTENT_URI, projection, referredSelection, null, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER); 

Espero que alguien me diga que voy alrededor de las casas aquí y hay una solución más obvia utilizando las API actuales. No considero iterating la tabla entera del mensaje usando ContactsContract.PhoneLookup una solución optimizada.

Gracias por adelantado.

No usaría el campo Telephony.Sms.Inbox.PERSON , y definitivamente no haría una consulta a las People desaprobadas apis si yo fuera tú. Las People apis habían sido obsoletas durante tanto tiempo que no se puede contar con todos los dispositivos de nuestro allí para apoyar adecuadamente más.

La primera cosa que usted necesita entender es que no hay un acoplamiento uno-a-uno entre los sms y los contactos. Un SMS puede provenir de un número de teléfono sin contacto, un solo contacto, múltiples contactos, una mezcla de contactos y no contactos, identificaciones alfanuméricas e incluso otras opciones más raras.

A continuación, debe leer cuidadosamente el código de stock y cómo maneja un correctamente llamado "Recipient ID" que puede obtener de la colección de SMS, hay una colección llamada canonical-addresses (o canonical-address ) que sirve como una correlación entre un Número de teléfono (o una lista de teléfonos separados por comas) y un identificador de destinatario. El código realiza una sola consulta al iniciar para almacenar en caché toda la tabla en memoria y, a continuación, la utiliza para correlacionar entre los teléfonos y los identificadores de destinatarios.

Aquí está la clase de mapeo

¿Por qué la relativamente nueva API de telefonía utiliza tablas obsoletas, en lugar de ContactsContract?

Lo que usted se está refiriendo no es nuevo. En Telephony.java , verá que se basa en el content://sms existente content://sms proveedor de content://sms :

  public static final class Inbox implements BaseColumns, TextBasedSmsColumns { /** * The {@code content://} style URL for this table. */ public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox"); 

Ya estaba allí en Donut (y probablemente antes, pero no lo hice).

Lo nuevo en Kitkat es la posibilidad de cambiar la aplicación de SMS .

No entiendo su preocupación correctamente, pero estoy trabajando en un proyecto similar, aquí está el código básico, y las columnas básicas, importantes para buscar y mostrar un mensaje:

 ContentResolver contentResolver = getContentResolver(); final String[] projection = new String[]{"*"}; Cursor SMSL = contentResolver.query(Telephony.Sms.CONTENT_URI, projection, null, null, "date ASC"); int msgscount = SMSL.getCount(); if (msgscount>0) { msgs = new String[SMSL.getCount()][msgs_column_count]; int i = 0; while (SMSL.moveToNext()) { progress.setProgress(i); msgs[i][0] = SMSL.getString(SMSL.getColumnIndex("address")); msgs[i][1] = SMSL.getString(SMSL.getColumnIndex("date_sent")); msgs[i][2] = SMSL.getString(SMSL.getColumnIndex("date")); msgs[i][3] = SMSL.getString(SMSL.getColumnIndex("type")); msgs[i][4] = SMSL.getString(SMSL.getColumnIndex("body")); msgs[i][5] = SMSL.getString(SMSL.getColumnIndex("read")); if (SMSL.getString(SMSL.getColumnIndex("service_center")) != null){ msgs[i][6] = SMSL.getString(SMSL.getColumnIndex("service_center")); }else{ msgs[i][6] = ""; } i++; } SMSL.close(); }else{ msgs = new String[0][0]; Toast.makeText(getApplicationContext(),"No messages found!",Toast.LENGTH_LONG).show(); } 

Si desea ayuda con esto o recoja mensajes, avíseme.

  • ¿Cómo puedo instanciar un objeto java utilizando JNI (Delphi)
  • Modo sin conexión Bluetooth en Android
  • ¿Puedo obtener la cantidad de memoria que queda para mi programa?
  • Android: ¿Dónde poner el código onCreate () de la actividad en un fragmento?
  • Cómo crear un setter personalizado de plantillas Intellij para su uso con Guava
  • Cómo hacer referencia a un archivo en carpeta sin procesar en Android
  • Libgdx se bloquea en Android
  • Al almacenar en caché las imágenes y los datos debe utilizar almacenamiento interno o externo?
  • No se puede leer / escribir en sdcard en Android
  • Biblioteca Json Parsing Gson de Google: ¿Cuál es la diferencia entre JsonElement y JsonObject?
  • Experiencia con Vaadin touchkit
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.