/* * Kontalk Android client * Copyright (C) 2017 Kontalk Devteam <devteam@kontalk.org> * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kontalk.ui.view; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; import android.support.v4.content.ContextCompat; import android.view.View; import android.view.ViewStub; import android.widget.LinearLayout; import org.kontalk.R; import org.kontalk.data.Contact; import org.kontalk.util.SystemUtils; /** * Avatar-based message balloon theme. * @author Daniele Ricci */ public class AvatarMessageTheme extends BaseMessageTheme implements Contact.ContactCallback { private static Drawable sDefaultContactImage; private final int mDrawableId; /** If true, handles collapsed message blocks (hides adjacent avatars). */ private final boolean mMessageBlocks; protected LinearLayout mBalloonView; protected CircleContactBadge mAvatar; private Handler mHandler; public AvatarMessageTheme(int layoutId, int drawableId, boolean messageBlocks) { super(layoutId); mDrawableId = drawableId; mMessageBlocks = messageBlocks; } @Override public View inflate(ViewStub stub) { View view = super.inflate(stub); mBalloonView = (LinearLayout) view.findViewById(R.id.balloon_view); mAvatar = (CircleContactBadge) view.findViewById(R.id.avatar); mHandler = new Handler(); if (sDefaultContactImage == null) { sDefaultContactImage = ContextCompat .getDrawable(mContext, R.drawable.ic_default_contact); } return view; } @Override public boolean isFullWidth() { return false; } @Override public void processComponentView(MessageContentView<?> view) { if (view instanceof TextContentView) { ((TextContentView) view).enableMeasureHack(true); } } protected void setView(boolean sameMessageBlock) { if (mBalloonView != null) { mBalloonView.setBackgroundResource(mDrawableId); } } @Override public void setIncoming(Contact contact, boolean sameMessageBlock) { setView(sameMessageBlock); if (mAvatar != null) { if (mMessageBlocks && sameMessageBlock) { mAvatar.setVisibility(View.INVISIBLE); mAvatar.setImageDrawable(null); } else { mAvatar.setImageDrawable(sDefaultContactImage); if (contact != null) { // we mark this with the contact's hash code for the async avatar mAvatar.setTag(contact.hashCode()); mAvatar.assignContactUri(contact.getUri()); contact.getAvatarAsync(mContext, this); } else { mAvatar.setTag(null); mAvatar.assignContactUri(null); } mAvatar.setVisibility(View.VISIBLE); } } super.setIncoming(contact, sameMessageBlock); } @Override public void setOutgoing(Contact contact, int status, boolean sameMessageBlock) { setView(sameMessageBlock); if (mAvatar != null) { if (mMessageBlocks && sameMessageBlock) { mAvatar.setVisibility(View.INVISIBLE); mAvatar.setImageDrawable(null); } else { Drawable avatar; Bitmap profile = SystemUtils.getProfilePhoto(mContext); if (profile != null) { avatar = new BitmapDrawable(mContext.getResources(), profile); } else { avatar = sDefaultContactImage; } mAvatar.setImageDrawable(avatar); mAvatar.assignContactUri(SystemUtils.getProfileUri(mContext)); mAvatar.setVisibility(View.VISIBLE); } } super.setOutgoing(contact, status, sameMessageBlock); } @Override public void avatarLoaded(final Contact contact, final Drawable avatar) { if (avatar != null) { if (mHandler.getLooper().getThread() != Thread.currentThread()) { mHandler.post(new Runnable() { public void run() { updateAvatar(contact, avatar); } }); } else { updateAvatar(contact, avatar); } } } void updateAvatar(Contact contact, Drawable avatar) { try { // be sure the contact is still the same // this is an insane workaround against race conditions Integer contactTag = (Integer) mAvatar.getTag(); if (contactTag != null && contactTag == contact.hashCode()) mAvatar.setImageDrawable(avatar); } catch (Exception e) { // we are deliberately ignoring any exception here // because an error here could happen only if something // weird is happening, e.g. user leaving the activity } } }