# HG changeset patch # User Da Risk # Date 1288652254 -3600 # Node ID 98d220b7fe9dce322423b88cef3bb14bb1367abf # Parent e4b9ec9f30e6b00dde44b45ef1ce14ff1427eeb4 Add a way to display the avatar of a contact. little quick and dirty but it will be good until the Contact API. diff -r e4b9ec9f30e6 -r 98d220b7fe9d res/layout/contactlistcontact.xml --- 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 @@ - + - + diff -r e4b9ec9f30e6 -r 98d220b7fe9d src/com/beem/project/beem/service/Contact.java --- 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 mRes; private final List mGroups = new ArrayList(); 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(); 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. diff -r e4b9ec9f30e6 -r 98d220b7fe9d src/com/beem/project/beem/service/RosterAdapter.java --- 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(); private final Map mDefaultStatusMessages; private final RosterListenerAdapter mRosterListener = new RosterListenerAdapter(); + private Map mAvatarIdmap = new HashMap(); + 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 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 avatarInfos) { + String bare = StringUtils.parseBareAddress(from); + if (avatarId == null) + mAvatarIdmap.remove(bare); + else { + mAvatarIdmap.put(bare, avatarId); + } + } + } } diff -r e4b9ec9f30e6 -r 98d220b7fe9d src/com/beem/project/beem/service/XmppConnectionAdapter.java --- 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 mRemoteConnListeners = new RemoteCallbackList(); 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); } /** diff -r e4b9ec9f30e6 -r 98d220b7fe9d src/com/beem/project/beem/service/XmppFacade.java --- 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); } } diff -r e4b9ec9f30e6 -r 98d220b7fe9d src/com/beem/project/beem/service/aidl/IXmppFacade.aidl --- 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(); } diff -r e4b9ec9f30e6 -r 98d220b7fe9d src/com/beem/project/beem/smack/avatar/AvatarListener.java --- /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 avatarInfos); + +} diff -r e4b9ec9f30e6 -r 98d220b7fe9d src/com/beem/project/beem/smack/avatar/AvatarManager.java --- 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 mListeners = new LinkedList(); /** * 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 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 items) { + if (!node.equals("urn:xmpp:avatar:metadata")) + return; Item i = items.get(0); if (i instanceof PayloadItem) { PayloadItem pi = (PayloadItem) 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 infos = ext.getInfos(); + if (infos.size() > 0 && mAutoDownload) { + Info info = selectAvatar(infos); + if (!mCache.contains(id)) + downloadAvatar(from, id, info); + } + fireListeners(from, id, infos); } } } diff -r e4b9ec9f30e6 -r 98d220b7fe9d src/com/beem/project/beem/ui/ContactList.java --- 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); } }