Pārlūkot izejas kodu

add avatar icons on sharee list

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
tobiasKaminsky 6 gadi atpakaļ
vecāks
revīzija
5589b8c0e9

+ 30 - 32
src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java

@@ -22,7 +22,6 @@
 package com.owncloud.android.datamodel;
 
 import android.accounts.Account;
-import android.accounts.AccountManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -773,12 +772,14 @@ public class ThumbnailsCacheManager {
         private final Resources mResources;
         private final float mAvatarRadius;
         private Account mAccount;
-        private String mUsername;
+        private String mUserId;
+        private String mServerName;
+        private Context mContext;
 
 
         public AvatarGenerationTask(AvatarGenerationListener avatarGenerationListener, Object callContext,
                                     FileDataStorageManager storageManager, Account account, Resources resources,
-                                    float avatarRadius) {
+                                    float avatarRadius, String userId, String serverName, Context context) {
             mAvatarGenerationListener = new WeakReference<>(avatarGenerationListener);
             mCallContext = callContext;
             if (storageManager == null) {
@@ -787,6 +788,9 @@ public class ThumbnailsCacheManager {
             mAccount = account;
             mResources = resources;
             mAvatarRadius = avatarRadius;
+            mUserId = userId;
+            mServerName = serverName;
+            mContext = context;
         }
 
         @SuppressFBWarnings("Dm")
@@ -796,20 +800,17 @@ public class ThumbnailsCacheManager {
 
             try {
                 if (mAccount != null) {
-                    OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount,
-                            MainApp.getAppContext());
-                    mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
-                            getClientFor(ocAccount, MainApp.getAppContext());
+                    OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext);
+                    mClient = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, mContext);
                 }
 
-                mUsername = params[0];
                 thumbnail = doAvatarInBackground();
 
             } catch(OutOfMemoryError oome) {
                 Log_OC.e(TAG, "Out of memory");
             } catch(Throwable t){
                 // the app should never break due to a problem with avatars
-                Log_OC.e(TAG, "Generation of avatar for " + mUsername + " failed", t);
+                Log_OC.e(TAG, "Generation of avatar for " + mUserId + " failed", t);
             }
 
             return thumbnail;
@@ -820,7 +821,7 @@ public class ThumbnailsCacheManager {
                 AvatarGenerationListener listener = mAvatarGenerationListener.get();
                 AvatarGenerationTask avatarWorkerTask = getAvatarWorkerTask(mCallContext);
 
-                if (this == avatarWorkerTask && listener.shouldCallGeneratedCallback(mUsername, mCallContext)) {
+                if (this == avatarWorkerTask && listener.shouldCallGeneratedCallback(mUserId, mCallContext)) {
                     listener.avatarGenerated(drawable, mCallContext);
                 }
             }
@@ -830,7 +831,7 @@ public class ThumbnailsCacheManager {
          * Converts size of file icon from dp to pixel
          * @return int
          */
-        private int getAvatarDimension(){
+        private int getAvatarDimension() {
             // Converts dp to pixel
             Resources r = MainApp.getAppContext().getResources();
             return Math.round(r.getDimension(R.dimen.file_avatar_size));
@@ -839,13 +840,14 @@ public class ThumbnailsCacheManager {
         private @Nullable
         Drawable doAvatarInBackground() {
             Bitmap avatar = null;
-            String username = mUsername;
 
-            ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(
-                    MainApp.getAppContext().getContentResolver());
+            String accountName = mUserId + "@" + mServerName;
+
+            ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(mContext.getContentResolver());
+
+            String eTag = arbitraryDataProvider.getValue(accountName, ThumbnailsCacheManager.AVATAR);
+            String avatarKey = "a_" + mUserId + "_" + mServerName + "_" + eTag;
 
-            String eTag = arbitraryDataProvider.getValue(mAccount, AVATAR);
-            final String imageKey = "a_" + username + "_" + eTag;
             int px = getAvatarDimension();
 
             // Download avatar from server
@@ -854,18 +856,13 @@ public class ThumbnailsCacheManager {
                 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);
-
-                        if (TextUtils.isEmpty(userId)) {
-                            userId = AccountUtils.getAccountUsername(username);
-                        }
-
-                        String uri = mClient.getBaseUri() + "/index.php/avatar/" + Uri.encode(userId) + "/" + px;
+                        String uri = mClient.getBaseUri() + "/index.php/avatar/" + Uri.encode(mUserId) + "/" + px;
                         Log_OC.d("Avatar", "URI: " + uri);
                         get = new GetMethod(uri);
 
-                        if (!eTag.isEmpty()) {
+                        // only use eTag if available and corresponding avatar is still there 
+                        // (might be deleted from cache)
+                        if (!eTag.isEmpty() && getBitmapFromDiskCache(avatarKey) != null) {
                             get.setRequestHeader("If-None-Match", eTag);
                         }
 
@@ -877,18 +874,19 @@ public class ThumbnailsCacheManager {
                                 // new avatar
                                 InputStream inputStream = get.getResponseBodyAsStream();
 
+                                String newETag = null;
                                 if (get.getResponseHeader(ETAG) != null) {
-                                    eTag = get.getResponseHeader(ETAG).getValue().replace("\"", "");
-                                    arbitraryDataProvider.storeOrUpdateKeyValue(mAccount.name, AVATAR, eTag);
+                                    newETag = get.getResponseHeader(ETAG).getValue().replace("\"", "");
+                                    arbitraryDataProvider.storeOrUpdateKeyValue(accountName, AVATAR, newETag);
                                 }
 
                                 Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                                 avatar = ThumbnailUtils.extractThumbnail(bitmap, px, px);
 
                                 // Add avatar to cache
-                                if (avatar != null) {
+                                if (avatar != null && !TextUtils.isEmpty(newETag)) {
                                     avatar = handlePNG(avatar, px, px);
-                                    String newImageKey = "a_" + username + "_" + eTag;
+                                    String newImageKey = "a_" + mUserId + "_" + mServerName + "_" + newETag;
                                     addBitmapToCache(newImageKey, avatar);
                                 } else {
                                     return TextDrawable.createAvatar(mAccount.name, mAvatarRadius);
@@ -897,7 +895,7 @@ public class ThumbnailsCacheManager {
 
                             case HttpStatus.SC_NOT_MODIFIED:
                                 // old avatar
-                                avatar = getBitmapFromDiskCache(imageKey);
+                                avatar = getBitmapFromDiskCache(avatarKey);
                                 mClient.exhaustResponse(get.getResponseBodyAsStream());
                                 break;
 
@@ -965,7 +963,7 @@ public class ThumbnailsCacheManager {
         final AvatarGenerationTask avatarWorkerTask = getAvatarWorkerTask(imageView);
 
         if (avatarWorkerTask != null) {
-            final Object usernameData = avatarWorkerTask.mUsername;
+            final Object usernameData = avatarWorkerTask.mUserId;
             // If usernameData is not yet set or it differs from the new data
             if (usernameData == null || !usernameData.equals(file)) {
                 // Cancel previous task
@@ -984,7 +982,7 @@ public class ThumbnailsCacheManager {
         final AvatarGenerationTask avatarWorkerTask = getAvatarWorkerTask(menuItem);
 
         if (avatarWorkerTask != null) {
-            final Object usernameData = avatarWorkerTask.mUsername;
+            final Object usernameData = avatarWorkerTask.mUserId;
             // If usernameData is not yet set or it differs from the new data
             if (usernameData == null || !usernameData.equals(file)) {
                 // Cancel previous task

+ 18 - 2
src/main/java/com/owncloud/android/ui/TextDrawable.java

@@ -103,6 +103,23 @@ public class TextDrawable extends Drawable {
         return createNamedAvatar(username, radiusInDp);
     }
 
+    /**
+     * creates an avatar in form of a TextDrawable with the first letter of the account name in a circle with the
+     * given radius.
+     *
+     * @param userId      userId to use
+     * @param radiusInDp  the circle's radius
+     * @return the avatar as a TextDrawable
+     * @throws UnsupportedEncodingException if the charset is not supported when calculating the color values
+     * @throws NoSuchAlgorithmException     if the specified algorithm is not available when calculating the color values
+     */
+    @NonNull
+    @NextcloudServer(max = 12)
+    public static TextDrawable createAvatarByUserId(String userId, float radiusInDp) throws
+            UnsupportedEncodingException, NoSuchAlgorithmException {
+        return createNamedAvatar(userId, radiusInDp);
+    }
+
     /**
      * creates an avatar in form of a TextDrawable with the first letter of a name in a circle with the
      * given radius.
@@ -114,8 +131,7 @@ public class TextDrawable extends Drawable {
      * @throws NoSuchAlgorithmException     if the specified algorithm is not available when calculating the color values
      */
     @NonNull
-    public static TextDrawable createNamedAvatar(String name, float radiusInDp) throws
-            UnsupportedEncodingException, NoSuchAlgorithmException {
+    public static TextDrawable createNamedAvatar(String name, float radiusInDp) {
         int[] hsl = BitmapUtils.calculateHSL(name);
         int[] rgb = BitmapUtils.HSLtoRGB(hsl[0], hsl[1], hsl[2], 1);
 

+ 6 - 6
src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -648,8 +648,8 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
                     View accountEndView = findNavigationViewChildById(R.id.drawer_account_end);
                     accountEndView.setTag(mAvatars[1].name);
 
-                    DisplayUtils.setAvatar(mAvatars[1], this,
-                            mOtherAccountAvatarRadiusDimension, getResources(), getStorageManager(), accountEndView);
+                    DisplayUtils.setAvatar(mAvatars[1], this, mOtherAccountAvatarRadiusDimension, getResources(),
+                            getStorageManager(), accountEndView, this);
                     mAccountEndAccountAvatar.setVisibility(View.VISIBLE);
                 } else {
                     mAccountEndAccountAvatar.setVisibility(View.GONE);
@@ -660,8 +660,8 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
                     View accountMiddleView = findNavigationViewChildById(R.id.drawer_account_middle);
                     accountMiddleView.setTag(mAvatars[2].name);
 
-                    DisplayUtils.setAvatar(mAvatars[2], this,
-                            mOtherAccountAvatarRadiusDimension, getResources(), getStorageManager(), accountMiddleView);
+                    DisplayUtils.setAvatar(mAvatars[2], this, mOtherAccountAvatarRadiusDimension, getResources(),
+                            getStorageManager(), accountMiddleView, this);
                     mAccountMiddleAccountAvatar.setVisibility(View.VISIBLE);
                 } else {
                     mAccountMiddleAccountAvatar.setVisibility(View.GONE);
@@ -695,7 +695,7 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
                             account.name)
                             .setIcon(TextDrawable.createAvatar(account.name, mMenuAccountAvatarRadiusDimension));
                     DisplayUtils.setAvatar(account, this, mMenuAccountAvatarRadiusDimension, getResources(),
-                            getStorageManager(), accountMenuItem);
+                            getStorageManager(), accountMenuItem, this);
                 }
             } catch (Exception e) {
                 Log_OC.e(TAG, "Error calculating RGB value for account menu item.", e);
@@ -761,7 +761,7 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
             currentAccountView.setTag(account.name);
 
             DisplayUtils.setAvatar(account, this, mCurrentAccountAvatarRadiusDimension, getResources(),
-                    getStorageManager(), currentAccountView);
+                    getStorageManager(), currentAccountView, this);
 
             // check and show quota info if available
             getAndDisplayUserQuota();

+ 1 - 1
src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java

@@ -263,7 +263,7 @@ public class UserInfoActivity extends FileActivity {
         userName.setText(account.name);
         avatar.setTag(account.name);
         DisplayUtils.setAvatar(account, UserInfoActivity.this, mCurrentAccountAvatarRadiusDimension, getResources(),
-                getStorageManager(), avatar);
+                getStorageManager(), avatar, this);
 
         int tint = ThemeUtils.primaryColor(account, this);
 

+ 1 - 1
src/main/java/com/owncloud/android/ui/adapter/AccountListAdapter.java

@@ -153,7 +153,7 @@ public class AccountListAdapter extends ArrayAdapter<AccountListItem> implements
             View viewItem = viewHolder.imageViewItem;
             viewItem.setTag(account.name);
             DisplayUtils.setAvatar(account, this, mAccountAvatarRadiusDimension, mContext.getResources(),
-                    mContext.getStorageManager(), viewItem);
+                    mContext.getStorageManager(), viewItem, mContext);
         } catch (Exception e) {
             Log_OC.e(TAG, "Error calculating RGB value for account list item.", e);
             // use user icon as a fallback

+ 26 - 10
src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java

@@ -22,6 +22,7 @@ package com.owncloud.android.ui.adapter;
 
 import android.accounts.Account;
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -42,6 +43,7 @@ import com.owncloud.android.lib.resources.shares.ShareType;
 import com.owncloud.android.lib.resources.status.OCCapability;
 import com.owncloud.android.lib.resources.status.OwnCloudVersion;
 import com.owncloud.android.ui.TextDrawable;
+import com.owncloud.android.utils.DisplayUtils;
 
 import java.io.UnsupportedEncodingException;
 import java.security.NoSuchAlgorithmException;
@@ -50,7 +52,7 @@ import java.util.ArrayList;
 /**
  * Adapter to show a user/group/email/remote in Sharing list in file details view.
  */
-public class UserListAdapter extends ArrayAdapter {
+public class UserListAdapter extends ArrayAdapter implements DisplayUtils.AvatarGenerationListener {
 
     private ShareeListAdapterListener listener;
     private OCCapability capabilities;
@@ -59,6 +61,7 @@ public class UserListAdapter extends ArrayAdapter {
     private float avatarRadiusDimension;
     private Account account;
     private OCFile file;
+    private FileDataStorageManager storageManager;
 
     public UserListAdapter(Context context, int resource, ArrayList<OCShare> shares,
                            Account account, OCFile file, ShareeListAdapterListener listener) {
@@ -69,10 +72,8 @@ public class UserListAdapter extends ArrayAdapter {
         this.account = account;
         this.file = file;
 
-        this.capabilities = new FileDataStorageManager(
-                account,
-                getContext().getContentResolver()
-        ).getCapability(account.name);
+        storageManager = new FileDataStorageManager(account, getContext().getContentResolver());
+        capabilities = storageManager.getCapability(account.name);
 
         avatarRadiusDimension = context.getResources().getDimension(R.dimen.standard_padding);
     }
@@ -123,11 +124,9 @@ public class UserListAdapter extends ArrayAdapter {
                     icon.setImageResource(R.drawable.ic_email);
                 }
             } else {
-                try {
-                    icon.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension));
-                } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
-                    icon.setImageResource(R.drawable.ic_user);
-                }
+                icon.setTag(share.getShareWith());
+                DisplayUtils.setAvatar(account, share.getShareWith(), this, avatarRadiusDimension,
+                        context.getResources(), storageManager, icon, context);
             }
             userName.setText(name);
 
@@ -237,6 +236,23 @@ public class UserListAdapter extends ArrayAdapter {
         );
     }
 
+    @Override
+    public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
+        if (callContext instanceof ImageView) {
+            ImageView iv = (ImageView) callContext;
+            iv.setImageDrawable(avatarDrawable);
+        }
+    }
+
+    @Override
+    public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
+        if (callContext instanceof ImageView) {
+            ImageView iv = (ImageView) callContext;
+            return String.valueOf(iv.getTag()).equals(tag);
+        }
+        return false;
+    }
+
     public interface ShareeListAdapterListener {
         /**
          * unshare with given sharee {@link OCShare}.

+ 5 - 5
src/main/java/com/owncloud/android/utils/BitmapUtils.java

@@ -34,9 +34,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 
 import org.apache.commons.codec.binary.Hex;
 
-import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.util.Locale;
 
 /**
@@ -269,10 +267,8 @@ public class BitmapUtils {
      *
      * @param name The name
      * @return corresponding RGB color
-     * @throws UnsupportedEncodingException if the charset is not supported
-     * @throws NoSuchAlgorithmException if the specified algorithm is not available
      */
-    public static int[] calculateHSL(String name) throws UnsupportedEncodingException, NoSuchAlgorithmException {
+    public static int[] calculateHSL(String name) {
         // using adapted algorithm from https://github.com/nextcloud/server/blob/master/core/js/placeholder.js#L126
 
         String[] result = new String[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"};
@@ -375,6 +371,10 @@ public class BitmapUtils {
      * @return the circular bitmap
      */
     public static RoundedBitmapDrawable bitmapToCircularBitmapDrawable(Resources resources, Bitmap bitmap) {
+        if (bitmap == null) {
+            return null;
+        }
+        
         RoundedBitmapDrawable roundedBitmap = RoundedBitmapDrawableFactory.create(resources, bitmap);
         roundedBitmap.setCircular(true);
         return roundedBitmap;

+ 55 - 32
src/main/java/com/owncloud/android/utils/DisplayUtils.java

@@ -25,6 +25,7 @@
 package com.owncloud.android.utils;
 
 import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.Activity;
@@ -433,50 +434,72 @@ public class DisplayUtils {
     }
 
     /**
-     * fetches and sets the avatar of the current account in the drawer in case the drawer is available.
+     * fetches and sets the avatar of the given account in the passed callContext
      *
-     * @param account        the account to be set in the drawer
+     * @param account        the account to be used to connect to server
      * @param avatarRadius   the avatar radius
      * @param resources      reference for density information
      * @param storageManager reference for caching purposes
+     * @param callContext    which context is called to set the generated avatar
      */
-    public static void setAvatar(Account account, AvatarGenerationListener listener, float avatarRadius,
-                                 Resources resources, FileDataStorageManager storageManager, Object callContext) {
-        if (account != null) {
-            if (callContext instanceof View) {
-                ((View) callContext).setContentDescription(account.name);
-            }
+    public static void setAvatar(@NonNull Account account, AvatarGenerationListener listener,
+                                 float avatarRadius, Resources resources, FileDataStorageManager storageManager,
+                                 Object callContext, Context context) {
+
+        AccountManager accountManager = AccountManager.get(context);
+        String userId = accountManager.getUserData(account,
+                com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
+
+        setAvatar(account, userId, listener, avatarRadius, resources, storageManager, callContext, context);
+    }
+
+    /**
+     * fetches and sets the avatar of the given account in the passed callContext
+     *
+     * @param account        the account to be used to connect to server
+     * @param userId         the userId which avatar should be set
+     * @param avatarRadius   the avatar radius
+     * @param resources      reference for density information
+     * @param storageManager reference for caching purposes
+     * @param callContext    which context is called to set the generated avatar
+     */
+    public static void setAvatar(@NonNull Account account, @NonNull String userId, AvatarGenerationListener listener,
+                                 float avatarRadius, Resources resources, FileDataStorageManager storageManager,
+                                 Object callContext, Context context) {
+        if (callContext instanceof View) {
+            ((View) callContext).setContentDescription(userId);
+        }
 
-            ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(
-                    MainApp.getAppContext().getContentResolver());
+        ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
 
-            String eTag = arbitraryDataProvider.getValue(account, ThumbnailsCacheManager.AVATAR);
+        String serverName = account.name.substring(account.name.lastIndexOf('@') + 1, account.name.length());
+        String eTag = arbitraryDataProvider.getValue(userId + "@" + serverName, ThumbnailsCacheManager.AVATAR);
+        String avatarKey = "a_" + userId + "_" + serverName + "_" + eTag;
 
-            // first show old one
-            Drawable avatar = BitmapUtils.bitmapToCircularBitmapDrawable(resources,
-                    ThumbnailsCacheManager.getBitmapFromDiskCache("a_" + account.name + "_" + eTag));
+        // first show old one
+        Drawable avatar = BitmapUtils.bitmapToCircularBitmapDrawable(resources,
+                ThumbnailsCacheManager.getBitmapFromDiskCache(avatarKey));
 
-            // if no one exists, show colored icon with initial char
-            if (avatar == null) {
-                try {
-                    avatar = TextDrawable.createAvatar(account.name, avatarRadius);
-                } catch (Exception e) {
-                    Log_OC.e(TAG, "Error calculating RGB value for active account icon.", e);
-                    avatar = resources.getDrawable(R.drawable.account_circle_white);
-                }
+        // if no one exists, show colored icon with initial char
+        if (avatar == null) {
+            try {
+                avatar = TextDrawable.createAvatarByUserId(userId, avatarRadius);
+            } catch (Exception e) {
+                Log_OC.e(TAG, "Error calculating RGB value for active account icon.", e);
+                avatar = resources.getDrawable(R.drawable.account_circle_white);
             }
+        }
 
-            // check for new avatar, eTag is compared, so only new one is downloaded
-            if (ThumbnailsCacheManager.cancelPotentialAvatarWork(account.name, callContext)) {
-                final ThumbnailsCacheManager.AvatarGenerationTask task =
-                        new ThumbnailsCacheManager.AvatarGenerationTask(listener, callContext, storageManager,
-                                account, resources, avatarRadius);
+        // check for new avatar, eTag is compared, so only new one is downloaded
+        if (ThumbnailsCacheManager.cancelPotentialAvatarWork(userId, callContext)) {
+            final ThumbnailsCacheManager.AvatarGenerationTask task =
+                    new ThumbnailsCacheManager.AvatarGenerationTask(listener, callContext, storageManager,
+                            account, resources, avatarRadius, userId, serverName, context);
 
-                final ThumbnailsCacheManager.AsyncAvatarDrawable asyncDrawable =
-                        new ThumbnailsCacheManager.AsyncAvatarDrawable(resources, avatar, task);
-                listener.avatarGenerated(asyncDrawable, callContext);
-                task.execute(account.name);
-            }
+            final ThumbnailsCacheManager.AsyncAvatarDrawable asyncDrawable =
+                    new ThumbnailsCacheManager.AsyncAvatarDrawable(resources, avatar, task);
+            listener.avatarGenerated(asyncDrawable, callContext);
+            task.execute(userId);
         }
     }