Add a basic way to publish avatar.
authorDa Risk <darisk972@gmail.com>
Sun, 20 Feb 2011 03:16:35 +0100
changeset 880 d23d8ad3b9ba
parent 879 2236fe5b2db1
child 881 0ceee1f2b829
Add a basic way to publish avatar.
res/layout/changestatus.xml
res/values/strings.xml
src/com/beem/project/beem/BeemService.java
src/com/beem/project/beem/service/BeemAvatarCache.java
src/com/beem/project/beem/service/BeemAvatarManager.java
src/com/beem/project/beem/service/XmppConnectionAdapter.java
src/com/beem/project/beem/service/XmppFacade.java
src/com/beem/project/beem/service/aidl/IXmppFacade.aidl
src/com/beem/project/beem/smack/avatar/AvatarManager.java
src/com/beem/project/beem/ui/ChangeStatus.java
src/com/beem/project/beem/ui/ContactList.java
--- a/res/layout/changestatus.xml	Sat Mar 05 17:44:41 2011 +0100
+++ b/res/layout/changestatus.xml	Sun Feb 20 03:16:35 2011 +0100
@@ -5,8 +5,21 @@
 	<RelativeLayout android:orientation="vertical"
 		android:layout_width="fill_parent" android:layout_height="fill_parent"
 		android:padding="10dip">
+		<LinearLayout android:id="@+id/avatar_panel"
+		    android:orientation="vertical"
+		    android:gravity="center"
+		    android:layout_alignParentTop="true"
+		    android:layout_width="fill_parent" android:layout_height="fill_parent" >
+		    <TextView android:text="@string/my_avatar" style="@style/Label"
+			android:layout_width="wrap_content" android:layout_height="wrap_content" />
+
+		    <ImageButton android:id="@+id/avatarButton"
+			android:layout_width="120dip" android:layout_height="120dip"
+			android:scaleType="fitCenter" />
+		</LinearLayout>
 		<TextView android:id="@+id/ChangeStatusTypeLabel"
 			android:layout_width="fill_parent" android:layout_height="wrap_content"
+			android:layout_below="@id/avatar_panel"
 			android:text="@string/ChangeStatusType" style="@style/Label" />
 		<Spinner android:id="@+id/ChangeStatusSpinner"
 			android:layout_width="fill_parent" android:layout_height="wrap_content"
--- a/res/values/strings.xml	Sat Mar 05 17:44:41 2011 +0100
+++ b/res/values/strings.xml	Sun Feb 20 03:16:35 2011 +0100
@@ -55,6 +55,7 @@
 	<string name="MenuConnection">Edit account</string>
 	<string name="ChangeStatusOk">Updating status</string>
 	<string name="ChangeStatusNoChange">Nothing to change</string>
+	<string name="my_avatar">My avatar</string>
 
 	<!-- Settings class -->
 	<string name="SettingsText">Edit your username</string>
--- a/src/com/beem/project/beem/BeemService.java	Sat Mar 05 17:44:41 2011 +0100
+++ b/src/com/beem/project/beem/BeemService.java	Sun Feb 20 03:16:35 2011 +0100
@@ -45,6 +45,7 @@
 
 import org.jivesoftware.smack.ConnectionConfiguration;
 import org.jivesoftware.smack.Roster;
+import org.jivesoftware.smack.SmackConfiguration;
 import org.jivesoftware.smack.XMPPConnection;
 import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
 import org.jivesoftware.smack.Roster.SubscriptionMode;
@@ -132,6 +133,7 @@
      * Initialize the connection.
      */
     private void initConnectionConfig() {
+	SmackConfiguration.setPacketReplyTimeout(30000);
 	mUseProxy = mSettings.getBoolean(BeemApplication.PROXY_USE_KEY, false);
 	if (mUseProxy) {
 	    String stype = mSettings.getString(BeemApplication.PROXY_TYPE_KEY, "HTTP");
--- a/src/com/beem/project/beem/service/BeemAvatarCache.java	Sat Mar 05 17:44:41 2011 +0100
+++ b/src/com/beem/project/beem/service/BeemAvatarCache.java	Sun Feb 20 03:16:35 2011 +0100
@@ -125,7 +125,6 @@
     @Override
     public boolean contains(String key) {
 	Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(key).build();
-	uri = Uri.parse("content://com.beem.project.beem.providers.avatarprovider");
 	Cursor c = mContentResolver.query(uri, null, null, null, null);
 	boolean res = c.getCount() > 0;
 	c.close();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/service/BeemAvatarManager.java	Sun Feb 20 03:16:35 2011 +0100
@@ -0,0 +1,162 @@
+/*
+    BEEM is a videoconference application on the Android Platform.
+
+    Copyright (C) 2009 by Frederic-Charles Barthelery,
+                          Jean-Manuel Da Silva,
+                          Nikita Kozlov,
+                          Philippe Lago,
+                          Jean Baptiste Vergely,
+                          Vincent Veronis.
+
+    This file is part of BEEM.
+
+    BEEM 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.
+
+    BEEM 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 BEEM.  If not, see <http://www.gnu.org/licenses/>.
+
+    Please send bug reports with examples or suggestions to
+    contact@beem-project.com or http://dev.beem-project.com/
+
+    Epitech, hereby disclaims all copyright interest in the program "Beem"
+    written by Frederic-Charles Barthelery,
+               Jean-Manuel Da Silva,
+               Nikita Kozlov,
+               Philippe Lago,
+               Jean Baptiste Vergely,
+               Vincent Veronis.
+
+    Nicolas Sadirac, November 26, 2009
+    President of Epitech.
+
+    Flavien Astraud, November 26, 2009
+    Head of the EIP Laboratory.
+
+*/
+
+package com.beem.project.beem.service;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.provider.MediaStore;
+import android.util.Log;
+
+import com.beem.project.beem.smack.avatar.AvatarManager;
+import com.beem.project.beem.smack.avatar.AvatarCache;
+import com.beem.project.beem.smack.avatar.AvatarMetadataExtension;
+
+import java.security.NoSuchAlgorithmException;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import com.beem.project.beem.smack.pep.PepSubManager;
+import org.jivesoftware.smack.Connection;
+
+/**
+ * An AvatarManager for Beem.
+ * It allows to publish avatar on the Android platform.
+ */
+public class BeemAvatarManager extends AvatarManager {
+    private static final String TAG = BeemAvatarManager.class.getSimpleName();
+    private static final int JPEG_QUALITY = 100;
+
+    private Context mContext;
+
+    /**
+     * Create a BeemAvatarManager.
+     *
+     * @param con the connection
+     * @param pepMgr the PepSubManager of the connection
+     * @param cache the cache which will store the avatars
+     * @param autoDownload tre to enable auto download of avatars
+     */
+    public BeemAvatarManager(final Context ctx, final Connection con, final PepSubManager pepMgr,
+	    final AvatarCache cache, final boolean autoDownload) {
+	super(con, pepMgr, cache, autoDownload);
+	mContext = ctx;
+    }
+
+    public boolean publishAvatar(Uri avatarUri) {
+	try {
+	    Bitmap bmp = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), avatarUri);
+	    return publishAvatar(bmp);
+	} catch (IOException e) {
+	    Log.d(TAG, "Error while publishing avatar " + avatarUri, e);
+	}
+	return false;
+    }
+
+    /**
+     * Publish an avatar.
+     * This will send the XMPP stanza to enable the publication of an avatar.
+     *
+     * @param bitmap the avatar to publish
+     * @return true on success false otherwise
+     */
+    private boolean publishAvatar(Bitmap bitmap) {
+	AvatarMetadataExtension meta = new AvatarMetadataExtension();
+	// Probably a bug on prosody but only the last data sent is kept
+	// and in beem we retrieve the first info
+	AvatarMetadataExtension.Info jpeg = publishBitmap(bitmap, Bitmap.CompressFormat.JPEG, JPEG_QUALITY);
+	// The png format is mandatory for interoperability
+	AvatarMetadataExtension.Info png = publishBitmap(bitmap, Bitmap.CompressFormat.PNG, JPEG_QUALITY);
+	if (png == null)
+	    return false;
+	meta.addInfo(png);
+	if (jpeg != null)
+	    meta.addInfo(jpeg);
+	publishAvatarMetaData(png.getId(), meta);
+	return true;
+    }
+
+    /**
+     * Send this bitmap to the avatar data node of the pep server.
+     *
+     * @param bmp the avatar bitmap
+     * @param format the image format to publish this data
+     * @param quality the compression quality use for JPEG compression
+     * @return the resulting info associate with this bitmap. null if the operation failed
+     */
+    private AvatarMetadataExtension.Info publishBitmap(Bitmap bmp, Bitmap.CompressFormat format, int quality) {
+	try {
+	    byte[] data = getBitmapByte(bmp, format, quality);
+	    String dataid = getAvatarId(data);
+	    if (!publishAvatarData(data))
+		return null;
+	    String mimetype = "image/png";
+	    if (Bitmap.CompressFormat.JPEG == format)
+		mimetype = "image/jpeg";
+	    AvatarMetadataExtension.Info info = new AvatarMetadataExtension.Info(dataid, mimetype, data.length);
+	    info.setHeight(bmp.getHeight());
+	    info.setWidth(bmp.getWidth());
+	    return info;
+	} catch (NoSuchAlgorithmException ex) {
+	    return null;
+	}
+    }
+
+    /**
+     * Convert the bitmap to a byte array.
+     *
+     * @param bitmap the avatar bitmap
+     * @param format the resulting image format
+     * @param quality the compression quality use for JPEG compression
+     * @return the bitmap data or a array of 0 element on error
+     */
+    private byte[] getBitmapByte(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
+	ByteArrayOutputStream bos = new ByteArrayOutputStream();
+	if (bitmap.compress(format, quality, bos))
+	    return bos.toByteArray();
+	else
+	    return new byte[0];
+    }
+
+}
--- a/src/com/beem/project/beem/service/XmppConnectionAdapter.java	Sat Mar 05 17:44:41 2011 +0100
+++ b/src/com/beem/project/beem/service/XmppConnectionAdapter.java	Sun Feb 20 03:16:35 2011 +0100
@@ -81,7 +81,6 @@
 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.AvatarManager;
 
 /**
  * This class implements an adapter for XMPPConnection.
@@ -110,7 +109,7 @@
     private ChatStateManager mChatStateManager;
     private final BeemService mService;
     private BeemApplication mApplication;
-    private AvatarManager mAvatarManager;
+    private BeemAvatarManager mAvatarManager;
     private PepSubManager mPepManager;
     private SharedPreferences mPref;
     private final RemoteCallbackList<IBeemConnectionListener> mRemoteConnListeners =
@@ -329,7 +328,7 @@
      *
      * @return the AvatarManager or null if there is not
      */
-    public AvatarManager getAvatarManager() {
+    public BeemAvatarManager getAvatarManager() {
 	return mAvatarManager;
     }
 
@@ -502,7 +501,7 @@
 	// mService.getExternalCacheDir()
 	mPepManager = new PepSubManager(mAdaptee);
 	AvatarCache avatarCache = new BeemAvatarCache(mService);
-	mAvatarManager = new AvatarManager(mAdaptee, mPepManager, avatarCache, true);
+	mAvatarManager = new BeemAvatarManager(mService, mAdaptee, mPepManager, avatarCache, true);
     }
 
     /**
--- a/src/com/beem/project/beem/service/XmppFacade.java	Sat Mar 05 17:44:41 2011 +0100
+++ b/src/com/beem/project/beem/service/XmppFacade.java	Sun Feb 20 03:16:35 2011 +0100
@@ -45,6 +45,7 @@
 
 import org.jivesoftware.smack.packet.Presence;
 
+import android.net.Uri;
 import android.os.RemoteException;
 
 import com.beem.project.beem.service.aidl.IChatManager;
@@ -53,7 +54,6 @@
 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,11 +150,18 @@
     }
 
     @Override
-    public byte[] getAvatar(String avatarId) throws RemoteException {
-	AvatarManager mgr = mConnexion.getAvatarManager();
+    public boolean publishAvatar(Uri avatarUri) throws RemoteException {
+	BeemAvatarManager mgr = mConnexion.getAvatarManager();
 	if (mgr == null)
-	    return null;
+	    return false;
+
+	return mgr.publishAvatar(avatarUri);
+    }
 
-	return mgr.getAvatar(avatarId);
+    @Override
+    public void disableAvatarPublishing() throws RemoteException {
+	BeemAvatarManager mgr = mConnexion.getAvatarManager();
+	if (mgr != null)
+	    mgr.disableAvatarPublishing();
     }
 }
--- a/src/com/beem/project/beem/service/aidl/IXmppFacade.aidl	Sat Mar 05 17:44:41 2011 +0100
+++ b/src/com/beem/project/beem/service/aidl/IXmppFacade.aidl	Sun Feb 20 03:16:35 2011 +0100
@@ -48,6 +48,7 @@
 import  com.beem.project.beem.service.aidl.IChatManager;
 import  com.beem.project.beem.service.aidl.IPrivacyListManager;
 import com.beem.project.beem.service.PresenceAdapter;
+import android.net.Uri;
 
 interface IXmppFacade {
 
@@ -96,11 +97,10 @@
      */
      void call(in String jid);
 
-     /**
-      * get the an avatar
-      * @param id the id of the avatar
-      */
-     byte[] getAvatar(in String id);
+    boolean publishAvatar(in Uri avatarUri);
+
+    void disableAvatarPublishing();
+
 
      IPrivacyListManager getPrivacyListManager();
 }
--- a/src/com/beem/project/beem/smack/avatar/AvatarManager.java	Sat Mar 05 17:44:41 2011 +0100
+++ b/src/com/beem/project/beem/smack/avatar/AvatarManager.java	Sun Feb 20 03:16:35 2011 +0100
@@ -51,11 +51,15 @@
 
 import java.util.List;
 import java.util.LinkedList;
+import java.security.NoSuchAlgorithmException;
+import java.security.MessageDigest;
 
 import org.jivesoftware.smack.Connection;
 import org.jivesoftware.smack.packet.PacketExtension;
 import org.jivesoftware.smackx.pubsub.Item;
 import org.jivesoftware.smackx.pubsub.PayloadItem;
+import org.jivesoftware.smackx.pubsub.LeafNode;
+import org.jivesoftware.smack.util.StringUtils;
 
 /**
  * This class deals with the avatar data.
@@ -64,6 +68,11 @@
  */
 public class AvatarManager {
 
+    /**  The pubsub node for avatar data. */
+    public static final String AVATARDATA_NODE = "urn:xmpp:avatar:data";
+    /**  The pubsub node for avatar metadata. */
+    public static final String AVATARMETADATA_NODE = "urn:xmpp:avatar:metadata";
+
     private PepSubManager mPep;
     private Connection mCon;
     private boolean mAutoDownload;
@@ -78,7 +87,8 @@
      * @param cache the cache which will store the avatars
      * @param autoDownload true to enable auto download of avatars
      */
-    public AvatarManager(final Connection con, final PepSubManager pepMgr, final AvatarCache cache, final boolean autoDownload) {
+    public AvatarManager(final Connection con, final PepSubManager pepMgr,
+	    final AvatarCache cache, final boolean autoDownload) {
 	mCon = con;
 	mPep = pepMgr;
 	mAutoDownload = autoDownload;
@@ -87,6 +97,21 @@
     }
 
     /**
+     * Create an AvatarManager.
+     *
+     * @param con the connection
+     * @param pepMgr the PepSubManager of the Connection
+     * @param autoDownload true to enable auto download of avatars
+     */
+    protected AvatarManager(final Connection con, final PepSubManager pepMgr, final boolean autoDownload) {
+	mCon = con;
+	mPep = pepMgr;
+	mAutoDownload = autoDownload;
+	mPep.addPEPListener(new Listener());
+	//TODO add a memory cache
+    }
+
+    /**
      * Get an avatar from the cache.
      *
      * @param avatarId the id of the avatar
@@ -121,31 +146,6 @@
 	mListeners.remove(listener);
     }
 
-
-    /**
-     * Select the avatar to download.
-     * Subclass should override this method to take control over the selection process.
-     * This implementation select the first element.
-     *
-     * @param available list of the avatar metadata information
-     * @return the metadata of the avatar to download
-     */
-    protected Info selectAvatar(List<Info> available) {
-	return available.get(0);
-    }
-
-    /**
-     * Fire the listeners for avatar change.
-     *
-     * @param from the jid of the contact
-     * @param avatarId the new avatar id
-     * @param avatarInfos the metadata infos of the avatar
-     */
-    private void fireListeners(String from, String avatarId, List<Info> avatarInfos) {
-	for (AvatarListener l : mListeners)
-	    l.onAvatarChange(from, avatarId, avatarInfos);
-    }
-
     /**
      * Download an avatar.
      *
@@ -169,6 +169,96 @@
     }
 
     /**
+     * Disable the diffusion of your avatar.
+     */
+    public void disableAvatarPublishing() {
+	AvatarMetadataExtension metadata = new AvatarMetadataExtension();
+	publishAvatarMetaData(null, metadata);
+    }
+
+    /**
+     * Send an avatar image to the pep server.
+     *
+     * @param data the image data.
+     * @return true if the image where successfully sent. false otherwise
+     */
+    public boolean publishAvatarData(byte[] data) {
+	try {
+	    String id = getAvatarId(data);
+	    publishAvatarData(id, data);
+	    return true;
+	} catch (NoSuchAlgorithmException e) {
+	    System.err.println("Security error while publishing avatar data : " + e.getMessage());
+	    return false;
+	}
+    }
+
+    /**
+     * Send the metadata of the avatar you want to publish.
+     * By sending this metadata, you publish an avatar.
+     *
+     * @param id the id of the metadata item
+     * @param metadata the metadata to publish
+     */
+    public void publishAvatarMetaData(String id, AvatarMetadataExtension metadata) {
+	PayloadItem<AvatarMetadataExtension> item = new PayloadItem<AvatarMetadataExtension>(id, metadata);
+	LeafNode node = mPep.getPEPNode(AVATARMETADATA_NODE);
+	node.publish(item);
+    }
+
+    /**
+     * Select the avatar to download.
+     * Subclass should override this method to take control over the selection process.
+     * This implementation select the first element.
+     *
+     * @param available list of the avatar metadata information
+     * @return the metadata of the avatar to download
+     */
+    protected Info selectAvatar(List<Info> available) {
+	return available.get(0);
+    }
+
+
+    /**
+     * Get the id corresponding to this avatar data.
+     *
+     * @param data the avatar data
+     * @return the id
+     * @throws NoSuchAlgorithmException if the sha-1 algorithm is unavailable
+     */
+    protected String getAvatarId(byte[] data) throws NoSuchAlgorithmException {
+	MessageDigest md = MessageDigest.getInstance("sha-1");
+	byte[] hash = md.digest(data);
+	return StringUtils.encodeHex(hash);
+    }
+
+    /**
+     * Publish an avatar data.
+     *
+     * @param id the id of the avatar data
+     * @param data the data of the avatar
+     */
+    private void publishAvatarData(String id, byte[] data) {
+	AvatarExtension avatar = new AvatarExtension(data);
+	PayloadItem<AvatarExtension> item = new PayloadItem<AvatarExtension>(id, avatar);
+	LeafNode node = mPep.getPEPNode(AVATARDATA_NODE);
+	node.publish(item);
+    }
+
+    /**
+     * Fire the listeners for avatar change.
+     *
+     * @param from the jid of the contact
+     * @param avatarId the new avatar id
+     * @param avatarInfos the metadata infos of the avatar
+     */
+    private void fireListeners(String from, String avatarId, List<Info> avatarInfos) {
+	for (AvatarListener l : mListeners)
+	    l.onAvatarChange(from, avatarId, avatarInfos);
+    }
+
+
+    /**
      * A listener to PEPEevent.
      */
     private class Listener implements PEPListener {
--- a/src/com/beem/project/beem/ui/ChangeStatus.java	Sat Mar 05 17:44:41 2011 +0100
+++ b/src/com/beem/project/beem/ui/ChangeStatus.java	Sun Feb 20 03:16:35 2011 +0100
@@ -51,14 +51,17 @@
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.preference.PreferenceManager;
+import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
+import android.widget.ImageButton;
 import android.widget.EditText;
 import android.widget.Spinner;
 import android.widget.Toast;
@@ -71,6 +74,7 @@
 import com.beem.project.beem.utils.BeemConnectivity;
 import com.beem.project.beem.utils.Status;
 
+
 /**
  * This Activity is used to change the status.
  * @author nikita
@@ -82,6 +86,7 @@
 	SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService"));
     }
 
+    private static final String TAG = ChangeStatus.class.getSimpleName();
     private static final int AVAILABLE_FOR_CHAT_IDX = 0;
     private static final int AVAILABLE_IDX = 1;
     private static final int BUSY_IDX = 2;
@@ -95,6 +100,8 @@
     private Button mClear;
     private Button mContact;
     private Spinner mSpinner;
+    private ImageButton mAvatar;
+    private Uri mAvatarUri;
 
     private SharedPreferences mSettings;
     private ArrayAdapter<CharSequence> mAdapter;
@@ -127,6 +134,9 @@
 	mContact = (Button) findViewById(R.id.OpenContactList);
 	mContact.setOnClickListener(mOnClickOk);
 
+	mAvatar = (ImageButton) findViewById(R.id.avatarButton);
+	mAvatar.setOnClickListener(mOnClickOk);
+
 	mSettings = PreferenceManager.getDefaultSharedPreferences(this);
 	mStatusMessageEditText = (EditText) findViewById(R.id.ChangeStatusMessage);
 	mStatusMessageEditText.setText(mSettings.getString(BeemApplication.STATUS_TEXT_KEY, ""));
@@ -174,6 +184,14 @@
 	this.unregisterReceiver(mReceiver);
     }
 
+    protected void onActivityResult (int requestCode, int resultCode, Intent data) {
+	if (data != null) {
+	    mAvatarUri = data.getData();
+	    mAvatar.setImageURI(mAvatarUri);
+	}
+
+    }
+
     /**
      * Return the status index from status the settings.
      * @return the status index from status the settings.
@@ -224,6 +242,25 @@
 	return result;
     }
 
+    private void onAvatarButton(View button) {
+	Intent i = new Intent(Intent.ACTION_GET_CONTENT);
+	i.setType("image/*");
+	i = Intent.createChooser(i, "Select avatar");
+//         Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+	startActivityForResult(i, 1);
+    }
+
+    private void changeAvatar() {
+	if (mAvatarUri == null)
+	    return;
+	try {
+	    mXmppFacade.publishAvatar(mAvatarUri);
+	} catch (RemoteException e) {
+	    Log.e(TAG, "Error while publishing avatar", e);
+	}
+
+    }
+
     /**
      * connection to service.
      * @author nikita
@@ -278,6 +315,7 @@
 		    try {
 			mXmppFacade.changeStatus(status, msg.toString());
 			edit.putInt(BeemApplication.STATUS_KEY, mSpinner.getSelectedItemPosition());
+			changeAvatar();
 		    } catch (RemoteException e) {
 			e.printStackTrace();
 		    }
@@ -290,7 +328,8 @@
 	    } else if (v == mContact) {
 		startActivity(new Intent(ChangeStatus.this, ContactList.class));
 		ChangeStatus.this.finish();
-	    }
+	    } else if (v == mAvatar)
+		onAvatarButton(v);
 	}
     }
 }
--- a/src/com/beem/project/beem/ui/ContactList.java	Sat Mar 05 17:44:41 2011 +0100
+++ b/src/com/beem/project/beem/ui/ContactList.java	Sun Feb 20 03:16:35 2011 +0100
@@ -665,7 +665,7 @@
 		ImageView img = (ImageView) view.findViewById(R.id.avatar);
 		String avatarId = curContact.getAvatarId();
 		int contactStatus = curContact.getStatus();
-		Drawable avatar = getAvatarStatusDrawable(curContact.getAvatarId());
+		Drawable avatar = getAvatarStatusDrawable(avatarId);
 		img.setImageDrawable(avatar);
 		img.setImageLevel(contactStatus);
 	    }
@@ -691,7 +691,7 @@
 			    in.close();
 		    }
 		} catch (IOException e) {
-		    Log.w(TAG, "Error while setting the avatar", e);
+		    Log.w(TAG, "Error while setting the avatar " + avatarId, e);
 		}
 	    }
 	    if (avatarDrawable == null)