通过 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 而不是原始数据。我的问题:
- 如何保存照片 (byte[]) 并获得 PHOTO_FILE_ID?
- 如果已有照片可用(照片不是 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 还没有照片,这将添加一张照片。
遗憾的是,无法将 openAssetFileDescriptor
与 PHOTO_FILE_ID
一起使用,因此您无法使用此方法覆盖由其 ID 标识的特定照片。然而,在现实生活中,大多数联系人可能最多只有一张照片,因此这并不是真正的限制。
这将使用大照片的缩略图自动更新 Photo.PHOTO
列并分配一个 PHOTO_FILE_ID
。
这似乎适用于小图像:
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 而不是原始数据。我的问题:
- 如何保存照片 (byte[]) 并获得 PHOTO_FILE_ID?
- 如果已有照片可用(照片不是 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 还没有照片,这将添加一张照片。
遗憾的是,无法将 openAssetFileDescriptor
与 PHOTO_FILE_ID
一起使用,因此您无法使用此方法覆盖由其 ID 标识的特定照片。然而,在现实生活中,大多数联系人可能最多只有一张照片,因此这并不是真正的限制。
这将使用大照片的缩略图自动更新 Photo.PHOTO
列并分配一个 PHOTO_FILE_ID
。