Fixed contact picture edition quality & rotation
This commit is contained in:
parent
7caff1175f
commit
ac12b1a7ea
4 changed files with 107 additions and 37 deletions
|
@ -23,6 +23,7 @@ import android.content.ContentProviderOperation;
|
||||||
import android.content.ContentProviderResult;
|
import android.content.ContentProviderResult;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
|
import android.content.res.AssetFileDescriptor;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
|
@ -30,6 +31,8 @@ import android.provider.ContactsContract.CommonDataKinds;
|
||||||
import android.provider.ContactsContract.Contacts;
|
import android.provider.ContactsContract.Contacts;
|
||||||
import android.provider.ContactsContract.Data;
|
import android.provider.ContactsContract.Data;
|
||||||
import android.provider.ContactsContract.RawContacts;
|
import android.provider.ContactsContract.RawContacts;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import org.linphone.LinphoneContext;
|
import org.linphone.LinphoneContext;
|
||||||
|
@ -41,10 +44,12 @@ class AndroidContact implements Serializable {
|
||||||
private String mAndroidRawId;
|
private String mAndroidRawId;
|
||||||
private boolean isAndroidRawIdLinphone;
|
private boolean isAndroidRawIdLinphone;
|
||||||
private final transient ArrayList<ContentProviderOperation> mChangesToCommit;
|
private final transient ArrayList<ContentProviderOperation> mChangesToCommit;
|
||||||
|
private byte[] mTempPicture;
|
||||||
|
|
||||||
AndroidContact() {
|
AndroidContact() {
|
||||||
mChangesToCommit = new ArrayList<>();
|
mChangesToCommit = new ArrayList<>();
|
||||||
isAndroidRawIdLinphone = false;
|
isAndroidRawIdLinphone = false;
|
||||||
|
mTempPicture = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getAndroidId() {
|
String getAndroidId() {
|
||||||
|
@ -78,6 +83,12 @@ class AndroidContact implements Serializable {
|
||||||
String rawId = String.valueOf(ContentUris.parseId(results[0].uri));
|
String rawId = String.valueOf(ContentUris.parseId(results[0].uri));
|
||||||
if (mAndroidId == null) {
|
if (mAndroidId == null) {
|
||||||
Log.i("[Contact] Contact created with RAW ID " + rawId);
|
Log.i("[Contact] Contact created with RAW ID " + rawId);
|
||||||
|
mAndroidRawId = rawId;
|
||||||
|
if (mTempPicture != null) {
|
||||||
|
Log.i(
|
||||||
|
"[Contact] Contact has been created, raw is is available, time to set the photo");
|
||||||
|
setPhoto(mTempPicture);
|
||||||
|
}
|
||||||
|
|
||||||
final String[] projection =
|
final String[] projection =
|
||||||
new String[] {ContactsContract.RawContacts.CONTACT_ID};
|
new String[] {ContactsContract.RawContacts.CONTACT_ID};
|
||||||
|
@ -551,33 +562,44 @@ class AndroidContact implements Serializable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAndroidId == null) {
|
if (mAndroidRawId == null) {
|
||||||
Log.i("[Contact] Setting picture to new contact.");
|
Log.w("[Contact] Can't set picture for not already created contact, will do it later");
|
||||||
addChangesToCommit(
|
mTempPicture = photo;
|
||||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
||||||
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
||||||
.withValue(
|
|
||||||
ContactsContract.Data.MIMETYPE,
|
|
||||||
ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, photo)
|
|
||||||
.build());
|
|
||||||
} else {
|
} else {
|
||||||
Log.i(
|
Log.i(
|
||||||
"[Contact] Setting picture to existing contact "
|
"[Contact] Setting picture to an already created raw contact [",
|
||||||
+ mAndroidId
|
mAndroidRawId,
|
||||||
+ " ("
|
"]");
|
||||||
+ mAndroidRawId
|
try {
|
||||||
+ ")");
|
long rawId = Long.parseLong(mAndroidRawId);
|
||||||
addChangesToCommit(
|
|
||||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
Uri rawContactPhotoUri =
|
||||||
.withValue(ContactsContract.Data.RAW_CONTACT_ID, mAndroidRawId)
|
Uri.withAppendedPath(
|
||||||
.withValue(
|
ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawId),
|
||||||
ContactsContract.Data.MIMETYPE,
|
RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
|
||||||
ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, photo)
|
if (rawContactPhotoUri != null) {
|
||||||
.withValue(ContactsContract.Data.IS_PRIMARY, 1)
|
ContentResolver resolver =
|
||||||
.withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1)
|
LinphoneContext.instance().getApplicationContext().getContentResolver();
|
||||||
.build());
|
AssetFileDescriptor fd =
|
||||||
|
resolver.openAssetFileDescriptor(rawContactPhotoUri, "rw");
|
||||||
|
OutputStream os = fd.createOutputStream();
|
||||||
|
os.write(photo);
|
||||||
|
os.close();
|
||||||
|
fd.close();
|
||||||
|
} else {
|
||||||
|
Log.e(
|
||||||
|
"[Contact] Failed to get raw contact photo URI for raw contact id [",
|
||||||
|
rawId,
|
||||||
|
"], aborting");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
Log.e("[Contact] Couldn't parse raw id [", mAndroidId, "], aborting");
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.e("[Contact] Couldn't set picture, IO error: ", ioe);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("[Contact] Couldn't set picture, unknown error: ", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.media.ExifInterface;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
@ -398,15 +399,18 @@ public class ContactEditorFragment extends Fragment {
|
||||||
editContactPicture(null, bm);
|
editContactPicture(null, bm);
|
||||||
} else if (data != null && data.getData() != null) {
|
} else if (data != null && data.getData() != null) {
|
||||||
Uri selectedImageUri = data.getData();
|
Uri selectedImageUri = data.getData();
|
||||||
try {
|
String filePath = FileUtils.getRealPathFromURI(getActivity(), selectedImageUri);
|
||||||
Bitmap selectedImage =
|
if (filePath != null) {
|
||||||
MediaStore.Images.Media.getBitmap(
|
editContactPicture(filePath, null);
|
||||||
getActivity().getContentResolver(), selectedImageUri);
|
} else {
|
||||||
selectedImage =
|
try {
|
||||||
Bitmap.createScaledBitmap(selectedImage, PHOTO_SIZE, PHOTO_SIZE, false);
|
Bitmap selectedImage =
|
||||||
editContactPicture(null, selectedImage);
|
MediaStore.Images.Media.getBitmap(
|
||||||
} catch (IOException e) {
|
getActivity().getContentResolver(), selectedImageUri);
|
||||||
Log.e(e);
|
editContactPicture(null, selectedImage);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e("[Contact Editor] IO error: ", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (mPickedPhotoForContactUri != null) {
|
} else if (mPickedPhotoForContactUri != null) {
|
||||||
String filePath = mPickedPhotoForContactUri.getPath();
|
String filePath = mPickedPhotoForContactUri.getPath();
|
||||||
|
@ -478,23 +482,52 @@ public class ContactEditorFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editContactPicture(String filePath, Bitmap image) {
|
private void editContactPicture(String filePath, Bitmap image) {
|
||||||
|
int orientation = ExifInterface.ORIENTATION_NORMAL;
|
||||||
|
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
Log.i(
|
Log.i(
|
||||||
"[Contact Editor] Bitmap is null, trying to decode image from file [",
|
"[Contact Editor] Bitmap is null, trying to decode image from file [",
|
||||||
filePath,
|
filePath,
|
||||||
"]");
|
"]");
|
||||||
image = BitmapFactory.decodeFile(filePath);
|
image = BitmapFactory.decodeFile(filePath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ExifInterface ei = new ExifInterface(filePath);
|
||||||
|
orientation =
|
||||||
|
ei.getAttributeInt(
|
||||||
|
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
|
||||||
|
Log.i("[Contact Editor] Exif rotation is ", orientation);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e("[Contact Editor] Failed to get Exif rotation, error is ", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
Log.e(
|
Log.e(
|
||||||
"[Contact Editor] Couldn't get bitmap from either filePath [",
|
"[Contact Editor] Couldn't get bitmap from either filePath [",
|
||||||
filePath,
|
filePath,
|
||||||
"] nor image [",
|
"] nor image");
|
||||||
image,
|
|
||||||
"]");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (orientation) {
|
||||||
|
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||||
|
image = ImageUtils.rotateImage(image, 90);
|
||||||
|
break;
|
||||||
|
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||||
|
image = ImageUtils.rotateImage(image, 180);
|
||||||
|
break;
|
||||||
|
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||||
|
image = ImageUtils.rotateImage(image, 270);
|
||||||
|
break;
|
||||||
|
case ExifInterface.ORIENTATION_NORMAL:
|
||||||
|
// Nothing to do
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.w("[Contact Editor] Unexpected orientation ", orientation);
|
||||||
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
image.compress(Bitmap.CompressFormat.JPEG, 100, stream);
|
image.compress(Bitmap.CompressFormat.JPEG, 100, stream);
|
||||||
mPhotoToAdd = stream.toByteArray();
|
mPhotoToAdd = stream.toByteArray();
|
||||||
|
|
|
@ -640,6 +640,10 @@ public class LinphoneContact extends AndroidContact
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
saveChangesCommited();
|
saveChangesCommited();
|
||||||
|
if (getAndroidId() != null) {
|
||||||
|
setThumbnailUri(getContactThumbnailPictureUri());
|
||||||
|
setPhotoUri(getContactPictureUri());
|
||||||
|
}
|
||||||
syncValuesFromAndroidContact(LinphoneContext.instance().getApplicationContext());
|
syncValuesFromAndroidContact(LinphoneContext.instance().getApplicationContext());
|
||||||
createOrUpdateFriend();
|
createOrUpdateFriend();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ package org.linphone.utils;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.PorterDuffXfermode;
|
import android.graphics.PorterDuffXfermode;
|
||||||
|
@ -85,4 +86,14 @@ public class ImageUtils {
|
||||||
/ ((float) context.getResources().getDisplayMetrics().densityDpi
|
/ ((float) context.getResources().getDisplayMetrics().densityDpi
|
||||||
/ DisplayMetrics.DENSITY_DEFAULT);
|
/ DisplayMetrics.DENSITY_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Bitmap rotateImage(Bitmap source, float angle) {
|
||||||
|
Matrix matrix = new Matrix();
|
||||||
|
matrix.postRotate(angle);
|
||||||
|
Bitmap rotatedBitmap =
|
||||||
|
Bitmap.createBitmap(
|
||||||
|
source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
|
||||||
|
source.recycle();
|
||||||
|
return rotatedBitmap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue