Add a way to display the avatar of a contact.
little quick and dirty but it will be good until the Contact API.
--- a/res/layout/contactlistcontact.xml Tue Oct 26 00:59:27 2010 +0200
+++ b/res/layout/contactlistcontact.xml Mon Nov 01 23:57:34 2010 +0100
@@ -1,20 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="fill_parent"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content" android:paddingLeft="10px"
android:paddingRight="10px" android:paddingTop="8dip"
android:paddingBottom="8dip" >
+ <ImageView android:id="@+id/avatar"
+ android:layout_width="48dip" android:layout_height="48dip"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ />
<TextView android:id="@+id/contactlistpseudo"
android:layout_width="fill_parent" android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/avatar"
android:singleLine="true"
android:maxLines="1" android:textColor="@color/white"
android:drawablePadding="12px"
+ android:paddingLeft="10dip"
android:textSize="18sp" android:textStyle="bold" />
<TextView android:id="@+id/contactlistmsgperso"
android:layout_width="fill_parent" android:layout_height="wrap_content"
+ android:layout_below="@id/contactlistpseudo"
+ android:layout_toRightOf="@id/avatar"
android:paddingLeft="30px" android:singleLine="true"
android:maxLines="1" android:linksClickable="false" android:autoLink="all"
android:scrollHorizontally="true" android:textColorLink="@color/white"
android:textSize="12sp" />
-</LinearLayout>
+</RelativeLayout>
--- a/src/com/beem/project/beem/service/Contact.java Tue Oct 26 00:59:27 2010 +0200
+++ b/src/com/beem/project/beem/service/Contact.java Mon Nov 01 23:57:34 2010 +0100
@@ -85,6 +85,7 @@
private List<String> mRes;
private final List<String> mGroups = new ArrayList<String>();
private String mName;
+ private String mAvatarId;
/**
* Construct a contact from a parcel.
@@ -97,6 +98,7 @@
mSelectedRes = in.readString();
mName = in.readString();
mMsgState = in.readString();
+ mAvatarId = in.readString();
mRes = new ArrayList<String>();
in.readStringList(mRes);
in.readStringList(mGroups);
@@ -148,6 +150,7 @@
dest.writeString(mSelectedRes);
dest.writeString(mName);
dest.writeString(mMsgState);
+ dest.writeString(mAvatarId);
dest.writeStringList(getMRes());
dest.writeStringList(getGroups());
}
@@ -258,6 +261,10 @@
return mStatus;
}
+ public String getAvatarId() {
+ return mAvatarId;
+ }
+
/**
* Set the groups the contact is in.
* @param groups list of groups
@@ -286,6 +293,10 @@
mID = mid;
}
+ public void setAvatarId(String avatarId) {
+ mAvatarId = avatarId;
+ }
+
/**
* Set the resource of the contact.
* @param resource to set.
--- a/src/com/beem/project/beem/service/RosterAdapter.java Tue Oct 26 00:59:27 2010 +0200
+++ b/src/com/beem/project/beem/service/RosterAdapter.java Mon Nov 01 23:57:34 2010 +0100
@@ -66,6 +66,10 @@
import com.beem.project.beem.R;
import com.beem.project.beem.service.aidl.IBeemRosterListener;
import com.beem.project.beem.utils.Status;
+import com.beem.project.beem.smack.avatar.AvatarMetadataExtension;
+import com.beem.project.beem.smack.avatar.AvatarMetadataExtension.Info;
+import com.beem.project.beem.smack.avatar.AvatarManager;
+import com.beem.project.beem.smack.avatar.AvatarListener;
/**
* This class implement a Roster adapter for BEEM.
@@ -78,6 +82,8 @@
new RemoteCallbackList<IBeemRosterListener>();
private final Map<Integer, String> mDefaultStatusMessages;
private final RosterListenerAdapter mRosterListener = new RosterListenerAdapter();
+ private Map<String, String> mAvatarIdmap = new HashMap<String, String>();
+ private AvatarManager mAvatarManager;
/**
* Constructor.
@@ -91,6 +97,21 @@
}
/**
+ * Constructor.
+ * @param roster The roster to adapt.
+ * @param context The context of the RosterAdapter.
+ */
+ public RosterAdapter(final Roster roster, final Context context, final AvatarManager avatarMgr) {
+ mAdaptee = roster;
+ roster.addRosterListener(mRosterListener);
+ mDefaultStatusMessages = createDefaultStatusMessagesMap(context);
+ mAvatarManager = avatarMgr;
+ if (mAvatarManager != null)
+ mAvatarManager.addAvatarListener(new AvatarEventListener());
+ }
+
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -242,7 +263,7 @@
try {
c.setGroups(entry.getGroups());
} catch (NullPointerException e) {
- Log.d(TAG, "Group list not ready");
+ Log.d(TAG, "Group list not ready", e);
}
Iterator<Presence> iPres = mAdaptee.getPresences(user);
while (iPres.hasNext()) {
@@ -251,6 +272,7 @@
c.addRes(StringUtils.parseResource(p.getFrom()));
}
c.setName(entry.getName());
+ c.setAvatarId(mAvatarIdmap.get(user));
return c;
}
@@ -357,6 +379,8 @@
for (int i = 0; i < n; i++) {
IBeemRosterListener listener = mRemoteRosListeners.getBroadcastItem(i);
try {
+ if (!presence.isAvailable())
+ mAvatarIdmap.remove(StringUtils.parseBareAddress(presence.getFrom()));
if (presence.getStatus() == null || "".equals(presence.getStatus())) {
presence.setStatus(mDefaultStatusMessages.get(Status.getStatusFromPresence(presence)));
}
@@ -368,4 +392,21 @@
mRemoteRosListeners.finishBroadcast();
}
}
+
+ /**
+ * Listener on avatar metadata event.
+ *
+ */
+ private class AvatarEventListener implements AvatarListener {
+
+ @Override
+ public void onAvatarChange(String from, String avatarId, List<Info> avatarInfos) {
+ String bare = StringUtils.parseBareAddress(from);
+ if (avatarId == null)
+ mAvatarIdmap.remove(bare);
+ else {
+ mAvatarIdmap.put(bare, avatarId);
+ }
+ }
+ }
}
--- a/src/com/beem/project/beem/service/XmppConnectionAdapter.java Tue Oct 26 00:59:27 2010 +0200
+++ b/src/com/beem/project/beem/service/XmppConnectionAdapter.java Mon Nov 01 23:57:34 2010 +0100
@@ -81,6 +81,7 @@
import com.beem.project.beem.ui.Subscription;
import com.beem.project.beem.utils.BeemBroadcastReceiver;
import com.beem.project.beem.utils.Status;
+import com.beem.project.beem.smack.pep.PepSubManager;
import com.beem.project.beem.smack.avatar.AvatarCache;
import com.beem.project.beem.smack.avatar.FileAvatarCache;
import com.beem.project.beem.smack.avatar.AvatarManager;
@@ -112,6 +113,8 @@
private ChatStateManager mChatStateManager;
private final BeemService mService;
private BeemApplication mApplication;
+ private AvatarManager mAvatarManager;
+ private PepSubManager mPepManager;
private final RemoteCallbackList<IBeemConnectionListener> mRemoteConnListeners =
new RemoteCallbackList<IBeemConnectionListener>();
private final SubscribePacketListener mSubscribePacketListener = new SubscribePacketListener();
@@ -239,6 +242,7 @@
mService.initJingle(mAdaptee);
discoverServerFeatures();
+ mRoster = new RosterAdapter(mAdaptee.getRoster(), mService, mAvatarManager);
mApplication.setConnected(true);
changeStatus(Status.CONTACT_STATUS_AVAILABLE, mService.getServicePreference().getString("status_text", ""));
return true;
@@ -319,6 +323,10 @@
changeStatusAndPriority(status, msg, mPreviousPriority);
}
+ public AvatarManager getAvatarManager() {
+ return mAvatarManager;
+ }
+
/**
* get the previous status.
* @return previous status.
@@ -388,7 +396,7 @@
Roster adap = mAdaptee.getRoster();
if (adap == null)
return null;
- mRoster = new RosterAdapter(adap, mService);
+ mRoster = new RosterAdapter(adap, mService, mAvatarManager);
return mRoster;
}
@@ -485,10 +493,11 @@
// Enable pep sending
// API 8
// mService.getExternalCacheDir()
+ mPepManager = new PepSubManager(mAdaptee);
File cacheDir = Environment.getExternalStorageDirectory();
cacheDir = new File(cacheDir, "/Android/data/com.beem.project.beem/cache/");
AvatarCache avatarCache = new FileAvatarCache(cacheDir);
- new AvatarManager(mAdaptee, avatarCache, true);
+ mAvatarManager = new AvatarManager(mAdaptee, mPepManager, avatarCache, true);
}
/**
--- a/src/com/beem/project/beem/service/XmppFacade.java Tue Oct 26 00:59:27 2010 +0200
+++ b/src/com/beem/project/beem/service/XmppFacade.java Mon Nov 01 23:57:34 2010 +0100
@@ -55,6 +55,7 @@
import com.beem.project.beem.service.aidl.IXmppConnection;
import com.beem.project.beem.service.aidl.IXmppFacade;
import com.beem.project.beem.utils.PresenceType;
+import com.beem.project.beem.smack.avatar.AvatarManager;
/**
* This class is a facade for the Beem Service.
@@ -150,19 +151,12 @@
public void call(String jid) throws RemoteException {
}
- /* (non-Javadoc)
- * @see com.beem.project.beem.service.aidl.IXmppFacade#getVcardAvatar(java.lang.String)
- */
@Override
- public byte[] getVcardAvatar(String jid) throws RemoteException {
- VCard vcard = new VCard();
+ public byte[] getAvatar(String avatarId) throws RemoteException {
+ AvatarManager mgr = mConnexion.getAvatarManager();
+ if (mgr == null)
+ return null;
- try {
- vcard.load(mConnexion.getAdaptee(), jid);
- return vcard.getAvatar();
- } catch (XMPPException e) {
- e.printStackTrace();
- }
- return null;
+ return mgr.getAvatar(avatarId);
}
}
--- a/src/com/beem/project/beem/service/aidl/IXmppFacade.aidl Tue Oct 26 00:59:27 2010 +0200
+++ b/src/com/beem/project/beem/service/aidl/IXmppFacade.aidl Mon Nov 01 23:57:34 2010 +0100
@@ -97,10 +97,10 @@
void call(in String jid);
/**
- * get the user vcard avatar
- * @param jid the user jid
+ * get the an avatar
+ * @param id the id of the avatar
*/
- byte[] getVcardAvatar(in String jid);
+ byte[] getAvatar(in String id);
IPrivacyListManager getPrivacyListManager();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/smack/avatar/AvatarListener.java Mon Nov 01 23:57:34 2010 +0100
@@ -0,0 +1,10 @@
+package com.beem.project.beem.smack.avatar;
+
+import java.util.List;
+import com.beem.project.beem.smack.avatar.AvatarMetadataExtension.Info;
+
+public interface AvatarListener {
+
+ void onAvatarChange(String from, String avatarId, List<Info> avatarInfos);
+
+}
--- a/src/com/beem/project/beem/smack/avatar/AvatarManager.java Tue Oct 26 00:59:27 2010 +0200
+++ b/src/com/beem/project/beem/smack/avatar/AvatarManager.java Mon Nov 01 23:57:34 2010 +0100
@@ -50,6 +50,7 @@
import java.io.IOException;
import java.util.List;
+import java.util.LinkedList;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.packet.PacketExtension;
@@ -67,6 +68,7 @@
private Connection mCon;
private boolean mAutoDownload;
private AvatarCache mCache;
+ private final List<AvatarListener> mListeners = new LinkedList<AvatarListener>();
/**
* Create an AvatarManager.
@@ -75,13 +77,12 @@
* @param cache the cache which will store the avatars
* @param autoDownload true to enable auto download of avatars
*/
- public AvatarManager(final Connection con, final AvatarCache cache, final boolean autoDownload) {
+ public AvatarManager(final Connection con, final PepSubManager pepMgr, final AvatarCache cache, final boolean autoDownload) {
mCon = con;
- mPep = new PepSubManager(mCon);
+ mPep = pepMgr;
mAutoDownload = autoDownload;
mCache = cache;
- if (mAutoDownload)
- mPep.addPEPListener(new Listener());
+ mPep.addPEPListener(new Listener());
}
/**
@@ -91,6 +92,8 @@
* @return the avatar or null if it cannot be retrieved from the cache
*/
public byte[] getAvatar(String avatarId) {
+ if (avatarId == null)
+ return null;
try {
return mCache.get(avatarId);
} catch (IOException e) {
@@ -98,6 +101,16 @@
}
}
+ public void addAvatarListener(AvatarListener listener) {
+ if (!mListeners.contains(listener))
+ mListeners.add(listener);
+ }
+
+ public void removeAvatarListener(AvatarListener listener){
+ mListeners.remove(listener);
+ }
+
+
/**
* Select the avatar to download.
* Subclass should override this method to take control over the selection process.
@@ -110,21 +123,28 @@
return available.get(0);
}
+ private void fireListeners(String from, String avatarId, List<Info> avatarInfos) {
+ for(AvatarListener l : mListeners)
+ l.onAvatarChange(from, avatarId, avatarInfos);
+ }
+
/**
- * Doawload an avatar.
+ * Download an avatar.
*
* @param from The jid of the user
* @param info the metadata information of the avatar to download
*/
- private void downloadAvatar(String from, Info info) {
+ public boolean downloadAvatar(String from, String avatarId, Info info) {
try {
AvatarRetriever retriever = AvatarRetrieverFactory.getRetriever(mCon, from, info);
byte[] avatar = retriever.getAvatar();
// TODO check the hash before store
- mCache.put(info.getId(), avatar);
+ mCache.put(avatarId, avatar);
+ return true;
} catch (IOException e) {
System.err.println("Error while downloading avatar");
e.printStackTrace();
+ return false;
}
}
@@ -141,15 +161,22 @@
@Override
public void eventReceived(String from, String node, List<Item> items) {
+ if (!node.equals("urn:xmpp:avatar:metadata"))
+ return;
Item i = items.get(0);
if (i instanceof PayloadItem) {
PayloadItem<PacketExtension> pi = (PayloadItem<PacketExtension>) i;
PacketExtension ex = pi.getPayload();
if (ex instanceof AvatarMetadataExtension) {
AvatarMetadataExtension ext = (AvatarMetadataExtension) ex;
- Info info = selectAvatar(ext.getInfos());
- if (!mCache.contains(info.getId()))
- downloadAvatar(from, info);
+ String id = i.getId();
+ List<Info> infos = ext.getInfos();
+ if (infos.size() > 0 && mAutoDownload) {
+ Info info = selectAvatar(infos);
+ if (!mCache.contains(id))
+ downloadAvatar(from, id, info);
+ }
+ fireListeners(from, id, infos);
}
}
}
--- a/src/com/beem/project/beem/ui/ContactList.java Tue Oct 26 00:59:27 2010 +0200
+++ b/src/com/beem/project/beem/ui/ContactList.java Mon Nov 01 23:57:34 2010 +0100
@@ -49,6 +49,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.io.ByteArrayInputStream;
import org.jivesoftware.smack.util.StringUtils;
@@ -81,9 +82,11 @@
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.Gallery;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
+import android.graphics.drawable.Drawable;
import com.beem.project.beem.R;
import com.beem.project.beem.service.Contact;
@@ -660,6 +663,23 @@
v.setText(curContact.getName());
v = (TextView) view.findViewById(R.id.contactlistmsgperso);
v.setText(curContact.getMsgState());
+ Drawable d = null;
+ try {
+ String avatarId = curContact.getAvatarId();
+ Log.d(TAG, "Avatar id = " + avatarId );
+ byte[] avatar = mXmppFacade.getAvatar(avatarId);
+ if (avatar != null) {
+ ByteArrayInputStream in = new ByteArrayInputStream(avatar);
+ d = Drawable.createFromStream(in, avatarId);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error while setting the avatar", e);
+ }
+ ImageView img = (ImageView) view.findViewById(R.id.avatar);
+ if (d != null)
+ img.setImageDrawable(d);
+ else
+ img.setImageResource(R.drawable.beem_launcher_icon_silver);
}
}