AccountAdapter.java

  1package eu.siacs.conversations.ui.adapter;
  2
  3import android.content.res.Resources;
  4import android.databinding.DataBindingUtil;
  5import android.graphics.Bitmap;
  6import android.graphics.drawable.BitmapDrawable;
  7import android.graphics.drawable.Drawable;
  8import android.os.AsyncTask;
  9import android.support.annotation.NonNull;
 10import android.view.LayoutInflater;
 11import android.view.View;
 12import android.view.ViewGroup;
 13import android.widget.ArrayAdapter;
 14import android.widget.ImageView;
 15
 16import java.lang.ref.WeakReference;
 17import java.util.List;
 18import java.util.concurrent.RejectedExecutionException;
 19
 20import eu.siacs.conversations.Config;
 21import eu.siacs.conversations.R;
 22import eu.siacs.conversations.databinding.AccountRowBinding;
 23import eu.siacs.conversations.entities.Account;
 24import eu.siacs.conversations.ui.XmppActivity;
 25import eu.siacs.conversations.ui.util.StyledAttributes;
 26import eu.siacs.conversations.utils.UIHelper;
 27
 28public class AccountAdapter extends ArrayAdapter<Account> {
 29
 30    private XmppActivity activity;
 31    private boolean showStateButton;
 32
 33    public AccountAdapter(XmppActivity activity, List<Account> objects, boolean showStateButton) {
 34        super(activity, 0, objects);
 35        this.activity = activity;
 36        this.showStateButton = showStateButton;
 37    }
 38
 39    public AccountAdapter(XmppActivity activity, List<Account> objects) {
 40        super(activity, 0, objects);
 41        this.activity = activity;
 42        this.showStateButton = true;
 43    }
 44
 45    @Override
 46    public View getView(int position, View view, @NonNull ViewGroup parent) {
 47        final Account account = getItem(position);
 48        final ViewHolder viewHolder;
 49        if (view == null) {
 50            AccountRowBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.account_row, parent, false);
 51            view = binding.getRoot();
 52            viewHolder = new ViewHolder(binding);
 53            view.setTag(viewHolder);
 54        } else {
 55            viewHolder = (ViewHolder) view.getTag();
 56        }
 57        if (Config.DOMAIN_LOCK != null) {
 58            viewHolder.binding.accountJid.setText(account.getJid().getLocal());
 59        } else {
 60            viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toString());
 61        }
 62        loadAvatar(account, viewHolder.binding.accountImage);
 63        viewHolder.binding.accountStatus.setText(getContext().getString(account.getStatus().getReadableId()));
 64        switch (account.getStatus()) {
 65            case ONLINE:
 66                viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline));
 67                break;
 68            case DISABLED:
 69            case CONNECTING:
 70                viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary));
 71                break;
 72            default:
 73                viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorError));
 74                break;
 75        }
 76        final boolean isDisabled = (account.getStatus() == Account.State.DISABLED);
 77        viewHolder.binding.tglAccountStatus.setOnCheckedChangeListener(null);
 78        viewHolder.binding.tglAccountStatus.setChecked(!isDisabled);
 79        if (this.showStateButton) {
 80            viewHolder.binding.tglAccountStatus.setVisibility(View.VISIBLE);
 81        } else {
 82            viewHolder.binding.tglAccountStatus.setVisibility(View.GONE);
 83        }
 84        viewHolder.binding.tglAccountStatus.setOnCheckedChangeListener((compoundButton, b) -> {
 85            if (b == isDisabled && activity instanceof OnTglAccountState) {
 86                ((OnTglAccountState) activity).onClickTglAccountState(account, b);
 87            }
 88        });
 89        return view;
 90    }
 91
 92    private static class ViewHolder {
 93        private final AccountRowBinding binding;
 94
 95        private ViewHolder(AccountRowBinding binding) {
 96            this.binding = binding;
 97        }
 98    }
 99
100    private static class BitmapWorkerTask extends AsyncTask<Account, Void, Bitmap> {
101        private final WeakReference<ImageView> imageViewReference;
102        private Account account = null;
103
104        BitmapWorkerTask(ImageView imageView) {
105            imageViewReference = new WeakReference<>(imageView);
106        }
107
108        @Override
109        protected Bitmap doInBackground(Account... params) {
110            this.account = params[0];
111            final XmppActivity activity = XmppActivity.find(imageViewReference);
112            if (activity == null) {
113                return null;
114            }
115            return activity.avatarService().get(this.account, activity.getPixel(48), isCancelled());
116        }
117
118        @Override
119        protected void onPostExecute(Bitmap bitmap) {
120            if (bitmap != null && !isCancelled()) {
121                final ImageView imageView = imageViewReference.get();
122                if (imageView != null) {
123                    imageView.setImageBitmap(bitmap);
124                    imageView.setBackgroundColor(0x00000000);
125                }
126            }
127        }
128    }
129
130    private void loadAvatar(Account account, ImageView imageView) {
131        if (cancelPotentialWork(account, imageView)) {
132            final Bitmap bm = activity.avatarService().get(account, activity.getPixel(48), true);
133            if (bm != null) {
134                cancelPotentialWork(account, imageView);
135                imageView.setImageBitmap(bm);
136                imageView.setBackgroundColor(0x00000000);
137            } else {
138                imageView.setBackgroundColor(UIHelper.getColorForName(account.getJid().asBareJid().toString()));
139                imageView.setImageDrawable(null);
140                final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
141                final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
142                imageView.setImageDrawable(asyncDrawable);
143                try {
144                    task.execute(account);
145                } catch (final RejectedExecutionException ignored) {
146                }
147            }
148        }
149    }
150
151
152    public interface OnTglAccountState {
153        void onClickTglAccountState(Account account, boolean state);
154    }
155
156    private static boolean cancelPotentialWork(Account account, ImageView imageView) {
157        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
158
159        if (bitmapWorkerTask != null) {
160            final Account oldAccount = bitmapWorkerTask.account;
161            if (oldAccount == null || account != oldAccount) {
162                bitmapWorkerTask.cancel(true);
163            } else {
164                return false;
165            }
166        }
167        return true;
168    }
169
170    private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
171        if (imageView != null) {
172            final Drawable drawable = imageView.getDrawable();
173            if (drawable instanceof AsyncDrawable) {
174                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
175                return asyncDrawable.getBitmapWorkerTask();
176            }
177        }
178        return null;
179    }
180
181    static class AsyncDrawable extends BitmapDrawable {
182        private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
183
184        AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
185            super(res, bitmap);
186            bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
187        }
188
189        BitmapWorkerTask getBitmapWorkerTask() {
190            return bitmapWorkerTaskReference.get();
191        }
192    }
193}