Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avatar Etags #1658

Merged
merged 5 commits into from
Jan 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.Display;
import android.view.MenuItem;
Expand All @@ -53,6 +54,7 @@
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.ui.TextDrawable;
import com.owncloud.android.ui.adapter.DiskLruImageCache;
import com.owncloud.android.ui.preview.PreviewImageFragment;
import com.owncloud.android.utils.BitmapUtils;
Expand Down Expand Up @@ -84,31 +86,25 @@ public class ThumbnailsCacheManager {
private static final String TAG = ThumbnailsCacheManager.class.getSimpleName();
private static final String PNG_MIMETYPE = "image/png";
private static final String CACHE_FOLDER = "thumbnailCache";
public static final String AVATAR = "avatar";
private static final String ETAG = "ETag";

private static final Object mThumbnailsDiskCacheLock = new Object();
private static DiskLruImageCache mThumbnailCache = null;
private static boolean mThumbnailCacheStarting = true;

private static final int DISK_CACHE_SIZE = 1024 * 1024 * 200; // 200MB
private static final CompressFormat mCompressFormat = CompressFormat.JPEG;
private static final int mCompressQuality = 70;
private static OwnCloudClient mClient = null;

public static final Bitmap mDefaultImg =
BitmapFactory.decodeResource(
MainApp.getAppContext().getResources(),
R.drawable.file_image
);

public static final Bitmap mDefaultVideo =
BitmapFactory.decodeResource(
MainApp.getAppContext().getResources(),
R.drawable.file_movie
);
public static final Bitmap mDefaultImg = BitmapFactory.decodeResource(MainApp.getAppContext().getResources(),
R.drawable.file_image);

public static final Bitmap mDefaultVideo = BitmapFactory.decodeResource(MainApp.getAppContext().getResources(),
R.drawable.file_movie);

public static class InitDiskCacheTask extends AsyncTask<File, Void, Void> {

@Override
protected Void doInBackground(File... params) {
synchronized (mThumbnailsDiskCacheLock) {
Expand Down Expand Up @@ -759,27 +755,32 @@ private Bitmap doFileInBackground(File file, Type type) {
}
}

public static class AvatarGenerationTask extends AsyncTask<String, Void, Bitmap> {
public static class AvatarGenerationTask extends AsyncTask<String, Void, Drawable> {
private final WeakReference<AvatarGenerationListener> mAvatarGenerationListener;
private final Object mCallContext;
private final Resources mResources;
private final float mAvatarRadius;
private Account mAccount;
private String mUsername;


public AvatarGenerationTask(AvatarGenerationListener avatarGenerationListener, Object callContext,
FileDataStorageManager storageManager, Account account) {
FileDataStorageManager storageManager, Account account, Resources resources,
float avatarRadius) {
mAvatarGenerationListener = new WeakReference<>(avatarGenerationListener);
mCallContext = callContext;
if (storageManager == null) {
throw new IllegalArgumentException("storageManager must not be NULL");
}
mAccount = account;
mResources = resources;
mAvatarRadius = avatarRadius;
}

@SuppressFBWarnings("Dm")
@Override
protected Bitmap doInBackground(String... params) {
Bitmap thumbnail = null;
protected Drawable doInBackground(String... params) {
Drawable thumbnail = null;

try {
if (mAccount != null) {
Expand All @@ -802,14 +803,14 @@ protected Bitmap doInBackground(String... params) {
return thumbnail;
}

protected void onPostExecute(Bitmap bitmap) {
if (bitmap != null) {
protected void onPostExecute(Drawable drawable) {
if (drawable != null) {
AvatarGenerationListener listener = mAvatarGenerationListener.get();
AvatarGenerationTask avatarWorkerTask = getAvatarWorkerTask(mCallContext);
if (this == avatarWorkerTask
&& listener.shouldCallGeneratedCallback(mUsername, mCallContext)) {
listener.avatarGenerated(new BitmapDrawable(bitmap), mCallContext);
}

if (this == avatarWorkerTask && listener.shouldCallGeneratedCallback(mUsername, mCallContext)) {
listener.avatarGenerated(drawable, mCallContext);
}
}
}

Expand All @@ -823,63 +824,97 @@ private int getAvatarDimension(){
return Math.round(r.getDimension(R.dimen.file_avatar_size));
}

private Bitmap doAvatarInBackground() {
private @Nullable
Drawable doAvatarInBackground() {
Bitmap avatar = null;
String username = mUsername;

final String imageKey = "a_" + username;
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(
MainApp.getAppContext().getContentResolver());

// Check disk cache in background thread
Bitmap avatar = getBitmapFromDiskCache(imageKey);
String eTag = arbitraryDataProvider.getValue(mAccount, AVATAR);

// Not found in disk cache
if (avatar == null) {
final String imageKey = "a_" + username + "_" + eTag;

int px = getAvatarDimension();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}

// Download avatar from server
OwnCloudVersion serverOCVersion = AccountUtils.getServerVersion(mAccount);
if (mClient != null && serverOCVersion != null) {
if (serverOCVersion.supportsRemoteThumbnails()) {
GetMethod get = null;
try {
int px = getAvatarDimension();

// Download avatar from server
OwnCloudVersion serverOCVersion = AccountUtils.getServerVersion(mAccount);
if (mClient != null && serverOCVersion != null) {
if (serverOCVersion.supportsRemoteThumbnails()) {
GetMethod get = null;
try {
String userId = AccountManager.get(MainApp.getAppContext()).getUserData(mAccount,
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);

String userId = AccountManager.get(MainApp.getAppContext()).getUserData(mAccount,
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
if (TextUtils.isEmpty(userId)) {
userId = AccountUtils.getAccountUsername(username);
}

if (TextUtils.isEmpty(userId)) {
userId = AccountUtils.getAccountUsername(username);
}
String uri = mClient.getBaseUri() + "/index.php/avatar/" + Uri.encode(userId) + "/" + px;
Log_OC.d("Avatar", "URI: " + uri);
get = new GetMethod(uri);

if (!eTag.isEmpty()) {
get.setRequestHeader("If-None-Match", eTag);
}

String uri = mClient.getBaseUri() + "/index.php/avatar/" + Uri.encode(userId) + "/" + px;
Log_OC.d("Avatar", "URI: " + uri);
get = new GetMethod(uri);
int status = mClient.executeMethod(get);
if (status == HttpStatus.SC_OK) {
int status = mClient.executeMethod(get);

// we are using eTag to download a new avatar only if it changed
switch (status) {
case HttpStatus.SC_OK:
// new avatar
InputStream inputStream = get.getResponseBodyAsStream();

if (get.getResponseHeader(ETAG) != null) {
eTag = get.getResponseHeader(ETAG).getValue().replace("\"", "");
arbitraryDataProvider.storeOrUpdateKeyValue(mAccount.name, AVATAR, eTag);
}

Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
avatar = ThumbnailUtils.extractThumbnail(bitmap, px, px);

// Add avatar to cache
if (avatar != null) {
avatar = handlePNG(avatar, px);
addBitmapToCache(imageKey, avatar);
String newImageKey = "a_" + username + "_" + eTag;
addBitmapToCache(newImageKey, avatar);
} else {
return TextDrawable.createAvatar(mAccount.name, mAvatarRadius);
}
} else {
break;

case HttpStatus.SC_NOT_MODIFIED:
// old avatar
avatar = getBitmapFromDiskCache(imageKey);
mClient.exhaustResponse(get.getResponseBodyAsStream());
}
} catch (Exception e) {
Log_OC.e(TAG, "Error downloading avatar", e);
} finally {
if (get != null) {
get.releaseConnection();
}
break;

default:
// everything else
mClient.exhaustResponse(get.getResponseBodyAsStream());
break;

}
} catch (Exception e) {
Log_OC.e(TAG, "Error downloading avatar", e);
} finally {
if (get != null) {
get.releaseConnection();
}
} else {
Log_OC.d(TAG, "Server too old");
}
} else {
Log_OC.d(TAG, "Server too old");
}
}
return avatar;
return BitmapUtils.bitmapToCircularBitmapDrawable(mResources, avatar);
}
}

Expand Down Expand Up @@ -1077,13 +1112,9 @@ public AsyncMediaThumbnailDrawable(Resources res, Bitmap bitmap,
public static class AsyncAvatarDrawable extends BitmapDrawable {
private final WeakReference<AvatarGenerationTask> avatarWorkerTaskReference;

public AsyncAvatarDrawable(
Resources res, Bitmap bitmap, AvatarGenerationTask avatarWorkerTask
) {

super(res, bitmap);
avatarWorkerTaskReference =
new WeakReference<AvatarGenerationTask>(avatarWorkerTask);
public AsyncAvatarDrawable(Resources res, Drawable bitmap, AvatarGenerationTask avatarWorkerTask) {
super(res, BitmapUtils.drawableToBitmap(bitmap));
avatarWorkerTaskReference = new WeakReference<>(avatarWorkerTask);
}

public AvatarGenerationTask getAvatarWorkerTask() {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/owncloud/android/ui/TextDrawable.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.utils.BitmapUtils;
import com.owncloud.android.utils.NextcloudServer;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
Expand Down Expand Up @@ -95,6 +96,7 @@ public TextDrawable(String text, int r, int g, int b, float radius) {
* @throws NoSuchAlgorithmException if the specified algorithm is not available when calculating the color values
*/
@NonNull
@NextcloudServer(max = 12)
public static TextDrawable createAvatar(String accountName, float radiusInDp) throws
UnsupportedEncodingException, NoSuchAlgorithmException {
String username = AccountUtils.getAccountUsername(accountName);
Expand Down
20 changes: 13 additions & 7 deletions src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -641,19 +641,23 @@ public void updateAccountList() {

// activate second/end account avatar
if (mAvatars[1] != null) {
View accountEndView = findNavigationViewChildById(R.id.drawer_account_end);
accountEndView.setTag(mAvatars[1].name);

DisplayUtils.setAvatar(mAvatars[1], this,
mOtherAccountAvatarRadiusDimension, getResources(), getStorageManager(),
findNavigationViewChildById(R.id.drawer_account_end));
mOtherAccountAvatarRadiusDimension, getResources(), getStorageManager(), accountEndView);
mAccountEndAccountAvatar.setVisibility(View.VISIBLE);
} else {
mAccountEndAccountAvatar.setVisibility(View.GONE);
}

// activate third/middle account avatar
if (mAvatars[2] != null) {
View accountMiddleView = findNavigationViewChildById(R.id.drawer_account_middle);
accountMiddleView.setTag(mAvatars[2].name);

DisplayUtils.setAvatar(mAvatars[2], this,
mOtherAccountAvatarRadiusDimension, getResources(), getStorageManager(),
findNavigationViewChildById(R.id.drawer_account_middle));
mOtherAccountAvatarRadiusDimension, getResources(), getStorageManager(), accountMiddleView);
mAccountMiddleAccountAvatar.setVisibility(View.VISIBLE);
} else {
mAccountMiddleAccountAvatar.setVisibility(View.GONE);
Expand Down Expand Up @@ -749,9 +753,11 @@ protected void setAccountInDrawer(Account account) {
username.setText(AccountUtils.getAccountUsername(account.name));
}

DisplayUtils.setAvatar(account, this,
mCurrentAccountAvatarRadiusDimension, getResources(), getStorageManager(),
findNavigationViewChildById(R.id.drawer_current_account));
View currentAccountView = findNavigationViewChildById(R.id.drawer_current_account);
currentAccountView.setTag(account.name);

DisplayUtils.setAvatar(account, this, mCurrentAccountAvatarRadiusDimension, getResources(),
getStorageManager(), currentAccountView);

// check and show quota info if available
getAndDisplayUserQuota();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,9 @@ public void onLoadFailed(Exception e, Drawable errorDrawable) {

private void populateUserInfoUi(UserInfo userInfo) {
userName.setText(account.name);
DisplayUtils.setAvatar(account, UserInfoActivity.this,
mCurrentAccountAvatarRadiusDimension, getResources(), getStorageManager(), avatar);
avatar.setTag(account.name);
DisplayUtils.setAvatar(account, UserInfoActivity.this, mCurrentAccountAvatarRadiusDimension, getResources(),
getStorageManager(), avatar);

int tint = ThemeUtils.primaryColor(account);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@ private void setCurrentlyActiveState(AccountViewHolderItem viewHolder, Account a

private void setAvatar(AccountViewHolderItem viewHolder, Account account) {
try {
DisplayUtils.setAvatar(account, this, mAccountAvatarRadiusDimension,
mContext.getResources(), mContext.getStorageManager(), viewHolder.imageViewItem);
View viewItem = viewHolder.imageViewItem;
viewItem.setTag(account.name);
DisplayUtils.setAvatar(account, this, mAccountAvatarRadiusDimension, mContext.getResources(),
mContext.getStorageManager(), viewItem);
} catch (Exception e) {
Log_OC.e(TAG, "Error calculating RGB value for account list item.", e);
// use user icon as a fallback
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/owncloud/android/utils/BitmapUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.media.ExifInterface;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
Expand Down Expand Up @@ -376,4 +379,27 @@ public static RoundedBitmapDrawable bitmapToCircularBitmapDrawable(Resources res
roundedBitmap.setCircular(true);
return roundedBitmap;
}

public static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap;

if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}

if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
Bitmap.Config.ARGB_8888);
}

Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
Loading