/*
* Copyright 2015. Appsi Mobile
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.appsimobile.appsii.module;
import android.content.ContentProviderOperation;
import android.content.Context;
import android.content.OperationApplicationException;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.util.Log;
import com.crashlytics.android.Crashlytics;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by nick on 29/05/14.
*/
public class ContactBitmapLoader extends AsyncTask<Void, Void, Bitmap> {
private final Uri mUri;
private final WeakReference<Context> mContext;
private final String mPhotoUri;
private final long mContactId;
private final int mMinDimen;
private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
public ContactBitmapLoader(Context context, long contactId, Uri lookupUri, String photoUri,
int minDimen) {
mUri = lookupUri;
mContext = new WeakReference<>(context);
mPhotoUri = photoUri;
mContactId = contactId;
mMinDimen = minDimen;
}
private static Bitmap loadContactBitmap(Context context, Uri lookupUri, long contactId,
String photoUri, int minDimen) {
Bitmap result = loadFromContentProvider(context, lookupUri);
if (result != null && result.getWidth() > minDimen) {
return result;
}
if (photoUri == null) return null;
Uri uri = Uri.parse(photoUri);
String scheme = uri.getScheme();
InputStream in;
AssetFileDescriptor fd;
byte[] bytes = null;
boolean loadedExternally = false;
try {
if ("http".equals(scheme) || "https".equals(scheme)) {
// Support HTTP urls that might come from extended directories
in = new URL(photoUri).openStream();
fd = null;
loadedExternally = true;
} else {
fd = context.getContentResolver().openAssetFileDescriptor(uri, "r");
in = fd.createInputStream();
}
byte[] buffer = new byte[16 * 1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
int size;
while ((size = in.read(buffer)) != -1) {
baos.write(buffer, 0, size);
}
bytes = baos.toByteArray();
} finally {
in.close();
if (fd != null) {
fd.close();
}
}
} catch (IOException e) {
Log.e("ContactBitmapLoader", "error", e);
}
if (bytes != null && loadedExternally) {
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
ops.add(ContentProviderOperation
.newUpdate(
ContactsContract.Data.CONTENT_URI)
.withSelection(
ContactsContract.Data.CONTACT_ID
+ " = ? AND "
+ ContactsContract.Data.MIMETYPE
+ " = ?",
new String[]{
String.valueOf(contactId),
ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE}
)
.withValue(ContactsContract.Contacts.Photo.PHOTO, bytes).build());
try {
context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException | OperationApplicationException e) {
Log.e("ContactBitmapLoader", "error updating provider", e);
}
}
if (bytes != null) {
result = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
//return BitmapFactory.decodeResource(context.getResources(),
// R.drawable.ic_contact_picture_holo_dark);
return result;
}
private static Bitmap loadFromContentProvider(Context context, Uri lookupUri) {
InputStream in = openContactPhotoInputStream(context, lookupUri);
if (in != null) {
try {
return BitmapFactory.decodeStream(in);
} catch (OutOfMemoryError e) {
Crashlytics.logException(e);
return null;
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
private static InputStream openContactPhotoInputStream(Context context, Uri lookupUri) {
try {
return ContactsContract.Contacts
.openContactPhotoInputStream(context.getContentResolver(), lookupUri, true);
// There was a bug report #152 in crashlytics a crash in the method called
} catch (NullPointerException e) {
Crashlytics.logException(e);
return null;
}
}
public void enqueue() {
executeOnExecutor(mExecutorService);
}
@Override
protected Bitmap doInBackground(Void... params) {
Context context = mContext.get();
if (context != null) {
PeopleCache peopleCache = PeopleCache.getInstance();
if (peopleCache.isKnownNoBitmap(mUri)) return null;
Bitmap result = peopleCache.getBitmap(mUri);
if (result == null) {
result = loadContactBitmap(context, mUri, mContactId, mPhotoUri, mMinDimen);
peopleCache.addToCache(mUri, result);
}
return result;
}
return null;
}
}