# HG changeset patch # User "Vincent Veronis" # Date 1300559491 -3600 # Node ID be08c91576360e27ef2ee0e45404c0abd11715e7 # Parent 85977e23817aecbc7eea1790695ff6cb2c94ae2f# Parent 2236fe5b2db178d4a8e7e4fde96043ba19efb45c Merge beem-account and Beem-avatar diff -r 85977e23817a -r be08c9157636 AndroidManifest.xml --- a/AndroidManifest.xml Fri Feb 25 15:11:29 2011 +0100 +++ b/AndroidManifest.xml Sat Mar 19 19:31:31 2011 +0100 @@ -76,6 +76,10 @@ android:name="android.intent.action.BOOT_COMPLETED" /> --> + + @@ -106,4 +110,4 @@ - \ No newline at end of file + diff -r 85977e23817a -r be08c9157636 src/com/beem/project/beem/providers/AvatarProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/providers/AvatarProvider.java Sat Mar 19 19:31:31 2011 +0100 @@ -0,0 +1,204 @@ +/* + 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 . + + 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.providers; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.File; +import java.io.FileNotFoundException; + +/** + * A simple content provider we expose the differents avatar downloaded. + * + */ +public class AvatarProvider extends ContentProvider { + + /** The content uri of this provider. */ + public static final Uri CONTENT_URI = + Uri.parse("content://com.beem.project.beem.providers.avatarprovider"); + + private static final String TAG = AvatarProvider.class.getSimpleName(); + private static final String AUTHORITY = "com.beem.project.beem.providers.avatarprovider"; + + /** + * The differents columns available in the AvatarProvider. + */ + public static interface Columns { + + /** The id of the avatar. */ + String ID = "_id"; + } + + private static String[] columnNames = new String[] {Columns.ID }; + + private static final int AVATAR = 1; + private static final int AVATAR_ID = 2; + private static final UriMatcher URIMATCHER = new UriMatcher(AVATAR); + + static + { + URIMATCHER.addURI(AUTHORITY, "*", AVATAR_ID); + // should not be needed if we pass AVATAR on the constructor but it does not work + URIMATCHER.addURI(AUTHORITY, null, AVATAR); + } + + private String mDataPath; + + /** + * Create an AvatarProvider. + */ + public AvatarProvider() { + } + + /** + * Translate the mode passed to {@link #openFile} into mode passed to {@link ParcelFileDescriptor#open}. + * + * @param uri the uri to open + * @param mode the mode + * @return the mode + * @throws FileNotFoundException if the mode passed is illegal + */ + public static int modeToMode(Uri uri, String mode) throws FileNotFoundException { + int modeBits; + if ("r".equals(mode)) { + modeBits = ParcelFileDescriptor.MODE_READ_ONLY; + } else if ("w".equals(mode) || "wt".equals(mode)) { + modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY + | ParcelFileDescriptor.MODE_CREATE + | ParcelFileDescriptor.MODE_TRUNCATE; + } else if ("wa".equals(mode)) { + modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY + | ParcelFileDescriptor.MODE_CREATE + | ParcelFileDescriptor.MODE_APPEND; + } else if ("rw".equals(mode)) { + modeBits = ParcelFileDescriptor.MODE_READ_WRITE + | ParcelFileDescriptor.MODE_CREATE; + } else if ("rwt".equals(mode)) { + modeBits = ParcelFileDescriptor.MODE_READ_WRITE + | ParcelFileDescriptor.MODE_CREATE + | ParcelFileDescriptor.MODE_TRUNCATE; + } else { + throw new FileNotFoundException("Bad mode for " + uri + ": " + + mode); + } + return modeBits; + } + + @Override + public boolean onCreate() { + File cacheDir = Environment.getExternalStorageDirectory(); + File dataPath = new File(cacheDir, "/Android/data/com.beem.project.beem/cache/avatar"); + dataPath.mkdirs(); + mDataPath = dataPath.getAbsolutePath(); + return true; + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) + throws FileNotFoundException { + String id = uri.getPath(); + File data = new File(mDataPath, id); + int modeBits = AvatarProvider.modeToMode(uri, mode); + return ParcelFileDescriptor.open(data, modeBits); + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + MatrixCursor c = new MatrixCursor(columnNames); + int match = URIMATCHER.match(uri); + switch (match) { + case AVATAR: + File[] files = new File(mDataPath).listFiles(); + if (files != null) { + for (File f : files) { + c.newRow().add(f.getName()); + } + } + break; + case AVATAR_ID: + String id = uri.getPathSegments().get(0); + File f = new File(mDataPath, id); + if (f.exists()) + c.newRow().add(f.getName()); + break; + default: + Log.w(TAG, "Unsupported uri for query match = " + match); + } + return c; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + int res = 0; + String id = uri.getPath(); + File data = new File(mDataPath, id); + if (data.exists() && data.delete()) { + res++; + } + return res; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + @Override + public String getType(Uri uri) { + return null; + } +} diff -r 85977e23817a -r be08c9157636 src/com/beem/project/beem/providers/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/providers/package-info.java Sat Mar 19 19:31:31 2011 +0100 @@ -0,0 +1,49 @@ +/* + 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 . + + 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. + +*/ + + +/** + * ContentProviders for Beem. + */ +package com.beem.project.beem.providers; diff -r 85977e23817a -r be08c9157636 src/com/beem/project/beem/service/BeemAvatarCache.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/service/BeemAvatarCache.java Sat Mar 19 19:31:31 2011 +0100 @@ -0,0 +1,134 @@ +/* + 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 . + + 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.ContentResolver; +import android.content.Context; + +import android.database.Cursor; + +import android.net.Uri; + +import com.beem.project.beem.providers.AvatarProvider; +import com.beem.project.beem.smack.avatar.AvatarCache; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * An implementation of an AvatarCache which store the data of the filesystem. + */ +public class BeemAvatarCache implements AvatarCache { + + private static final String TAG = BeemAvatarCache.class.getSimpleName(); + + private Context mContext; + private ContentResolver mContentResolver; + + /** + * Create a BeemAvatarCache. + * + * @param ctx The android context of the cache. + */ + public BeemAvatarCache(final Context ctx) { + mContext = ctx; + mContentResolver = mContext.getContentResolver(); + } + + + @Override + public void put(String key, byte[] data) throws IOException { + Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(key).build(); + OutputStream os = new BufferedOutputStream(mContentResolver.openOutputStream(uri)); + try { + os.write(data); + } finally { + os.close(); + } + } + + @Override + public void put(String key, InputStream in) throws IOException { + Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(key).build(); + OutputStream os = new BufferedOutputStream(mContentResolver.openOutputStream(uri)); + try { + byte[] data = new byte[1024]; + int nbread; + while ((nbread = in.read(data)) != -1) + os.write(data, 0, nbread); + } finally { + in.close(); + os.close(); + } + } + + @Override + public byte[] get(String key) throws IOException { + Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(key).build(); + InputStream is = new BufferedInputStream(mContentResolver.openInputStream(uri)); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try { + byte[] data = new byte[1024]; + is.read(data); + bos.write(data); + } finally { + is.close(); + } + return bos.toByteArray(); + } + + @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(); + return res; + } +} diff -r 85977e23817a -r be08c9157636 src/com/beem/project/beem/service/XmppConnectionAdapter.java --- a/src/com/beem/project/beem/service/XmppConnectionAdapter.java Fri Feb 25 15:11:29 2011 +0100 +++ b/src/com/beem/project/beem/service/XmppConnectionAdapter.java Sat Mar 19 19:31:31 2011 +0100 @@ -64,11 +64,9 @@ import android.content.SharedPreferences; import android.os.RemoteCallbackList; import android.os.RemoteException; -import android.os.Environment; import android.util.Log; import java.util.Iterator; -import java.io.File; import com.beem.project.beem.BeemService; import com.beem.project.beem.R; @@ -83,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.FileAvatarCache; import com.beem.project.beem.smack.avatar.AvatarManager; /** @@ -483,7 +480,7 @@ try { // jid et server ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(mAdaptee); - DiscoverInfo info = sdm.discoverInfo("elyzion.net"); + DiscoverInfo info = sdm.discoverInfo(mAdaptee.getServiceName()); Iterator it = info.getIdentities(); while (it.hasNext()) { DiscoverInfo.Identity identity = it.next(); @@ -504,9 +501,7 @@ // 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); + AvatarCache avatarCache = new BeemAvatarCache(mService); mAvatarManager = new AvatarManager(mAdaptee, mPepManager, avatarCache, true); } diff -r 85977e23817a -r be08c9157636 src/com/beem/project/beem/smack/avatar/AvatarMetadataProvider.java --- a/src/com/beem/project/beem/smack/avatar/AvatarMetadataProvider.java Fri Feb 25 15:11:29 2011 +0100 +++ b/src/com/beem/project/beem/smack/avatar/AvatarMetadataProvider.java Sat Mar 19 19:31:31 2011 +0100 @@ -70,16 +70,34 @@ int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { if ("info".equals(parser.getName())) { - int bytes = Integer.parseInt(parser.getAttributeValue(null, "bytes")); - int height = Integer.parseInt(parser.getAttributeValue(null, "height")); - int width = Integer.parseInt(parser.getAttributeValue(null, "width")); String id = parser.getAttributeValue(null, "id"); String type = parser.getAttributeValue(null, "type"); + String sbytes = parser.getAttributeValue(null, "bytes"); + String sheight = parser.getAttributeValue(null, "height"); + String swidth = parser.getAttributeValue(null, "width"); + int bytes = 0; + AvatarMetadataExtension.Info info = null; + try { + if (sbytes != null) + bytes = Integer.parseInt(sbytes); + } catch (NumberFormatException e) { } + if (bytes != 0 && id != null && type != null) + info = new AvatarMetadataExtension.Info(id, type, bytes); + else // invalid info + continue; + String url = parser.getAttributeValue(null, "url"); - AvatarMetadataExtension.Info info = new AvatarMetadataExtension.Info(id, type, bytes); - info.setHeight(height); - info.setWidth(width); info.setUrl(url); + try { + int height = 0; + int width = 0; + if (sheight != null) + height = Integer.parseInt(parser.getAttributeValue(null, "height")); + if (swidth != null) + width = Integer.parseInt(parser.getAttributeValue(null, "width")); + info.setHeight(height); + info.setWidth(width); + } catch (NumberFormatException e) { } metadata.addInfo(info); } } else if (eventType == XmlPullParser.END_TAG) { diff -r 85977e23817a -r be08c9157636 src/com/beem/project/beem/smack/caps/CapsManager.java --- a/src/com/beem/project/beem/smack/caps/CapsManager.java Fri Feb 25 15:11:29 2011 +0100 +++ b/src/com/beem/project/beem/smack/caps/CapsManager.java Sat Mar 19 19:31:31 2011 +0100 @@ -178,7 +178,7 @@ PacketExtension p = packet.getExtension("c", "http://jabber.org/protocol/caps"); CapsExtension caps = (CapsExtension) p; if (!isInCache(caps.getVer())) { - validate(packet.getFrom(), caps.getVer(), caps.getHash()); + validate(packet.getFrom(), caps.getNode(), caps.getVer(), caps.getHash()); } } }, filter); @@ -204,13 +204,14 @@ * Validate the ver attribute of a received capability. * * @param jid the jid of the sender of the capability. + * @param node the node attribute of the capability. * @param ver the ver attribute of the capability. * @param hashMethod the hash algorithm to use to calculate ver * @return true if the ver attribute is valid false otherwise. */ - private boolean validate(String jid, String ver, String hashMethod) { + private boolean validate(String jid, String node, String ver, String hashMethod) { try { - DiscoverInfo info = mSdm.discoverInfo(jid); + DiscoverInfo info = mSdm.discoverInfo(jid, node + "#" + ver); if (!mSupportedAlgorithm.contains(hashMethod)) { mJidCache.put(jid, info); return false; diff -r 85977e23817a -r be08c9157636 src/com/beem/project/beem/ui/Chat.java --- a/src/com/beem/project/beem/ui/Chat.java Fri Feb 25 15:11:29 2011 +0100 +++ b/src/com/beem/project/beem/ui/Chat.java Sat Mar 19 19:31:31 2011 +0100 @@ -49,6 +49,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.io.InputStream; +import java.io.IOException; import org.jivesoftware.smack.packet.Presence.Mode; import org.jivesoftware.smack.util.StringUtils; @@ -65,6 +67,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; +import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -88,9 +91,9 @@ import android.widget.ListView; import android.widget.TextView; -import java.io.ByteArrayInputStream; import com.beem.project.beem.R; +import com.beem.project.beem.providers.AvatarProvider; import com.beem.project.beem.service.Contact; import com.beem.project.beem.service.Message; import com.beem.project.beem.service.PresenceAdapter; @@ -143,6 +146,7 @@ private final BeemBroadcastReceiver mBroadcastReceiver = new BeemBroadcastReceiver(); private final BeemRosterListener mBeemRosterListener = new BeemRosterListener(); private IXmppFacade mXmppFacade; + private String mCurrentAvatarId; private boolean mBinded; private boolean mCompact; @@ -576,7 +580,11 @@ } } else { Mode m = Status.getPresenceModeFromStatus(mContact.getStatus()); - setTitle(getString(R.string.chat_name) + " " + mContact.getName() + " (" + m.name() + ")"); + if (m == null) + setTitle(getString(R.string.chat_name) + " " + name + + " (" + getString(R.string.contact_status_msg_offline) + ")"); + else + setTitle(getString(R.string.chat_name) + " " + name + " (" + m.name() + ")"); } } @@ -588,8 +596,15 @@ private void updateContactStatusIcon() { if (mCompact) return; - Drawable avatar = getAvatarDrawable(mContact.getAvatarId()); - mAvatarStatusDrawable.setDrawableByLayerId(R.id.avatar, avatar); + String id = mContact.getAvatarId(); + if (id == null) + id = ""; + Log.d(TAG, "update contact icon : " + id); + if (!id.equals(mCurrentAvatarId)) { + Drawable avatar = getAvatarDrawable(mContact.getAvatarId()); + mAvatarStatusDrawable.setDrawableByLayerId(R.id.avatar, avatar); + mCurrentAvatarId = id; + } mContactStatusIcon.setImageLevel(mContact.getStatus()); } @@ -601,19 +616,25 @@ */ private Drawable getAvatarDrawable(String avatarId) { Drawable avatarDrawable = null; - try { - byte[] avatar = mXmppFacade.getAvatar(avatarId); - if (avatar != null) { - ByteArrayInputStream in = new ByteArrayInputStream(avatar); - avatarDrawable = Drawable.createFromStream(in, avatarId); + if (avatarId != null) { + Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build(); + InputStream in = null; + try { + try { + in = getContentResolver().openInputStream(uri); + avatarDrawable = Drawable.createFromStream(in, avatarId); + } finally { + if (in != null) + in.close(); + } + } catch (IOException e) { + Log.w(TAG, "Error while setting the avatar", e); } - } catch (RemoteException e) { - Log.e(TAG, "Error while setting the avatar", e); } if (avatarDrawable == null) avatarDrawable = getResources().getDrawable(R.drawable.beem_launcher_icon_silver); return avatarDrawable; - } + } /** * Prepare the status icons map. diff -r 85977e23817a -r be08c9157636 src/com/beem/project/beem/ui/ContactList.java --- a/src/com/beem/project/beem/ui/ContactList.java Fri Feb 25 15:11:29 2011 +0100 +++ b/src/com/beem/project/beem/ui/ContactList.java Sat Mar 19 19:31:31 2011 +0100 @@ -49,7 +49,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.IOException; import org.jivesoftware.smack.util.StringUtils; @@ -60,6 +61,7 @@ import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.SharedPreferences; +import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -89,6 +91,7 @@ import android.graphics.drawable.LayerDrawable; import com.beem.project.beem.R; +import com.beem.project.beem.providers.AvatarProvider; import com.beem.project.beem.service.Contact; import com.beem.project.beem.service.PresenceAdapter; import com.beem.project.beem.service.aidl.IBeemRosterListener; @@ -676,16 +679,20 @@ */ private Drawable getAvatarStatusDrawable(String avatarId) { Drawable avatarDrawable = null; - try { - if (mXmppFacade != null) { - byte[] avatar = mXmppFacade.getAvatar(avatarId); - if (avatar != null) { - ByteArrayInputStream in = new ByteArrayInputStream(avatar); + if (avatarId != null) { + Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build(); + InputStream in = null; + try { + try { + in = getContentResolver().openInputStream(uri); avatarDrawable = Drawable.createFromStream(in, avatarId); + } finally { + if (in != null) + in.close(); } + } catch (IOException e) { + Log.w(TAG, "Error while setting the avatar", e); } - } catch (RemoteException e) { - Log.e(TAG, "Error while setting the avatar", e); } if (avatarDrawable == null) avatarDrawable = getResources().getDrawable(R.drawable.beem_launcher_icon_silver);