Skip to content
Snippets Groups Projects
Select Git revision
  • 649d49f1e8a33b5e87181f16854f4c37ddf828b2
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/windows-test/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • release/201811
  • release/201808
  • wip/patches_poly_2017/cedryk_doucet/abderahmane_bouziane
  • releases/beta1
  • android/release_464
  • android/release_463
  • android/release_462
  • android/release_461
  • android/release_460
  • android/release_459
  • android/release_458
  • android/release_457
  • android/release_456
  • android/release_455
  • android/release_454
  • android/release_453
  • android/release_452
  • android/release_451
  • android/release_450
  • android/release_449
  • android/release_448
  • android/release_447
  • android/release_446
  • android/release_445
38 results

ContactDetailsTask.java

Blame
  • user avatar
    Thibault Wittemberg authored and Aline Bonnet committed
    Change-Id: If7d0206eef39a4d309ccaf9a37625feaad008c84
    Tuleap: #1143
    649d49f1
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    ContactDetailsTask.java 11.63 KiB
    /*
     *  Copyright (C) 2004-2016 Savoir-faire Linux Inc.
     *
     *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
     *  Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
     *
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation; either version 3 of the License, or
     *  (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License
     *  along with this program; if not, write to the Free Software
     *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     */
    
    package cx.ring.adapters;
    
    import android.content.ContentResolver;
    import android.content.ContentUris;
    import android.content.Context;
    import android.content.res.Resources;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Matrix;
    import android.net.Uri;
    import android.provider.ContactsContract;
    import android.provider.MediaStore;
    import android.text.TextUtils;
    import android.util.Log;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.lang.ref.WeakReference;
    import java.util.ArrayList;
    
    import cx.ring.R;
    import cx.ring.model.CallContact;
    import cx.ring.utils.CropImageUtils;
    import cx.ring.utils.VCardUtils;
    import ezvcard.VCard;
    import ezvcard.property.Photo;
    
    public class ContactDetailsTask implements Runnable {
        static final String TAG = ContactDetailsTask.class.getSimpleName();
    
        private final WeakReference<ImageView> mImageViewWeakRef;
        private final WeakReference<TextView> mTextViewWeakRef;
        private final CallContact mContact;
    
        private Context mContext;
    
        private final ArrayList<DetailsLoadedCallback> mCallbacks = new ArrayList<>(1);
    
        private final int mViewWidth, mViewHeight;
    
        private final static String MIME_TYPE_JPG = "image/jpg";
        private final static String MIME_TYPE_JPEG = "image/jpeg";
        private final static String MIME_TYPE_PNG = "image/png";
        private final static int ORIENTATION_LEFT = 270;
        private final static int ORIENTATION_RIGHT = 90;
        private final static int MAX_IMAGE_DIMENSION = 70;
    
        public void addCallback(DetailsLoadedCallback cb) {
            synchronized (mCallbacks) {
                if (cb == null) {
                    return;
                }
                mImageViewWeakRef.clear();
                mCallbacks.add(cb);
            }
        }
    
        public interface DetailsLoadedCallback {
            void onDetailsLoaded(Bitmap bmp, String formattedName);
        }
    
        public ContactDetailsTask(Context context, ImageView element, CallContact item) {
            mContact = item;
            mContext = context;
            mImageViewWeakRef = new WeakReference<>(element);
            mTextViewWeakRef = new WeakReference<>(null);
            mViewWidth = element.getWidth();
            mViewHeight = element.getHeight();
        }
    
        public ContactDetailsTask(Context context, ImageView photoView, TextView nameView, CallContact item, DetailsLoadedCallback cb) {
            mContact = item;
            mContext = context;
            mViewWidth = photoView.getWidth();
            mViewHeight = photoView.getHeight();
            mImageViewWeakRef = new WeakReference<>(photoView);
            mTextViewWeakRef = new WeakReference<>(nameView);
            addCallback(cb);
        }
    
        public ContactDetailsTask(Context context, CallContact item, DetailsLoadedCallback cb) {
            mImageViewWeakRef = new WeakReference<>(null);
            mTextViewWeakRef = new WeakReference<>(null);
            mViewWidth = 0;
            mViewHeight = 0;
    
            mContact = item;
            mContext = context;
            addCallback(cb);
        }
    
        public static Bitmap loadContactPhoto(ContentResolver cr, long id) {
            if (id == -1) {
                return null;
            }
            Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
            InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri, true);
            if (input == null) {
                return null;
            }
            return BitmapFactory.decodeStream(input);
        }
    
        @Override
        public void run() {
            if (mContact == null) {
                return;
            }
            Log.i(TAG, "ContactDetailsTask run " + mContact.getId() + " " + mContact.getDisplayName());
    
            final Bitmap externalBMP;
            String additionnalName = null;
            VCard vcard = null;
    
            if (!mContact.getPhones().isEmpty()) {
                String username = mContact.getPhones().get(0).getNumber().host;
                Log.d(TAG, "getPhones not empty. Username : " + username);
                vcard = VCardUtils.loadPeerProfileFromDisk(username + ".vcf", mContext);
    
                if (vcard != null && vcard.getFormattedName() != null) {
                    if (!TextUtils.isEmpty(vcard.getFormattedName().getValue())) {
                        additionnalName = vcard.getFormattedName().getValue();
                    }
                }
            }
            if (additionnalName == null) {
                additionnalName = mContact.getDisplayName();
            }
    
            if (vcard != null && !vcard.getPhotos().isEmpty()) {
                Photo tmp = vcard.getPhotos().get(0);
                Bitmap croppedBitmap;
                if (tmp != null && tmp.getData() != null) {
                    croppedBitmap = CropImageUtils.cropImageToCircle(tmp.getData());
                } else {
                    croppedBitmap = decodeSampledBitmapFromResource(mContext.getResources(), R.drawable.ic_contact_picture, mViewWidth, mViewHeight);
                }
    
                externalBMP = croppedBitmap != null ? croppedBitmap : decodeSampledBitmapFromResource(mContext.getResources(), R.drawable.ic_contact_picture, mViewWidth, mViewHeight);
    
            } else {
                Bitmap photoBmp;
                try {
                    photoBmp = loadContactPhoto(mContext.getContentResolver(), mContact.getId());
                } catch (IllegalArgumentException e) {
                    photoBmp = null;
                }
    
                if (photoBmp == null) {
                    photoBmp = decodeSampledBitmapFromResource(mContext.getResources(), R.drawable.ic_contact_picture, mViewWidth, mViewHeight);
                }
    
                externalBMP = CropImageUtils.cropImageToCircle(photoBmp);
                photoBmp.recycle();
            }
    
            final String formattedName = additionnalName;
            mContact.setPhoto(externalBMP);
            synchronized (mCallbacks) {
                final ImageView v = mImageViewWeakRef.get();
                final TextView textView = mTextViewWeakRef.get();
    
                mImageViewWeakRef.clear();
                if (v == null) {
                    for (DetailsLoadedCallback cb : mCallbacks) {
                        cb.onDetailsLoaded(externalBMP, formattedName);
                    }
                } else {
                    v.post(new Runnable() {
                        @Override
                        public void run() {
                            v.setImageBitmap(externalBMP);
                            if (textView != null) {
                                textView.setText(formattedName);
                            }
                        }
                    });
                }
                mCallbacks.clear();
            }
        }
    
        public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
    
            final BitmapFactory.Options options = new BitmapFactory.Options();
    
            // Calculate inSampleSize
            options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    
            // Decode bitmap with inSampleSize set
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeResource(res, resId, options);
        }
    
        public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
            // Raw height and width of image
            final int height = options.outHeight;
            final int width = options.outWidth;
            int inSampleSize = 1;
    
            if (height > reqHeight || width > reqWidth) {
    
                // Calculate ratios of height and width to requested height and width
                final int heightRatio = Math.round((float) height / (float) reqHeight);
                final int widthRatio = Math.round((float) width / (float) reqWidth);
    
                // Choose the smallest ratio as inSampleSize value, this will guarantee
                // a final image with both dimensions larger than or equal to the
                // requested height and width.
                inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
            }
    
            return inSampleSize;
        }
    
        public static Bitmap loadProfilePhotoFromUri(Context context, Uri uriImage) {
            try {
                InputStream is = context.getContentResolver().openInputStream(uriImage);
                BitmapFactory.Options dbo = new BitmapFactory.Options();
                dbo.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(is, null, dbo);
                is.close();
    
                int rotatedWidth, rotatedHeight;
                int orientation = getOrientation(context, uriImage);
    
                if (orientation == ORIENTATION_LEFT || orientation == ORIENTATION_RIGHT) {
                    rotatedWidth = dbo.outHeight;
                    rotatedHeight = dbo.outWidth;
                } else {
                    rotatedWidth = dbo.outWidth;
                    rotatedHeight = dbo.outHeight;
                }
    
                Bitmap srcBitmap;
                is = context.getContentResolver().openInputStream(uriImage);
                if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
                    float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
                    float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
                    float maxRatio = Math.max(widthRatio, heightRatio);
    
                    // Create the bitmap from file
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inSampleSize = (int) maxRatio;
                    srcBitmap = BitmapFactory.decodeStream(is, null, options);
                } else {
                    srcBitmap = BitmapFactory.decodeStream(is);
                }
                is.close();
    
                if (orientation > 0) {
                    Matrix matrix = new Matrix();
                    matrix.postRotate(orientation);
    
                    srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                            srcBitmap.getHeight(), matrix, true);
                }
    
                String type = context.getContentResolver().getType(uriImage);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                if (type.equals(MIME_TYPE_PNG)) {
                    srcBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
                } else if (type.equals(MIME_TYPE_JPG) || type.equals(MIME_TYPE_JPEG)) {
                    srcBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
                }
                byte[] bMapArray = baos.toByteArray();
                baos.close();
                return BitmapFactory.decodeByteArray(bMapArray, 0, bMapArray.length);
            } catch (Exception e) {
                Log.e(TAG, "Error while loading photo from URI", e);
                return null;
            }
        }
    
        public static int getOrientation(Context context, Uri photoUri) {
            Cursor cursor = context.getContentResolver().query(photoUri,
                    new String[]{MediaStore.Images.ImageColumns.ORIENTATION}, null, null, null);
    
            if (cursor.getCount() != 1) {
                return -1;
            }
    
            cursor.moveToFirst();
            return cursor.getInt(0);
        }
    }