通过 Android 中的 PHOTO_FILE_ID 将联系人的图像更改为大照片

Changing contact's image to a large photo via PHOTO_FILE_ID in Android

这似乎适用于小图像:

ContentValues values = new ContentValues();

values.put(ContactsContract.Data.RAW_CONTACT_ID, id);
values.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, photo);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
if (photoRow >= 0) {
    context.getContentResolver().update(ContactsContract.Data.CONTENT_URI, values, ContactsContract.Data._ID + " = " + photoRow, null);
} else {
    context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
}

docs 我意识到对于大图像我需要设置 PHOTO_FILE_ID,所以我可以替换:

ContactsContract.CommonDataKinds.Photo.PHOTO

与:

ContactsContract.CommonDataKinds.Photo.PHOTO_FILE_ID

但是,我需要提供 PHOTO_FILE_ID 而不是原始数据。我的问题:

  1. 如何保存照片 (byte[]) 并获得 PHOTO_FILE_ID?
  2. 如果已有照片可用(照片不是 PHOTO_FILE_ID)。需要删大图才能看到还是大图优先,如果不能,怎么删?

您可以通过以下方式在不使用 ContactsContract.CommonDataKinds.Email.PHOTO_URI 的情况下获取联系人照片 uri: 在此处阅读完整答案 More

哪里!按照你说的方式获取联系人 URI,试试这个:

import android.provider.ContactsContract.PhoneLookup;

public String fetchContactIdFromPhoneNumber(String phoneNumber) {
    Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
        Uri.encode(phoneNumber));
    Cursor cursor = this.getContentResolver().query(uri,
        new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID },
        null, null, null);

    String contactId = "";

    if (cursor.moveToFirst()) {
        do {
        contactId = cursor.getString(cursor
            .getColumnIndex(PhoneLookup._ID));
        } while (cursor.moveToNext());
    }

    return contactId;
  }

要使用 phone 号码获取联系人 ID,请使用以下代码:

import android.provider.ContactsContract.PhoneLookup;

public String fetchContactIdFromPhoneNumber(String phoneNumber) {
    Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
        Uri.encode(phoneNumber));
    Cursor cursor = this.getContentResolver().query(uri,
        new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID },
        null, null, null);

    String contactId = "";

if (cursor.moveToFirst()) {
    do {
    contactId = cursor.getString(cursor
        .getColumnIndex(PhoneLookup._ID));
    } while (cursor.moveToNext());
}

return contactId;

}

并使用获取的联系人 ID 获取联系人照片 URI。使用以下代码获取照片 URI:

import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;

public Uri getPhotoUri(long contactId) {
    ContentResolver contentResolver = getContentResolver();

    try {
        Cursor cursor = contentResolver
            .query(ContactsContract.Data.CONTENT_URI,
                null,
                ContactsContract.Data.CONTACT_ID
                    + "="
                    + contactId
                    + " AND "

                    + ContactsContract.Data.MIMETYPE
                    + "='"
                    + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
                    + "'", null, null);

        if (cursor != null) {
        if (!cursor.moveToFirst()) {
            return null; // no photo
        }
        } else {
        return null; // error in cursor process
        }

    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }

    Uri person = ContentUris.withAppendedId(
        ContactsContract.Contacts.CONTENT_URI, contactId);
    return Uri.withAppendedPath(person,
        ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
  }

如果这不能回答您的问题,请告诉我

终于解决了:

public void changeContactImage(String contactId, byte[] b) {
 ArrayList < ContentProviderOperation > ops = new ArrayList < > ();

 ops.add(ContentProviderOperation
  .newUpdate(
   ContactsContract.Data.CONTENT_URI)
  .withSelection(
   ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?",
   new String[] {
    contactId,
    ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
   })
  .withValue(ContactsContract.CommonDataKinds.Photo.DATA15, b).build());


 // Do something with the phone number...
 try {

  context.getContentResolver().
  applyBatch(ContactsContract.AUTHORITY, ops);

 } catch (RemoteException e) {
  Log.d("RemoteException", e.toString());
 } catch (OperationApplicationException e) {
  Log.d("OperationException", e.toString());
 }

}

PHOTO_FILE_ID 不是文件的 ID(令人困惑),而是数据库中包含原始照片数据的行的 ID。根据我看过的文档,您实际上可以避免使用它 (from the docs) :

PHOTO_FILE_ID

If present, this will be used to populate PHOTO_URI

PHOTO_ID 下(如果 PHOTO_FILE_ID 存在 , 保证填充)

Reference to the row in the data table holding the photo. A photo can be referred to either by ID (this field) or by URI (see PHOTO_THUMBNAIL_URI and PHOTO_URI)

这意味着如果您只使用 PHOTO_URI,您将获得与使用方法 openDisplayPhoto 相同的结果图像。它还表明 URI 方法与第 3 部分目录更好地兼容,因此可能更适合使用

您自己的答案会奏效,但效率不高,因为照片需要编码成 SQL 查询并通过 Android IPC 进行传输。这也使其受到 Android 1MB 的 IPC 大小限制(即,如果您的照片太大,内容提供商操作将失败)。

设置(创建或覆盖)RawContact 的(主要)照片的最有效方法是像这样使用 openAssetFileDescriptor and a ContactsContract.RawContacts.DisplayPhoto URI(从 Android 文档复制的示例):

public void writeDisplayPhoto(long rawContactId, byte[] photo) {
    Uri rawContactPhotoUri = Uri.withAppendedPath(
            ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
            RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
    try {
        AssetFileDescriptor fd =
            getContentResolver().openAssetFileDescriptor(rawContactPhotoUri, "rw");
        OutputStream os = fd.createOutputStream();
        os.write(photo);
        os.close();
        fd.close();
    } catch (IOException e) {
        // Handle error cases.
    }
}

这种方法的唯一缺点是它总是 creates/replaces RawContact 的主照片。如果 RawContact 还没有照片,这将添加一张照片。

遗憾的是,无法将 openAssetFileDescriptorPHOTO_FILE_ID 一起使用,因此您无法使用此方法覆盖由其 ID 标识的特定照片。然而,在现实生活中,大多数联系人可能最多只有一张照片,因此这并不是真正的限制。

这将使用大照片的缩略图自动更新 Photo.PHOTO 列并分配一个 PHOTO_FILE_ID