2016-12-20 2 views
1

La situation: J'ai ajouté une action personnalisée à un contact dans Android en suivant les instructions dans this question et le related sample app on GitHub. Lorsque je suis pressé, je veux composer ce contact dans mon application. Je suis en mesure de récupérer le contact dans l'activité qui est ouverte lorsque l'action personnalisée est activée.Comment récupérer les numéros de téléphone d'un contact en cliquant sur un champ personnalisé dans l'application Contacts native d'Android?

J'exécute ceci:

Cursor cursor = context.getContentResolver().query(data, null, null, null, null); 
if (cursor != null) { 
    newIntent = true; 
    contact = LocalContactAsync.getContacts(cursor, context.getContentResolver()).get(0); 
    cursor.close(); 
} 

Et le data je récupère d'Android est:

contenu: //com.android.contacts/data/2849

Avis le numéro 2849 à la fin, ce n'est pas l'ID natif du contact. L'ID natif du contact est 459. Je suis en mesure de récupérer avec succès le contact d'exécuter cette requête, les déclarations de données suivantes:

cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID); 

-Retours de 2849 '

cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)) ; 

-Retours 'échantillon samplee' Wich est correct

Mais bien que cela soit vrai:

cursor.getInt(cur.getColumnIndex(
      ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) 

La fonction suivante renvoie un curseur vide:

Cursor pCur = cr.query(
       ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 
       null, 
       ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", 
       new String[]{id}, null); 

-id = 2849 dans ce cas, mais si je remplir 459 je récupère la bonne quantité de numéros de téléphone

Le vrai contact a 3 chiffres, il devrait revenir 3 chiffres.

Comment puis-je résoudre ce problème?

Modifié:

Voici comment je récupère les numéros, pour être clair: je reçois le nom correct, mais la requête suivante renvoie null tandis que le contact a des numéros.

ArrayList<Number> numbers = new ArrayList<>(); 
    if (cur.getInt(cur.getColumnIndex(
      ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) { 
     Cursor pCur = cr.query(
       ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 
       null, 
       ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", 
       new String[]{id}, null); 
     while (pCur.moveToNext()) { 
      numbers.add(new nl.coffeeit.clearvoxnexxt.objects.dto.Number(pCur.getString(pCur.getColumnIndex(
        ContactsContract.CommonDataKinds.Phone.NUMBER)))); 
     } 
     pCur.close(); 
    } 
    return numbers; 

S'il vous plaît noter que je ne demande pas l'intention, je le reçois par une action personnalisée qui est ajoutée à un contact natif, comme Viber et WhatsApp faire:

custom action android contact

code complet LocalContacts async:

private static final String TAG = "LocalContactAsync"; 
private static List<Contact> contacts; 

private Context context; 
private boolean refreshOtherFragments; 
private boolean renew;  

private synchronized List<Contact> getContacts(Context context) { 
    if (!renew && contacts != null) { 
     return contacts; 
    } 
    ContentResolver cr = context.getContentResolver(); 
    Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, 
      null, null, null, null); 

    if (cur != null && cur.getCount() > 0) { 
     contacts = getContacts(cur, cr); 
     cur.close(); 
     return contacts; 
    } 
    if (cur != null) { 
     cur.close(); 
    } 
    return new ArrayList<>(); 
} 

public static List<Contact> getContacts(Cursor cur, ContentResolver cr) { 
    List<Contact> contacts = new ArrayList<>(); 
    while (cur.moveToNext()) { 
     String id = getId(cur); 
     String name = getName(cur); 
     ArrayList<Number> numbers = getNumbers(cur, cr, id); 
     if (name != null) { 
      contacts.add(new Contact(id, name, numbers)); 
     } 
    } 
    Log.d(TAG, "amount of contacts" + contacts.size()); 
    return contacts; 
} 

private static ArrayList<Number> getNumbers(Cursor cur, ContentResolver cr, String id) { 
    ArrayList<Number> numbers = new ArrayList<>(); 
    if (cur.getInt(cur.getColumnIndex(
      ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) { 
     Cursor pCur = cr.query(
       ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 
       null, 
       ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", 
       new String[]{id}, null); 
     while (pCur.moveToNext()) { 
      numbers.add(getNumber(pCur)); 
     } 
     pCur.close(); 
    } 
    return numbers; 
} 

private static Number getNumber(Cursor pCur) { 
    return new nl.coffeeit.clearvoxnexxt.objects.dto.Number(pCur.getString(pCur.getColumnIndex(
      ContactsContract.CommonDataKinds.Phone.NUMBER))); 
} 

private static String getId(Cursor cur) { 
    return cur.getString(
      cur.getColumnIndex(ContactsContract.Contacts._ID)); 
} 

private static String getName(Cursor cur) { 
    return cur.getString(cur.getColumnIndex(
      ContactsContract.Contacts.DISPLAY_NAME)); 
} 
code

pour le numéro DTO:

public class Number implements Parcelable, Serializable { 

    @SerializedName("number") 
    @Expose 
    public String number; 
    @SerializedName("type") 
    @Expose 
    public String type = ""; 
    @SerializedName("inherited") 
    @Expose 
    public Boolean inherited = false; 

    public Number(String number) { 
     this.number = number; 
    } 

    protected Number(Parcel in) { 
     number = in.readString(); 
     type = in.readString(); 
     byte inheritedVal = in.readByte(); 
     inherited = inheritedVal == 0x02 ? null : inheritedVal != 0x00; 
    } 

    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeString(number); 
     dest.writeString(type); 
     if (inherited == null) { 
      dest.writeByte((byte) (0x02)); 
     } else { 
      dest.writeByte((byte) (inherited ? 0x01 : 0x00)); 
     } 
    } 

    @SuppressWarnings("unused") 
    public static final Parcelable.Creator<Number> CREATOR = new Parcelable.Creator<Number>() { 
     @Override 
     public Number createFromParcel(Parcel in) { 
      return new Number(in); 
     } 

     @Override 
     public Number[] newArray(int size) { 
      return new Number[size]; 
     } 
    }; 

    public Number setNumber(String number) { 
     this.number = number; 
     return this; 
    } 
} 

Répondre

1

La première chose à noter est qu'un appel aux sélecteur de contacts comme celui-ci:

Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI); 

retournera un Uri comme celui-ci:

content://com.android.contacts/contacts/lookup/3163r328-4D2941473F314D2941473F3131/328 

Le deuxième au dernier chemin (3163r .. ..) est la clé de recherche, tandis que 328 est le NAME_RAW_ID.

Comparez cela avec l'intention que vous obtenez du sample application. Celui-ci contient un Uri qui ressemble à ceci:

content://com.android.contacts/data/2849 

Comme vous l'avez dit, appelant le résolveur de contenu avec ce Uri ne suffit pas pour récupérer les numéros de téléphone, bien qu'il puisse être utilisé pour récupérer le nom du contact et de la id. Nous utiliserons donc l'intention incomplète d'Uri pour construire un nouvel Uri de recherche que nous pourrons utiliser pour obtenir les numéros de téléphone.

Ajoutons les méthodes suivantes à votre LocalContactAsync (je ne factoriser tout ce que vous avez fait jusqu'à présent, je vais juste ajouter dans le style que vous avez utilisé):

public static Uri getLookupUri(Cursor cur) { 
    return getContentUri(getLookupKey(cur), getNameRawId(cur)); 
} 

private static String getLookupKey(Cursor cur) { 
    return cur.getString(
      cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); 
} 

private static String getNameRawId(Cursor cur) { 
    return cur.getString(cur.getColumnIndex(ContactsContract.Contacts.NAME_RAW_CONTACT_ID)); 
} 

private static Uri getContentUri(String lookupKey, String nameRawId) { 
    return new Uri.Builder() 
      .scheme("content") 
      .authority("com.android.contacts") 
      .appendPath("contacts") 
      .appendPath("lookup") 
      .appendPath(lookupKey) 
      .appendPath(nameRawId) 
      .build(); 
} 

Modifions le ViewingActivity intérieur l'exemple d'application afin qu'il récupère réellement les détails de contact. Nous pouvons maintenant faire avec le code suivant à l'intérieur onResume():

@Override 
protected void onResume() { 
    super.onResume(); 
    Uri uri = getIntent().getData(); 
    Cursor intentCursor = this.getContentResolver().query(uri, null, null, null, null); 
    Contact contact = null; 
    if (intentCursor != null) { 
     intentCursor.moveToFirst(); 
     Uri lookupUri = LocalContactAsync.getLookupUri(intentCursor); 
     Cursor lookupCursor = this.getContentResolver().query(lookupUri, null, null, null, null); 
     contact = LocalContactAsync.getContacts(lookupCursor, this.getContentResolver()).get(0); 
     intentCursor.close(); 
     lookupCursor.close(); 
    } 
} 

Le contact contiendra maintenant les numéros de téléphone au besoin.

+0

Merci pour l'info, mais je ne démarre pas une activité pour un résultat. J'ajoute un événement personnalisé au contact natif qui ouvre mon application directement à partir de l'application de contact d'Android. Comment puis-je gérer ces extras? – jobbert

+0

J'ai ajouté des informations supplémentaires à la question. Le code que vous avez fourni fonctionnait comme le mien. Je reçois le nom et l'identifiant mais pas de numéro de téléphone. Alors que le contact a 3 numéros de téléphone. Aussi, si je viens de récupérer tous les contacts, je suis en mesure d'obtenir les numéros de téléphone. – jobbert

+0

Ensuite, le nombre 2849 revient. C'est mauvais nom. Ce n'est pas du tout asynchrone. Je peux poster le code complet si vous voulez. – jobbert