如何通过单击Android中原生联系人应用中的自定义字段来获取联系人的电话号码?

时间:2016-12-20 14:30:27

标签: android native contacts android-contact-mimetype

情况: 我已根据this questionrelated sample app on GitHub中的说明向Android中的联系人添加了自定义操作。按下时我想在我的应用程序中拨打该联系人。我能够成功检索按下自定义操作时打开的活动中的联系人。

我执行此操作:

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();
} 

我从Android检索到的data是:

  

内容://com.android.contacts/data/2849

注意最后的数字2849,这不是联系人的本机ID。联系人的本机ID为459。我能够成功检索执行此查询的联系人,以下数据返回:

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

-returns'''

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

-returns'样品样品'这是正确的

但是,虽然这是真的:

cursor.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); 

-id = 2849在这种情况下如果我填写459我检索到适量的电话号码

真正的联系人有3个号码,所以它应该返回3个号码。

我如何解决这个问题?

编辑:

这是我检索数字的方式,要明确:我得到了正确的名称,但是当联系人有数字时,以下查询会返回null

    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;

请注意,我没有请求意图,我是通过添加到本机联系人的自定义操作收到的,例如Viber和WhatsApp:

custom action android contact

完整代码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));
}

编号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;
    }
}

1 个答案:

答案 0 :(得分:1)

首先要注意的是对联系人选择器的调用如下:

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

会像这样返回一个Uri:

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

倒数第二个路径(3163r ....)是查找键,而328是NAME_RAW_ID

将此与您从sample application获得的意图进行比较。这包含一个看起来像这样的Uri:

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

正如您所说,使用此Uri调用内容解析程序不足以检索电话号码,尽管它可能用于检索联系人姓名和ID。因此,我们将使用不完整的Intent Uri构建一个新的Lookup Uri,我们可以使用它来获取电话号码。

让我们将以下方法添加到您的LocalContactAsync(我不会重构您到目前为止所做的任何事情,我只会添加您使用的样式):

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();
}

让我们更改示例应用程序中的ViewingActivity,以便它实际检索联系人详细信息。我们现在可以使用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();
    }
}

联系人现在将根据需要包含电话号码。