AccountAdapter.java

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