android: first publishable implementation of Ring on Android

Change-Id: I6d65993a0bbed0ac680d6fe5980aae0fb931116e
diff --git a/ring-android/app/app.iml b/ring-android/app/app.iml
index ece991d..3502718 100644
--- a/ring-android/app/app.iml
+++ b/ring-android/app/app.iml
@@ -12,10 +12,12 @@
         <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
         <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
         <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
-        <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
         <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
         <option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
-        <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
+        <afterSyncTasks>
+          <task>generateDebugAndroidTestSources</task>
+          <task>generateDebugSources</task>
+        </afterSyncTasks>
         <option name="ALLOW_USER_CONFIGURATION" value="false" />
         <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
         <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
@@ -24,7 +26,7 @@
       </configuration>
     </facet>
   </component>
-  <component name="NewModuleRootManager" inherit-compiler-output="false">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
     <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
     <output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
     <exclude-output />
@@ -34,13 +36,13 @@
       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
       <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
       <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/build-types/debug/res" type="java-resource" />
       <sourceFolder url="file://$MODULE_DIR$/build-types/debug/resources" type="java-resource" />
       <sourceFolder url="file://$MODULE_DIR$/build-types/debug/assets" type="java-resource" />
@@ -67,11 +69,12 @@
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/22.2.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/22.2.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v13/22.2.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/22.2.0/jars" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.0.1/jars" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/23.0.1/jars" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v13/23.0.1/jars" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.0.1/jars" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.astuetz/pagerslidingtabstrip/1.0.1/jars" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/se.emilsjolander/stickylistheaders/2.7.0/jars" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
@@ -87,16 +90,18 @@
       <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
       <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
     </content>
-    <orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" />
+    <orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="library" exported="" name="ormlite-android-4.48" level="project" />
+    <orderEntry type="library" exported="" name="libphonenumber-7.0.11" level="project" />
     <orderEntry type="library" exported="" name="pagerslidingtabstrip-1.0.1" level="project" />
     <orderEntry type="library" exported="" name="ormlite-core-4.48" level="project" />
-    <orderEntry type="library" exported="" name="robotium-solo-5.0.1" level="project" />
-    <orderEntry type="library" exported="" name="support-annotations-22.2.0" level="project" />
-    <orderEntry type="library" exported="" name="support-v13-22.2.0" level="project" />
-    <orderEntry type="library" exported="" name="support-v4-22.2.0" level="project" />
-    <orderEntry type="library" exported="" name="design-22.2.0" level="project" />
-    <orderEntry type="library" exported="" name="appcompat-v7-22.2.0" level="project" />
+    <orderEntry type="library" exported="" name="support-v13-23.0.1" level="project" />
+    <orderEntry type="library" exported="" name="stickylistheaders-2.7.0" level="project" />
+    <orderEntry type="library" exported="" name="support-v4-23.0.1" level="project" />
+    <orderEntry type="library" exported="" name="robotium-solo-5.4.1" level="project" />
+    <orderEntry type="library" exported="" name="design-23.0.1" level="project" />
+    <orderEntry type="library" exported="" name="appcompat-v7-23.0.1" level="project" />
+    <orderEntry type="library" exported="" name="support-annotations-23.0.1" level="project" />
   </component>
 </module>
\ No newline at end of file
diff --git a/ring-android/app/build.gradle b/ring-android/app/build.gradle
index e1bcbff..2ca1c19 100644
--- a/ring-android/app/build.gradle
+++ b/ring-android/app/build.gradle
@@ -1,18 +1,20 @@
 apply plugin: 'com.android.application'
 
 dependencies {
-    compile fileTree(dir: 'libs', include: '*.jar')
+    compile fileTree(include: '*.jar', dir: 'libs')
     compile 'com.j256.ormlite:ormlite-core:4.48'
     compile 'com.j256.ormlite:ormlite-android:4.48'
-    compile "com.android.support:support-v13:22.2.0"
-    compile 'com.android.support:design:22.2.0'
+    compile 'com.android.support:support-v13:23.0.+'
+    compile 'com.android.support:design:23.0.+'
     compile 'com.jayway.android.robotium:robotium-solo:5.4.1'
     compile 'com.astuetz:pagerslidingtabstrip:1.0.1'
+    compile 'com.googlecode.libphonenumber:libphonenumber:7.0.11'
+    compile 'se.emilsjolander:stickylistheaders:2.7.+'
 }
 
 android {
-    compileSdkVersion 22
-    buildToolsVersion "22.0.1"
+    compileSdkVersion 23
+    buildToolsVersion "23.0.1"
 
     sourceSets {
         main {
@@ -33,4 +35,8 @@
         debug.setRoot('build-types/debug')
         release.setRoot('build-types/release')
     }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_7
+        targetCompatibility JavaVersion.VERSION_1_7
+    }
 }
\ No newline at end of file
diff --git a/ring-android/app/src/main/AndroidManifest.xml b/ring-android/app/src/main/AndroidManifest.xml
index ceb3bd8..321aa68 100644
--- a/ring-android/app/src/main/AndroidManifest.xml
+++ b/ring-android/app/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
+Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
                                                                     
 Author: 	Alexandre Lision <alexandre.lision@savoirfairelinux.com>
 			Adrien Beraud <adrien.beraud@gmail.com>                     
@@ -36,6 +36,10 @@
     android:versionCode="14"
     android:versionName="2.0.0" >
 
+    <uses-sdk
+        android:minSdkVersion="16"
+        android:targetSdkVersion="23" />
+
     <supports-screens
         android:anyDensity="true"
         android:largeScreens="true"
@@ -43,10 +47,6 @@
         android:smallScreens="true"
         android:xlargeScreens="true" />
 
-    <uses-sdk
-        android:minSdkVersion="15"
-        android:targetSdkVersion="22" />
-
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
@@ -67,6 +67,8 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.READ_LOGS" />
     <uses-permission android:name="android.permission.USE_SIP" />
+    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
 
     <uses-feature
         android:name="android.hardware.wifi"
@@ -89,7 +91,7 @@
         android:icon="@drawable/ic_launcher"
         android:label="@string/app_name" >
         <activity
-            android:name="cx.ring.client.HomeActivity"
+            android:name=".client.HomeActivity"
             android:label="@string/title_activity_sflphone_home"
             android:screenOrientation="portrait"
             android:theme="@style/AppThemeWithOverlay"
@@ -101,40 +103,74 @@
             </intent-filter>
         </activity>
         <activity
-            android:name="cx.ring.client.AccountWizard"
+            android:name=".client.AccountWizard"
             android:screenOrientation="portrait"
             android:theme="@style/AppThemeWithoutOverlay" >
             <meta-data
                 android:name="android.support.PARENT_ACTIVITY"
-                android:value="cx.ring.client.AccountPreferenceActivity" />
+                android:value="cx.ring.client.AccountEditionActivity" />
         </activity>
         <activity
-            android:name="cx.ring.client.AccountEditionActivity"
+            android:name=".client.AccountEditionActivity"
             android:label="@string/app_name"
             android:screenOrientation="portrait"
             android:theme="@style/AppThemeWithoutOverlay" />
         <activity
-            android:name="cx.ring.client.DetailHistoryActivity"
+            android:name=".client.DetailHistoryActivity"
             android:label="@string/app_name"
             android:screenOrientation="portrait"
             android:theme="@style/AppThemeWithoutOverlay" />
+
+        <activity android:name=".client.NewConversationActivity" android:theme="@style/AppThemeWithoutOverlay" android:label="@string/app_name" >
+        </activity>
+
         <activity
-            android:name="cx.ring.client.CallActivity"
+            android:name=".client.CallActivity"
             android:label="@string/app_name"
             android:screenOrientation="portrait"
             android:theme="@style/AppThemeWithoutOverlay"
             android:windowSoftInputMode="adjustPan" >
             <intent-filter>
                 <action android:name="android.intent.action.CALL_PRIVILEGED" />
+                <action android:name="android.intent.action.CALL" />
+                <action android:name="android.intent.action.DIAL" />
+                <action android:name="android.intent.action.VIEW" />
 
                 <category android:name="android.intent.category.DEFAULT" />
 
                 <data android:scheme="tel" />
+                <data android:scheme="ring" />
+                <data android:scheme="sip" />
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.CALL" />
+                <action android:name="android.intent.action.DIAL" />
+
+                <category android:name="android.intent.category.DEFAULT" />
+
+                <data android:mimeType="vnd.android.cursor.item/phone" />
+                <data android:mimeType="vnd.android.cursor.item/phone_v2" />
+                <data android:mimeType="vnd.android.cursor.item/person" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".client.ConversationActivity"
+            android:label="@string/app_name"
+            android:parentActivityName=".client.HomeActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/AppThemeWithoutOverlay"
+            android:windowSoftInputMode="adjustResize" >
         </activity>
 
         <service
-            android:name="cx.ring.service.SipService"
+            android:name=".service.LocalService"
+            android:exported="false" >
+            <intent-filter>
+                <action android:name=".service.LocalService" />
+            </intent-filter>
+        </service>
+        <service
+            android:name=".service.SipService"
             android:exported="false" >
             <intent-filter>
                 <action android:name=".service.SipService" />
@@ -142,4 +178,4 @@
         </service>
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/AccountSelectionAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/AccountSelectionAdapter.java
index 003f347..6a2ab31 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/AccountSelectionAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/AccountSelectionAdapter.java
@@ -32,12 +32,11 @@
 package cx.ring.adapters;
 
 import java.io.File;
-import java.util.ArrayList;
+import java.util.List;
 
 import cx.ring.R;
 
 import android.content.Context;
-import android.graphics.Color;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -51,12 +50,12 @@
 
     private static final String TAG = AccountSelectionAdapter.class.getSimpleName();
 
-    ArrayList<Account> accounts;
+    List<Account> accounts;
     Context mContext;
     int selectedAccount = -1;
     static final String DEFAULT_ACCOUNT_ID = "IP2IP";
 
-    public AccountSelectionAdapter(Context cont, ArrayList<Account> newList) {
+    public AccountSelectionAdapter(Context cont, List<Account> newList) {
         super();
         accounts = newList;
         mContext = cont;
@@ -133,7 +132,11 @@
 
     private void updateAccountView(AccountView entryView, Account acc) {
         entryView.alias.setText(acc.getAlias());
-        entryView.host.setText(acc.getHost()/*+ " - " + acc.getRegistered_state()*/);
+        if (acc.isRing()) {
+            entryView.host.setText(acc.getBasicDetails().getUsername());
+        } else {
+            entryView.host.setText(acc.getBasicDetails().getUsername() + "@" + acc.getBasicDetails().getHostname());
+        }
         entryView.error.setVisibility(acc.isRegistered() ? View.GONE : View.VISIBLE);
     }
 
@@ -171,7 +174,13 @@
 
     }
 
-    public void addAll(ArrayList<Account> results) {
+    public void addAll(List<Account> results) {
+        accounts.addAll(results);
+        notifyDataSetChanged();
+    }
+
+    public void replaceAll(List<Account> results) {
+        accounts.clear();
         accounts.addAll(results);
         notifyDataSetChanged();
     }
@@ -184,7 +193,7 @@
 
         for (Account a : accounts) {
             if (a.getAccountID().contentEquals(accoundID)) {
-                a.setRegistered_state(state, code);
+                a.setRegistrationState(state, code);
                 Log.i(TAG, "updateAccount " + accoundID + " " + code);
                 notifyDataSetChanged();
                 return;
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/ContactPictureTask.java b/ring-android/app/src/main/java/cx/ring/adapters/ContactPictureTask.java
index 5596a06..0377dc7 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/ContactPictureTask.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/ContactPictureTask.java
@@ -32,6 +32,8 @@
 package cx.ring.adapters;
 
 import java.io.InputStream;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 import cx.ring.R;
 import cx.ring.model.CallContact;
@@ -51,20 +53,55 @@
 import android.graphics.Shader;
 import android.net.Uri;
 import android.provider.ContactsContract;
+import android.util.Log;
+import android.util.LruCache;
+import android.view.animation.AnimationUtils;
 import android.widget.ImageView;
 
 public class ContactPictureTask implements Runnable {
-    private ImageView view;
-    private CallContact contact;
+    static final String TAG = ContactPictureTask.class.getSimpleName();
+
+    private final WeakReference<ImageView> view;
+    private final CallContact contact;
+
     private ContentResolver cr;
-    private static int PADDING = 5;
+    private final Resources res;
+    //private PictureLoadedCallback cb;
+    private final ArrayList<PictureLoadedCallback> callbacks = new ArrayList<>(1);
+
+    //int w = photo_bmp.getWidth(), h = photo_bmp.getHeight();
+    private final int vw, vh;
+
+    public void addCallback(PictureLoadedCallback cb) {
+        //this.cb = callback;
+        synchronized (callbacks) {
+            view.clear();
+            callbacks.add(cb);
+        }
+    }
 
     // private final String TAG = ContactPictureTask.class.getSimpleName();
 
+    public interface PictureLoadedCallback {
+        void onPictureLoaded(Bitmap bmp);
+    };
+
     public ContactPictureTask(Context context, ImageView element, CallContact item) {
         contact = item;
         cr = context.getContentResolver();
-        view = element;
+        res = context.getResources();
+        view = new WeakReference<>(element);
+        vw = element.getWidth();
+        vh = element.getHeight();
+    }
+    public ContactPictureTask(Context context, ImageView element, CallContact item, PictureLoadedCallback cb) {
+        contact = item;
+        cr = context.getContentResolver();
+        res = context.getResources();
+        vw = element.getWidth();
+        vh = element.getHeight();
+        view = new WeakReference<>(element);
+        addCallback(cb);
     }
 
     public static Bitmap loadContactPhoto(ContentResolver cr, long id) {
@@ -80,17 +117,27 @@
 
     @Override
     public void run() {
+        Log.i(TAG, "ContactPictureTask run " + contact.getId());
+
         Bitmap photo_bmp;
         try {
             photo_bmp = loadContactPhoto(cr, contact.getId());
         } catch (IllegalArgumentException e) {
             photo_bmp = null;
         }
+        cr = null;
 
-        int dpiPadding = (int) (PADDING * view.getResources().getDisplayMetrics().density);
+        /*final ImageView v = view.get();
+        view.clear();
+        if (v == null) {
+            Log.i(TAG, "ContactPictureTask cancelling: view is now null");
+            return;
+        }*/
+
+        //int dpiPadding = (int) (PADDING * view.getResources().getDisplayMetrics().density);
 
         if (photo_bmp == null) {
-            photo_bmp = decodeSampledBitmapFromResource(view.getResources(), R.drawable.ic_contact_picture, view.getWidth(), view.getHeight());
+            photo_bmp = decodeSampledBitmapFromResource(res, R.drawable.ic_contact_picture, vw, vh);
         }
 
         int w = photo_bmp.getWidth(), h = photo_bmp.getHeight();
@@ -119,14 +166,41 @@
         // internalCanvas.drawOval(new RectF(PADDING, PADDING, externalBMP.getWidth() - dpiPadding, externalBMP.getHeight() - dpiPadding), paint);
         internalCanvas.drawOval(new RectF(0, 0, externalBMP.getWidth(), externalBMP.getHeight()), paint);
 
-        view.post(new Runnable() {
+        photo_bmp.recycle();
+
+        contact.setPhoto(externalBMP);
+        //v.invalidate();
+        synchronized (callbacks) {
+            final ImageView v = view.get();
+            view.clear();
+            if (v == null) {
+                for (PictureLoadedCallback cb : callbacks) {
+                    cb.onPictureLoaded(externalBMP);
+                }
+            } else {
+                v.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        v.setImageBitmap(externalBMP);
+                    }
+                });
+            }
+            callbacks.clear();
+        }
+
+        /*v.post(new Runnable() {
             @Override
             public void run() {
-                view.setImageBitmap(externalBMP);
+                Log.w(TAG, "ContactPictureTask END " + contact.getId());
+                //v.setImageBitmap(externalBMP);
                 contact.setPhoto(externalBMP);
-                view.invalidate();
+                //v.invalidate();
+                for (PictureLoadedCallback cb : callbacks) {
+                    cb.onPictureLoaded(externalBMP);
+                }
+                callbacks.clear();
             }
-        });
+        });*/
     }
 
     public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/ContactsAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/ContactsAdapter.java
index de47d94..1754589 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/ContactsAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/ContactsAdapter.java
@@ -33,28 +33,30 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 import cx.ring.R;
 import cx.ring.fragments.ContactListFragment;
 import cx.ring.model.CallContact;
-import cx.ring.views.stickylistheaders.StickyListHeadersAdapter;
+import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.util.LruCache;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
 import android.widget.BaseAdapter;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.SectionIndexer;
 import android.widget.TextView;
-import android.widget.Toast;
 
 public class ContactsAdapter extends BaseAdapter implements StickyListHeadersAdapter, SectionIndexer {
-
     private ExecutorService infos_fetcher = Executors.newCachedThreadPool();
     Context mContext;
 
@@ -64,30 +66,41 @@
     WeakReference<ContactListFragment> parent;
     private LayoutInflater mInflater;
 
-    // private static final String TAG = ContactsAdapter.class.getSimpleName();
+    final private LruCache<Long, Bitmap> mMemoryCache;
+    final private HashMap<Long, WeakReference<ContactPictureTask>> running_tasks = new HashMap<>();
+
+    private static final String TAG = ContactsAdapter.class.getSimpleName();
 
     public ContactsAdapter(ContactListFragment contactListFragment) {
         super();
         mContext = contactListFragment.getActivity();
         mInflater = LayoutInflater.from(mContext);
-        parent = new WeakReference<ContactListFragment>(contactListFragment);
-        mContacts = new ArrayList<CallContact>();
+        parent = new WeakReference<>(contactListFragment);
+        mContacts = new ArrayList<>();
         mSectionIndices = getSectionIndices();
         mSectionLetters = getSectionLetters();
+        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
+        final int cacheSize = maxMemory / 8;
+        mMemoryCache = new LruCache<Long, Bitmap>(cacheSize){
+            @Override
+            protected int sizeOf(Long key, Bitmap bitmap) {
+                return bitmap.getByteCount() / 1024;
+            }
+        };
     }
 
     public static final int TYPE_HEADER = 0;
     public static final int TYPE_CONTACT = 1;
 
     private int[] getSectionIndices() {
-        ArrayList<Integer> sectionIndices = new ArrayList<Integer>();
+        ArrayList<Integer> sectionIndices = new ArrayList<>();
         if (mContacts.isEmpty())
             return new int[0];
-        char lastFirstChar = mContacts.get(0).getmDisplayName().charAt(0);
+        char lastFirstChar = mContacts.get(0).getDisplayName().charAt(0);
         sectionIndices.add(0);
         for (int i = 1; i < mContacts.size(); i++) {
-            if (mContacts.get(i).getmDisplayName().charAt(0) != lastFirstChar) {
-                lastFirstChar = mContacts.get(i).getmDisplayName().charAt(0);
+            if (mContacts.get(i).getDisplayName().charAt(0) != lastFirstChar) {
+                lastFirstChar = mContacts.get(i).getDisplayName().charAt(0);
                 sectionIndices.add(i);
             }
         }
@@ -101,26 +114,27 @@
     private Character[] getSectionLetters() {
         Character[] letters = new Character[mSectionIndices.length];
         for (int i = 0; i < mSectionIndices.length; i++) {
-            letters[i] = mContacts.get(mSectionIndices[i]).getmDisplayName().charAt(0);
+            letters[i] = mContacts.get(mSectionIndices[i]).getDisplayName().charAt(0);
         }
         return letters;
     }
 
     @Override
-    public View getView(int position, View convertView, ViewGroup root) {
+    public View getView(final int position, View convertView, ViewGroup root) {
         ContactView entryView;
 
         if (convertView == null) {
             convertView = mInflater.inflate(R.layout.item_contact, null);
 
             entryView = new ContactView();
-            entryView.quick_starred = (ImageButton) convertView.findViewById(R.id.quick_starred);
+            /*entryView.quick_starred = (ImageButton) convertView.findViewById(R.id.quick_starred);
             entryView.quick_edit = (ImageButton) convertView.findViewById(R.id.quick_edit);
             entryView.quick_discard = (ImageButton) convertView.findViewById(R.id.quick_discard);
             entryView.quick_call = (ImageButton) convertView.findViewById(R.id.quick_call);
-            entryView.quick_msg = (ImageButton) convertView.findViewById(R.id.quick_message);
+            entryView.quick_msg = (ImageButton) convertView.findViewById(R.id.quick_message);*/
             entryView.photo = (ImageView) convertView.findViewById(R.id.photo);
             entryView.display_name = (TextView) convertView.findViewById(R.id.display_name);
+            entryView.position = -1;
             convertView.setTag(entryView);
         } else {
             entryView = (ContactView) convertView.getTag();
@@ -128,14 +142,56 @@
 
         final CallContact item = mContacts.get(position);
 
-        entryView.display_name.setText(item.getmDisplayName());
+        if (entryView.position == position || (entryView.contact != null && entryView.contact.get() != null && item.getId() == entryView.contact.get().getId()))
+            return convertView;
 
-        if (item.hasPhoto()) {
-            entryView.photo.setImageBitmap(item.getPhoto());
-        } else {
-            infos_fetcher.execute(new ContactPictureTask(mContext, entryView.photo, item));
+        entryView.display_name.setText(item.getDisplayName());
+        entryView.contact = new WeakReference<>(item);
+        entryView.position = position;
+        final Long cid = item.getId();
+        final Long pid = item.getPhotoId();
+        Bitmap bmp = item.getPhoto();
+        if (bmp == null) {
+            bmp = mMemoryCache.get(pid);
+            if (bmp != null) item.setPhoto(bmp);
         }
 
+        if (bmp != null) {
+            entryView.photo.setImageBitmap(bmp);
+        } else {
+            entryView.photo.setImageBitmap(null);
+            final WeakReference<ContactView> wh = new WeakReference<>(entryView);
+            infos_fetcher.execute(new ContactPictureTask(mContext, entryView.photo, item, new ContactPictureTask.PictureLoadedCallback() {
+                @Override
+                public void onPictureLoaded(final Bitmap bmp) {
+                    mMemoryCache.put(pid, bmp);
+                    final ContactView fh = wh.get();
+                    if (fh == null || fh.photo.getParent() == null)
+                        return;
+                    if (fh.position == position)
+                        fh.photo.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                final CallContact c = fh.contact.get();
+                                if (c.getId() == cid) {
+                                    c.setPhoto(bmp);
+                                    fh.photo.setImageBitmap(bmp);
+                                    fh.photo.startAnimation(AnimationUtils.loadAnimation(fh.photo.getContext(), R.anim.contact_fadein));
+                                }
+                            }
+                        });
+                }
+            }));
+        }
+
+        convertView.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                parent.get().mCallbacks.onTextContact(item);
+            }
+        });
+
+/*
         entryView.quick_call.setOnClickListener(new OnClickListener() {
 
             @Override
@@ -182,7 +238,7 @@
         entryView.quick_edit.setClickable(false);
         entryView.quick_discard.setClickable(false);
         entryView.quick_starred.setClickable(false);
-
+*/
         return convertView;
     }
 
@@ -190,9 +246,11 @@
      * ViewHolder Pattern
      *********************/
     public class ContactView {
-        ImageButton quick_starred, quick_edit, quick_discard, quick_call, quick_msg;
+        ImageButton /*quick_starred, quick_edit, quick_discard, */quick_call, quick_msg;
         ImageView photo;
         TextView display_name;
+        WeakReference<CallContact> contact = new WeakReference<>(null);
+        int position;
     }
 
     @Override
@@ -224,7 +282,7 @@
         }
 
         // set header text as first char in name
-        char headerChar = mContacts.get(position).getmDisplayName().subSequence(0, 1).charAt(0);
+        char headerChar = mContacts.get(position).getDisplayName().subSequence(0, 1).charAt(0);
 
         holder.text.setText("" + headerChar);
 
@@ -240,7 +298,7 @@
     public long getHeaderId(int position) {
         // return the first character of the name as ID because this is what
         // headers are based upon
-        return mContacts.get(position).getmDisplayName().subSequence(0, 1).charAt(0);
+        return mContacts.get(position).getDisplayName().subSequence(0, 1).charAt(0);
     }
 
     @Override
@@ -274,14 +332,14 @@
     }
 
     public void clear() {
-        mContacts = new ArrayList<CallContact>();
+        mContacts = new ArrayList<>();
         mSectionIndices = new int[0];
         mSectionLetters = new Character[0];
         notifyDataSetChanged();
     }
-
+/*
     public void restore() {
-        mContacts = new ArrayList<CallContact>();
+        mContacts = new ArrayList<>();
         mSectionIndices = getSectionIndices();
         mSectionLetters = getSectionLetters();
         notifyDataSetChanged();
@@ -292,6 +350,13 @@
         mSectionIndices = getSectionIndices();
         mSectionLetters = getSectionLetters();
         notifyDataSetChanged();
+    }*/
+
+    public void setData(ArrayList<CallContact> contacts) {
+        mContacts = contacts;
+        mSectionIndices = getSectionIndices();
+        mSectionLetters = getSectionLetters();
+        notifyDataSetChanged();
     }
 
 }
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/DiscussArrayAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/DiscussArrayAdapter.java
deleted file mode 100644
index 9cdfc41..0000000
--- a/ring-android/app/src/main/java/cx/ring/adapters/DiscussArrayAdapter.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
- *
- *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
- *
- *  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, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Additional permission under GNU GPL version 3 section 7:
- *
- *  If you modify this program, or any covered work, by linking or
- *  combining it with the OpenSSL project's OpenSSL library (or a
- *  modified version of that library), containing parts covered by the
- *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
- *  grants you additional permission to convey the resulting work.
- *  Corresponding Source for a non-source form of such a combination
- *  shall include the source code for the parts of OpenSSL used as well
- *  as that of the covered work.
- */
-
-package cx.ring.adapters;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import cx.ring.R;
-import cx.ring.model.SipMessage;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-public class DiscussArrayAdapter extends BaseAdapter {
-
-    private TextView countryName;
-    private List<SipMessage> messages = new ArrayList<SipMessage>();
-    private LinearLayout wrapper;
-    private Context mContext;
-
-    public DiscussArrayAdapter(Context context, Bundle args) {
-        mContext = context;
-        
-        if(args == null)
-            messages = new ArrayList<SipMessage>();
-        else
-            messages = args.getParcelableArrayList("messages");
-        
-    }
-
-    public void add(SipMessage object) {
-        messages.add(object);
-        notifyDataSetChanged();
-    }
-
-    public int getCount() {
-        return this.messages.size();
-    }
-
-    public SipMessage getItem(int index) {
-        return this.messages.get(index);
-    }
-
-    public View getView(int position, View convertView, ViewGroup parent) {
-        View row = convertView;
-        if (row == null) {
-            LayoutInflater inflater = LayoutInflater.from(mContext);
-            row = inflater.inflate(R.layout.item_message, parent, false);
-        }
-
-        wrapper = (LinearLayout) row.findViewById(R.id.wrapper);
-
-        SipMessage coment = getItem(position);
-
-        countryName = (TextView) row.findViewById(R.id.comment);
-
-        countryName.setText(coment.comment);
-
-        countryName.setBackgroundResource(coment.left ? R.drawable.bubble_left_selector : R.drawable.bubble_right_selector);
-        wrapper.setGravity(coment.left ? Gravity.LEFT : Gravity.RIGHT);
-
-        return row;
-    }
-
-    @Override
-    public long getItemId(int position) {
-        return 0;
-    }
-
-}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/SectionsPagerAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/SectionsPagerAdapter.java
index b9b2d13..1f3be00 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/SectionsPagerAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/SectionsPagerAdapter.java
@@ -50,12 +50,11 @@
 
     private static final String TAG = SectionsPagerAdapter.class.getSimpleName();
     Context mContext;
-    ArrayList<Fragment> fragments;
+    private final ArrayList<Fragment> fragments = new ArrayList<>();
 
     public SectionsPagerAdapter(Context c, FragmentManager fm) {
         super(fm);
         mContext = c;
-        fragments = new ArrayList<Fragment>();
         fragments.add(new DialingFragment());
         fragments.add(new CallListFragment());
         fragments.add(new HistoryFragment());
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/StarredContactsAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/StarredContactsAdapter.java
index 6690341..d2a4c1d 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/StarredContactsAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/StarredContactsAdapter.java
@@ -70,6 +70,11 @@
         notifyDataSetChanged();
     }
 
+    public void setData(ArrayList<CallContact> contacts) {
+        dataset = contacts;
+        notifyDataSetChanged();
+    }
+
     @Override
     public int getCount() {
         return dataset.size();
@@ -97,7 +102,7 @@
 
         CallContact item = dataset.get(pos);
 
-        ((TextView) v.findViewById(R.id.display_name)).setText(item.getmDisplayName());
+        ((TextView) v.findViewById(R.id.display_name)).setText(item.getDisplayName());
         ImageView photo_view = (ImageView) v.findViewById(R.id.photo);
 
         if(item.hasPhoto()){
diff --git a/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java b/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java
index 8026bb8..bd93dd1 100644
--- a/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java
@@ -37,6 +37,7 @@
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.content.*;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -49,26 +50,33 @@
 import cx.ring.R;
 import cx.ring.fragments.AdvancedAccountFragment;
 import cx.ring.fragments.AudioManagementFragment;
+import cx.ring.fragments.HomeFragment;
+import cx.ring.fragments.MenuFragment;
 import cx.ring.fragments.NestedSettingsFragment;
 import cx.ring.fragments.SecurityAccountFragment;
 import cx.ring.model.account.Account;
 import cx.ring.service.ISipService;
+import cx.ring.service.LocalService;
 import cx.ring.service.SipService;
 import com.astuetz.PagerSlidingTabStrip;
 import java.util.ArrayList;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Observable;
 import java.util.Observer;
 
 import cx.ring.fragments.GeneralAccountFragment;
 
-public class AccountEditionActivity extends Activity implements GeneralAccountFragment.Callbacks, AudioManagementFragment.Callbacks,
+public class AccountEditionActivity extends Activity implements LocalService.Callbacks, GeneralAccountFragment.Callbacks, AudioManagementFragment.Callbacks,
         AdvancedAccountFragment.Callbacks, SecurityAccountFragment.Callbacks, NestedSettingsFragment.Callbacks {
     private static final String TAG = AccountEditionActivity.class.getSimpleName();
 
+    public static final Uri CONTENT_URI = Uri.withAppendedPath(LocalService.AUTHORITY_URI, "accounts");
+
     private boolean mBound = false;
-    private ISipService service;
-    private Account acc_selected;
+    private LocalService service;
+
+    private Account acc_selected = null;
 
     private NestedSettingsFragment toDisplay;
 
@@ -81,24 +89,35 @@
     };
 
     PreferencesPagerAdapter mPreferencesPagerAdapter;
+
     private ServiceConnection mConnection = new ServiceConnection() {
 
         @Override
-        public void onServiceConnected(ComponentName className, IBinder binder) {
-            service = ISipService.Stub.asInterface(binder);
+        public void onServiceConnected(ComponentName className, IBinder s) {
+            LocalService.LocalBinder binder = (LocalService.LocalBinder) s;
+            service = binder.getService();
             mBound = true;
 
-            ArrayList<Fragment> fragments = new ArrayList<Fragment>();
+            setContentView(R.layout.activity_account_settings);
+            getActionBar().setDisplayHomeAsUpEnabled(true);
+            String account_id = getIntent().getData().getLastPathSegment();
+            Log.i(TAG, "Service connected " + className.getClassName() + " " + getIntent().getData().toString());
+
+            acc_selected = service.getAccount(account_id);
+            acc_selected.addObserver(mAccountObserver);
+            getActionBar().setTitle(acc_selected.getAlias());
+
+            ArrayList<Fragment> fragments = new ArrayList<>();
             if (acc_selected.isIP2IP()) {
                 fragments.add(new AudioManagementFragment());
             } else {
                 fragments.add(new GeneralAccountFragment());
                 fragments.add(new AudioManagementFragment());
-				if(acc_selected.isSip())
-				{
-					fragments.add(new AdvancedAccountFragment());
-					fragments.add(new SecurityAccountFragment());
-				}
+                if(acc_selected.isSip())
+                {
+                    fragments.add(new AdvancedAccountFragment());
+                    fragments.add(new SecurityAccountFragment());
+                }
             }
 
             ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
@@ -110,33 +129,22 @@
             final PagerSlidingTabStrip strip = PagerSlidingTabStrip.class.cast(findViewById(R.id.pager_sliding_strip));
 
             strip.setViewPager(mViewPager);
-
         }
 
         @Override
         public void onServiceDisconnected(ComponentName arg0) {
-
+            acc_selected.deleteObserver(mAccountObserver);
+            mBound = false;
         }
     };
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.activity_account_settings);
-
-        getActionBar().setDisplayHomeAsUpEnabled(true);
-
-        acc_selected = getIntent().getExtras().getParcelable("account");
-
-        acc_selected.addObserver(mAccountObserver);
-
         if (!mBound) {
-            Log.i(TAG, "onCreate: Binding service...");
-            Intent intent = new Intent(this, SipService.class);
+            Intent intent = new Intent(this, LocalService.class);
             bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
         }
-
     }
 
     @Override
@@ -206,8 +214,12 @@
 
     private void processAccount() {
         try {
-            service.setCredentials(acc_selected.getAccountID(), acc_selected.getCredentialsHashMapList());
-            service.setAccountDetails(acc_selected.getAccountID(), acc_selected.getDetails());
+            service.getRemoteService().setCredentials(acc_selected.getAccountID(), acc_selected.getCredentialsHashMapList());
+            Map<String, String> details = acc_selected.getDetails();
+            service.getRemoteService().setAccountDetails(acc_selected.getAccountID(), details);
+            Log.w(TAG, "service.setAccountDetails " + details.get("Account.hostname"));
+            getActionBar().setTitle(acc_selected.getAlias());;
+
         } catch (RemoteException e) {
             e.printStackTrace();
         }
@@ -225,7 +237,7 @@
                         bundle.putString("AccountID", acc_selected.getAccountID());
 
                         try {
-                            service.removeAccount(acc_selected.getAccountID());
+                            service.getRemoteService().removeAccount(acc_selected.getAccountID());
                         } catch (RemoteException e) {
                             e.printStackTrace();
                         }
@@ -244,6 +256,16 @@
         return alertDialog;
     }
 
+    @Override
+    public ISipService getRemoteService() {
+        return service.getRemoteService();
+    }
+
+    @Override
+    public LocalService getService() {
+        return service;
+    }
+
     public class PreferencesPagerAdapter extends FragmentStatePagerAdapter {
 
         Context mContext;
@@ -290,11 +312,6 @@
     }
 
     @Override
-    public ISipService getService() {
-        return service;
-    }
-
-    @Override
     public Account getAccount() {
         return acc_selected;
     }
diff --git a/ring-android/app/src/main/java/cx/ring/client/CallActivity.java b/ring-android/app/src/main/java/cx/ring/client/CallActivity.java
index 32682b7..c481bca 100644
--- a/ring-android/app/src/main/java/cx/ring/client/CallActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/CallActivity.java
@@ -33,28 +33,25 @@
 
 package cx.ring.client;
 
-import java.util.*;
-
 import android.app.Activity;
 import android.util.Log;
 import cx.ring.R;
 import cx.ring.fragments.CallFragment;
-import cx.ring.fragments.IMFragment;
+import cx.ring.model.Conversation;
+import cx.ring.model.TextMessage;
 import cx.ring.model.account.Account;
 import cx.ring.model.CallContact;
 import cx.ring.model.Conference;
 import cx.ring.model.SipCall;
-import cx.ring.model.SipMessage;
+import cx.ring.model.account.AccountDetailBasic;
 import cx.ring.service.ISipService;
-import cx.ring.service.SipService;
+import cx.ring.service.LocalService;
 import cx.ring.utils.CallProximityManager;
-import cx.ring.views.CallPaneLayout;
 
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.net.Uri;
 import android.os.Bundle;
@@ -62,88 +59,37 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.support.v4.widget.SlidingPaneLayout;
 import android.view.KeyEvent;
-import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 
-public class CallActivity extends Activity implements IMFragment.Callbacks, CallFragment.Callbacks, CallProximityManager.ProximityDirector {
-
+public class CallActivity extends Activity implements LocalService.Callbacks, CallFragment.Callbacks, CallProximityManager.ProximityDirector {
     @SuppressWarnings("unused")
     static final String TAG = "CallActivity";
-    private ISipService mService;
-    CallPaneLayout mSlidingPaneLayout;
+    private boolean init = false;
+    private LocalService service;
 
-    IMFragment mIMFragment;
     CallFragment mCurrentCallFragment;
     private Conference mDisplayedConference;
 
     /* result code sent in case of call failure */
     public static int RESULT_FAILURE = -10;
-    private CallProximityManager mProximityManager;
+    private CallProximityManager mProximityManager = null;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "CallActivity onCreate");
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_call_layout);
 
         Window w = getWindow();
         w.setFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED, WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
 
-        setUpSlidingPanel();
-
-        mProximityManager = new CallProximityManager(this, this);
-        mProximityManager.startTracking();
-
-        mCurrentCallFragment = new CallFragment();
-        mIMFragment = new IMFragment();
-
-        if(!checkExternalCall()) {
-            mDisplayedConference = getIntent().getParcelableExtra("conference");
-            Bundle IMBundle = new Bundle();
-            if (getIntent().getBooleanExtra("resuming", false)) {
-                IMBundle.putParcelableArrayList("messages", mDisplayedConference.getMessages());
-                mIMFragment.setArguments(IMBundle);
-            } else {
-                IMBundle.putParcelableArrayList("messages", new ArrayList<SipMessage>());
-                mIMFragment.setArguments(IMBundle);
-            }
-        }
-
-        mSlidingPaneLayout.setCurFragment(mCurrentCallFragment);
-        getFragmentManager().beginTransaction().replace(R.id.ongoingcall_pane, mCurrentCallFragment)
-                .replace(R.id.message_list_frame, mIMFragment).commit();
-    }
-
-    private void setUpSlidingPanel() {
-        mSlidingPaneLayout = (CallPaneLayout) findViewById(R.id.slidingpanelayout);
-        mSlidingPaneLayout.setParallaxDistance(500);
-        mSlidingPaneLayout.setSliderFadeColor(Color.TRANSPARENT);
-
-        mSlidingPaneLayout.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() {
-
-            @Override
-            public void onPanelSlide(View view, float offSet) {
-            }
-
-            @Override
-            public void onPanelOpened(View view) {
-                getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-            }
-
-            @Override
-            public void onPanelClosed(View view) {
-                mCurrentCallFragment.getBubbleView().restartDrawing();
-                getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
-            }
-        });
+        Intent intent = new Intent(this, LocalService.class);
+        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
     }
 
     @Override
     public void onFragmentCreated() {
-        Intent intent = new Intent(this, SipService.class);
-        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
     }
 
     @Override
@@ -182,11 +128,12 @@
 
     @Override
     protected void onDestroy() {
-
+        Log.i(TAG, "CallActivity onDestroy");
         unbindService(mConnection);
-
-        mProximityManager.stopTracking();
-        mProximityManager.release(0);
+        if (mProximityManager != null) {
+            mProximityManager.stopTracking();
+            mProximityManager.release(0);
+        }
 
         super.onDestroy();
     }
@@ -198,15 +145,34 @@
         @SuppressWarnings("unchecked")
         @Override
         public void onServiceConnected(ComponentName className, IBinder binder) {
-            mService = ISipService.Stub.asInterface(binder);
+            service = ((LocalService.LocalBinder)binder).getService();
+
+            if (!init) {
+                mProximityManager = new CallProximityManager(CallActivity.this, CallActivity.this);
+                mProximityManager.startTracking();
+
+                if(!checkExternalCall()) {
+                    mDisplayedConference = getIntent().getParcelableExtra("conference");
+                }
+                Log.i(TAG, "CallActivity onCreate in:" + mDisplayedConference.isIncoming() + " out:" + mDisplayedConference.isOnGoing() + " contact" + mDisplayedConference.getParticipants().get(0).getContact().getDisplayName());
+                init = true;
+            }
 
             if (mDisplayedConference.getState().contentEquals("NONE")) {
+                SipCall call = mDisplayedConference.getParticipants().get(0);
                 try {
-                    mService.placeCall(mDisplayedConference.getParticipants().get(0));
+                    String callId = service.getRemoteService().placeCall(call);
+                    if (callId == null || callId.isEmpty()) {
+                        CallActivity.this.terminateCall();
+                    }
+                    mDisplayedConference = service.getRemoteService().getConference(callId);
                 } catch (RemoteException e) {
                     e.printStackTrace();
                 }
             }
+
+            setContentView(R.layout.activity_call_layout);
+            mCurrentCallFragment = (CallFragment) getFragmentManager().findFragmentById(R.id.ongoingcall_pane);
         }
 
         @Override
@@ -217,25 +183,30 @@
     private boolean checkExternalCall() {
         Uri u = getIntent().getData();
         if (u != null) {
-            CallContact c = CallContact.ContactBuilder.buildUnknownContact(u.getSchemeSpecificPart());
+            String number = u.getSchemeSpecificPart();
+            Log.w(TAG, "number " + number);
+            number = CallContact.canonicalNumber(number);
+            Log.w(TAG, "canonicalNumber " + number);
+            CallContact c = service.findContactByNumber(number);
+            Conversation conv = service.getByContact(c);
+            if (conv == null)
+                conv = new Conversation(c);
+            Account acc = service.getAccounts().get(0);
+            String id = conv.getLastAccountUsed();
+            if (id != null && !id.isEmpty()) {
+                Account alt_acc = service.getAccount(id);
+                Log.w(TAG, "Found suitable account for calling " + u.getSchemeSpecificPart() + " " + id + " " + alt_acc.getBasicDetails().getDetailString(AccountDetailBasic.CONFIG_ACCOUNT_TYPE));
+                if (alt_acc.isEnabled())
+                    acc = alt_acc;
+            } else {
+                acc = service.guessAccount(c, number);
+            }
             try {
-                String accountID = (String) mService.getAccountList().get(1); // We use the first account to place outgoing calls
-                Map<String, String> details = (Map<String, String>) mService.getAccountDetails(accountID);
-                ArrayList<Map<String, String>> credentials = (ArrayList<Map<String, String>>) mService.getCredentials(accountID);
-                Map<String, String> state = (Map<String, String>) mService.getVolatileAccountDetails(accountID);
-                Account acc = new Account(accountID, details, credentials, state);
-
-                Bundle args = new Bundle();
-                args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
-                args.putParcelable(SipCall.ACCOUNT, acc);
-                args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_NONE);
-                args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
-                args.putParcelable(SipCall.CONTACT, c);
-
+                SipCall call = new SipCall(null, acc.getAccountID(), number, SipCall.Direction.OUTGOING);
+                call.setCallState(SipCall.State.NONE);
+                call.setContact(c);
                 mDisplayedConference = new Conference(Conference.DEFAULT_ID);
-                mDisplayedConference.getParticipants().add(new SipCall(args));
-            } catch (RemoteException e) {
-                e.printStackTrace();
+                mDisplayedConference.getParticipants().add(call);
             } catch (Exception e) {
                 e.printStackTrace();
             }
@@ -245,8 +216,13 @@
     }
 
     @Override
-    public ISipService getService() {
-        return mService;
+    public ISipService getRemoteService() {
+        return service.getRemoteService();
+    }
+
+    @Override
+    public LocalService getService() {
+        return service;
     }
 
     @Override
@@ -273,30 +249,7 @@
     @Override
     public void terminateCall() {
         mHandler.removeCallbacks(mUpdateTimeTask);
-        mCurrentCallFragment.getBubbleView().stopThread();
-        TimerTask quit = new TimerTask() {
-
-            @Override
-            public void run() {
-                finish();
-            }
-        };
-
-        new Timer().schedule(quit, 1000);
-    }
-
-    @Override
-    public boolean sendIM(SipMessage msg) {
-
-        try {
-            Log.i(TAG, "Sending:"+msg.comment+"to"+mDisplayedConference.getId());
-            mService.sendTextMessage(mDisplayedConference.getId(), msg);
-        } catch (RemoteException e) {
-            e.printStackTrace();
-            return false;
-        }
-
-        return true;
+        finish();
     }
 
     @Override
@@ -305,24 +258,11 @@
     }
 
     @Override
-    public void slideChatScreen() {
-
-        if (mSlidingPaneLayout.isOpen()) {
-            mSlidingPaneLayout.closePane();
-        } else {
-            mCurrentCallFragment.getBubbleView().stopThread();
-            mSlidingPaneLayout.openPane();
-        }
-    }
-
-    @Override
     public boolean shouldActivateProximity() {
         return true;
     }
 
     @Override
     public void onProximityTrackingChanged(boolean acquired) {
-        // TODO Stub de la méthode généré automatiquement
-
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java b/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java
new file mode 100644
index 0000000..a0ce375
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java
@@ -0,0 +1,386 @@
+package cx.ring.client;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import cx.ring.R;
+import cx.ring.adapters.ContactPictureTask;
+import cx.ring.model.CallContact;
+import cx.ring.model.Conference;
+import cx.ring.model.Conversation;
+import cx.ring.model.SipCall;
+import cx.ring.model.TextMessage;
+import cx.ring.model.account.Account;
+import cx.ring.service.LocalService;
+
+public class ConversationActivity extends Activity {
+    private static final String TAG = ConversationActivity.class.getSimpleName();
+
+    public static final Uri CONTENT_URI = Uri.withAppendedPath(LocalService.AUTHORITY_URI, "conversations");
+
+    private boolean mBound = false;
+    private LocalService service = null;
+    private Conversation conversation = null;
+    private String preferredNumber = null;
+
+
+    private ListView histList = null;
+    private View msgSendBtn = null;
+    private EditText msgEditTxt = null;
+    private ViewGroup bottomPane = null;
+
+    private ConversationAdapter adapter = null;
+
+    private ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder binder) {
+            service = ((LocalService.LocalBinder)binder).getService();
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(LocalService.ACTION_CONF_UPDATE);
+            registerReceiver(receiver, intentFilter);
+
+            mBound = true;
+
+            String conv_id = getIntent().getData().getLastPathSegment();
+            preferredNumber = getIntent().getStringExtra("number");
+            conversation = service.getConversation(conv_id);
+            if (conversation == null) {
+                long contact_id = CallContact.contactIdFromId(conv_id);
+                CallContact contact;
+                if (contact_id >= 0)
+                    contact = service.findContactById(contact_id);
+                else if (preferredNumber != null && !preferredNumber.isEmpty()) {
+                    contact = service.findContactByNumber(preferredNumber);
+                    if (contact == null)
+                        contact = CallContact.ContactBuilder.buildUnknownContact(conv_id);
+                } else {
+                    contact = service.findContactByNumber(conv_id);
+                    if (contact == null)
+                        contact = CallContact.ContactBuilder.buildUnknownContact(conv_id);
+                    preferredNumber = conv_id;
+                }
+                conversation = service.startConversation(contact);
+            }
+
+            Log.w(TAG, "ConversationActivity onServiceConnected " + conv_id);
+
+            if (conversation == null) {
+                finish();
+                return;
+            }
+
+            getActionBar().setTitle(conversation.getContact().getDisplayName());
+
+            Conference conf = conversation.getCurrentCall();
+            bottomPane.setVisibility(conf == null ? View.GONE : View.VISIBLE);
+            if (conf != null) {
+                Log.w(TAG, "ConversationActivity onServiceConnected " + conf.getId() + " " + conversation.getCurrentCall());
+                bottomPane.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        startActivity(new Intent(ConversationActivity.this.getApplicationContext(), CallActivity.class).putExtra("conference", conversation.getCurrentCall()));
+                    }
+                });
+            }
+
+            adapter.updateDataset(conversation.getHistory());
+            scrolltoBottom();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName arg0) {
+            Log.w(TAG, "ConversationActivity onServiceDisconnected " + arg0.getClassName());
+            mBound = false;
+        }
+    };
+    final BroadcastReceiver receiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.w(TAG, "onReceive " + intent.getAction() + " " + intent.getDataString());
+            //conversation = service.getConversation(conversation.getId());
+            conversation = service.getByContact(conversation.getContact());
+            adapter.updateDataset(conversation.getHistory());
+            scrolltoBottom();
+            Conference conf = conversation.getCurrentCall();
+            bottomPane.setVisibility(conf == null ? View.GONE : View.VISIBLE);
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.frag_conversation);
+        msgEditTxt = (EditText) findViewById(R.id.msg_input_txt);
+        msgSendBtn = findViewById(R.id.msg_send);
+        msgSendBtn.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onSendTextMessage(msgEditTxt.getText().toString());
+                msgEditTxt.setText("");
+            }
+        });
+        bottomPane = (ViewGroup) findViewById(R.id.ongoingcall_pane);
+        bottomPane.setVisibility(View.GONE);
+        //getActionBar().setDisplayHomeAsUpEnabled(true);
+        conversation = getIntent().getParcelableExtra("conversation");
+
+        adapter = new ConversationAdapter(this);
+        histList = (ListView) findViewById(R.id.hist_list);
+        histList.setAdapter(adapter);
+
+        if (!mBound) {
+            Log.i(TAG, "onCreate: Binding service...");
+            Intent intent = new Intent(this, LocalService.class);
+            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+            service = null;
+        }
+    }
+
+    private void scrolltoBottom() {
+        histList.post(new Runnable() {
+            @Override
+            public void run() {
+                // Select the last row so it will scroll into view...
+                histList.setSelection(adapter.getCount() - 1);
+            }
+        });
+    }
+
+    private class ConversationAdapter extends BaseAdapter {
+        final private Context context;
+        final private ArrayList<Conversation.ConversationElement> texts = new ArrayList<>();
+        private ExecutorService infos_fetcher = Executors.newCachedThreadPool();
+
+        public void updateDataset(ArrayList<Conversation.ConversationElement> list) {
+            Log.i(TAG, "updateDataset " + list.size());
+            if (list.size() == 0 && texts.size() == 0)
+                return;
+            texts.clear();
+            texts.addAll(list);
+            notifyDataSetChanged();
+        }
+
+        ConversationAdapter(Context ctx) {
+            context = ctx;
+        }
+
+        @Override
+        public int getCount() {
+            return texts.size();
+        }
+
+        @Override
+        public Conversation.ConversationElement getItem(int position) {
+            return texts.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return 0;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null)
+                convertView = LayoutInflater.from(context).inflate(R.layout.item_textmsg, null);
+
+            ViewGroup txtEntry = (ViewGroup) convertView.findViewById(R.id.txt_entry);
+            TextView msgTxt = (TextView) convertView.findViewById(R.id.msg_txt);
+            TextView msgDetailTxt = (TextView) convertView.findViewById(R.id.msg_details_txt);
+            ImageView photo = (ImageView) convertView.findViewById(R.id.photo);
+
+            ViewGroup txtEntryRight = (ViewGroup) convertView.findViewById(R.id.txt_entry_right);
+            TextView msgTxtRight = (TextView) convertView.findViewById(R.id.msg_txt_right);
+            TextView msgDetailTxtRight = (TextView) convertView.findViewById(R.id.msg_details_txt_right);
+
+            ViewGroup callEntry = (ViewGroup) convertView.findViewById(R.id.call_entry);
+            TextView histTxt = (TextView) convertView.findViewById(R.id.call_hist_txt);
+            TextView histDetailTxt = (TextView) convertView.findViewById(R.id.call_details_txt);
+
+            Conversation.ConversationElement txt = texts.get(position);
+            if (txt.text != null) {
+                callEntry.setVisibility(View.GONE);
+                if (txt.text.isIncoming()) {
+                    txtEntry.setVisibility(View.VISIBLE);
+                    txtEntryRight.setVisibility(View.GONE);
+                    msgTxt.setText(txt.text.getMessage());
+                    msgDetailTxt.setText(DateFormat.getDateTimeInstance().format(new Date(txt.text.getTimestamp())));
+                    infos_fetcher.execute(new ContactPictureTask(context, photo, txt.text.getContact()));
+                } else {
+                    txtEntry.setVisibility(View.GONE);
+                    txtEntryRight.setVisibility(View.VISIBLE);
+                    msgTxtRight.setText(txt.text.getMessage());
+                    msgDetailTxtRight.setText(DateFormat.getDateTimeInstance().format(new Date(txt.text.getTimestamp())));
+                }
+            } else {
+                callEntry.setVisibility(View.VISIBLE);
+                txtEntry.setVisibility(View.GONE);
+                txtEntryRight.setVisibility(View.GONE);
+                msgTxt.setText("");
+                histTxt.setText((txt.call.isIncoming() ? "Incoming" : "Outgoing") + " call with " + txt.call.getNumber());
+                histDetailTxt.setText(DateFormat.getDateTimeInstance().format(txt.call.getStartDate()));
+            }
+
+            return convertView;
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        if (mBound) {
+            unregisterReceiver(receiver);
+            unbindService(mConnection);
+            mBound = false;
+        }
+        super.onDestroy();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu items for use in the action bar
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.conversation_actions, menu);
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle presses on the action bar items
+        switch (item.getItemId()) {
+            case R.id.conv_action_audiocall:
+                onAudioCall();
+                return true;
+            case R.id.conv_action_videocall:
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+    public void launchCallActivity(SipCall infos) {
+        Conference tmp = conversation.getCurrentCall();
+        if (tmp == null)
+            //tmp = service.startConversation(infos.getContact());
+            tmp = new Conference(Conference.DEFAULT_ID);
+
+        tmp.getParticipants().add(infos);
+        Intent intent = new Intent().setClass(this, CallActivity.class);
+        intent.putExtra("conference", tmp);
+        intent.putExtra("resuming", false);
+        startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL);
+        // overridePendingTransition(R.anim.slide_down, R.anim.slide_up);
+    }
+
+    private void onSendTextMessage(String txt) {
+
+        Conference conf = conversation.getCurrentCall();
+        if (conf == null || !conf.isOnGoing()) {
+            String account = conversation.getLastAccountUsed();
+            if (account == null || account.isEmpty())
+                account = service.guessAccount(conversation.getContact(), conversation.contact.getPhones().get(0).getNumber()).getAccountID();
+            String number = preferredNumber;
+            if (number == null || number.isEmpty())
+                number = conversation.getLastNumberUsed(account);
+            if (number == null || number.isEmpty())
+                number = conversation.contact.getPhones().get(0).getNumber();
+            try {
+                service.getRemoteService().sendAccountTextMessage(account, number, txt);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        } else {
+            try {
+                service.getRemoteService().sendTextMessage(conf.getId(), new TextMessage(false, txt));
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private void onAudioCall() {
+        Conference conf = conversation.getCurrentCall();
+        if (conf != null) {
+            startActivity(new Intent(ConversationActivity.this.getApplicationContext(), CallActivity.class).putExtra("conference", conversation.getCurrentCall()));
+            return;
+        }
+
+        if (service.getAccounts().isEmpty()) {
+            //createNotRegisteredDialog().show();
+            return;
+        }
+
+        Account usedAccount = service.getAccounts().get(0);
+        CallContact contact = null;
+        if (conversation != null) {
+            String last_used = conversation.getLastAccountUsed();
+            Account a = service.getAccount(last_used);
+            if (a != null/* && a.isEnabled()*/)
+                usedAccount = a;
+            else {
+                Set<String> acc_ids = conversation.getAccountsUsed();
+                for (Account acc : service.getAccounts()) {
+                    if (acc_ids.contains(acc.getAccountID())) {
+                        usedAccount = acc;
+                        break;
+                    }
+                }
+            }
+            contact = conversation.getContact();
+        }   
+
+        String number = preferredNumber;
+        if (number == null)
+            number = conversation.getLastNumberUsed(usedAccount.getAccountID());
+        if (number == null && contact != null)
+            number = contact.getPhones().get(0).getNumber();
+
+        //conversation.getHistory().getAccountID()
+        //if (usedAccount.isRegistered() || usedAccount.isIP2IP()) {
+         /*   Bundle args = new Bundle();
+            args.putParcelable(SipCall.ACCOUNT, usedAccount);
+            args.putInt(SipCall.STATE, SipCall.State.NONE);
+            args.putInt(SipCall.TYPE, SipCall.Direction.OUTGOING);
+            args.putParcelable(SipCall.CONTACT, contact);*/
+        SipCall call = new SipCall(null, usedAccount.getAccountID(), number, SipCall.Direction.OUTGOING);
+        call.setContact(contact);
+
+            try {
+                launchCallActivity(call);
+            } catch (Exception e) {
+                e.printStackTrace();
+                Log.e(TAG, e.toString());
+            }
+        /*} else {
+            createNotRegisteredDialog().show();
+        }*/
+
+    }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
index 9358e7e..52d9b37 100644
--- a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
@@ -36,9 +36,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.Random;
 import java.util.Timer;
-import java.util.TimerTask;
+import java.util.regex.Pattern;
 
 import android.app.Activity;
 import android.app.AlertDialog;
@@ -52,14 +51,13 @@
 import cx.ring.fragments.HomeFragment;
 import cx.ring.fragments.MenuFragment;
 import cx.ring.history.HistoryEntry;
+import cx.ring.history.HistoryManager;
+import cx.ring.loaders.LoaderConstants;
 import cx.ring.model.account.Account;
-import cx.ring.model.CallContact;
 import cx.ring.model.Conference;
 import cx.ring.model.SipCall;
 import cx.ring.service.ISipService;
-import cx.ring.service.SipService;
-import cx.ring.views.SlidingUpPanelLayout;
-import cx.ring.views.SlidingUpPanelLayout.PanelSlideListener;
+import cx.ring.service.LocalService;
 
 import android.app.Fragment;
 import android.app.FragmentManager;
@@ -72,18 +70,12 @@
 import android.content.ServiceConnection;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
-import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.preference.PreferenceManager;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 import android.support.design.widget.FloatingActionButton;
 import android.support.design.widget.NavigationView;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.app.ActionBarDrawerToggle;
 import android.support.v7.app.AppCompatActivity;
@@ -91,14 +83,14 @@
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.RelativeLayout;
-import android.widget.Toast;
 
-public class HomeActivity extends AppCompatActivity implements DialingFragment.Callbacks, AccountsManagementFragment.Callbacks,
-        ContactListFragment.Callbacks, CallListFragment.Callbacks, HistoryFragment.Callbacks, NavigationView.OnNavigationItemSelectedListener, MenuFragment.Callbacks {
+public class HomeActivity extends AppCompatActivity implements LocalService.Callbacks, DialingFragment.Callbacks,
+        /*ContactListFragment.Callbacks, */HistoryFragment.Callbacks, NavigationView.OnNavigationItemSelectedListener {
 
     static final String TAG = HomeActivity.class.getSimpleName();
 
@@ -107,12 +99,13 @@
     private MenuFragment fMenuHead = null;
 
     private boolean mBound = false;
-    private ISipService service;
+    private LocalService service;
 
     public static final int REQUEST_CODE_PREFERENCES = 1;
     public static final int REQUEST_CODE_CALL = 3;
+    public static final int REQUEST_CODE_CONVERSATION = 4;
 
-    SlidingUpPanelLayout mContactDrawer;
+    //SlidingUpPanelLayout mContactDrawer;
     private DrawerLayout mNavigationDrawer;
     private ActionBarDrawerToggle mDrawerToggle;
     private Toolbar toolbar;
@@ -123,6 +116,22 @@
 
     protected Fragment fContent;
 
+    public static final Pattern RING_ID_REGEX = Pattern.compile("^\\s+(?:ring(?:[\\s\\:]+))?(\\p{XDigit}{40})\\s+$", Pattern.CASE_INSENSITIVE);
+
+    private static void setDefaultUncaughtExceptionHandler() {
+        try {
+            Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+                @Override
+                public void uncaughtException(Thread t, Throwable e) {
+                    Log.e(TAG, "Uncaught Exception detected in thread ", e);
+                    //e.printStackTrace();
+                }
+            });
+        } catch (SecurityException e) {
+            Log.e(TAG, "Could not set the Default Uncaught Exception Handler");
+        }
+    }
+
     /* called before activity is killed, e.g. rotation */
     @Override
     protected void onSaveInstanceState(Bundle bundle) {
@@ -131,14 +140,18 @@
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
+        setDefaultUncaughtExceptionHandler();
+
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_home);
 
         // Bind to LocalService
         if (!mBound) {
             Log.i(TAG, "onStart: Binding service...");
-            Intent intent = new Intent(this, SipService.class);
+            /*Intent intent = new Intent(this, SipService.class);
             startService(intent);
+            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);*/
+            Intent intent = new Intent(this, LocalService.class);
             bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
         }
 
@@ -148,9 +161,13 @@
 
         fMenu = (NavigationView) findViewById(R.id.left_drawer);
         fMenu.setNavigationItemSelectedListener(this);
-
-        mContactsFragment = new ContactListFragment();
-        getFragmentManager().beginTransaction().replace(R.id.contacts_frame, mContactsFragment).commit();
+/*
+        FragmentManager fm = getFragmentManager();
+        mContactsFragment = (ContactListFragment) fm.findFragmentByTag(ContactListFragment.TAG);
+        if(mContactsFragment == null) {
+            mContactsFragment = new ContactListFragment();
+            getFragmentManager().beginTransaction().replace(R.id.contacts_frame, mContactsFragment, ContactListFragment.TAG).commit();
+        }
 
         mContactDrawer = (SlidingUpPanelLayout) findViewById(R.id.contact_panel);
         // mContactDrawer.setShadowDrawable(getResources().getDrawable(R.drawable.above_shadow));
@@ -187,7 +204,7 @@
 
             }
         });
-
+*/
         mNavigationDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
 
         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@@ -217,17 +234,23 @@
     @Override
     protected void onPostCreate(Bundle savedInstanceState) {
         super.onPostCreate(savedInstanceState);
-        // Sync the toggle state after onRestoreInstanceState has occurred.
+        // Sync the toggle State after onRestoreInstanceState has occurred.
         mDrawerToggle.syncState();
-        if (mContactDrawer.isExpanded()) {
+        /*if (mContactDrawer.isExpanded()) {
             getSupportActionBar().hide();
-        }
+        }*/
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        mDrawerToggle.onConfigurationChanged(newConfig);
+        //mDrawerToggle.onConfigurationChanged(newConfig);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.history, menu);
+        return super.onCreateOptionsMenu(menu);
     }
 
     @Override
@@ -248,7 +271,11 @@
         TypedValue tv = new TypedValue();
         if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
             int abSz = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
-            ViewGroup.LayoutParams params = toolbar.getLayoutParams();
+            ViewGroup.LayoutParams params = toolbar.getLayoutParams();//toolbar.setContentInsetsRelative();
+
+            //TypedArray a = obtainStyledAttributes(attrs, R.styleable.Toolbar_titleMarginBottom);
+
+            //toolbar.get
             if (double_h) {
                 params.height = abSz*2;
                 actionButton.setVisibility(View.VISIBLE);
@@ -261,6 +288,7 @@
             toolbar.setMinimumHeight(abSz);
         }
         toolbar.setTitle(title_res);
+        //toolbar.setTitleTextAppearance(toolbar.getT);
     }
 
     public FloatingActionButton getActionButton() {
@@ -336,10 +364,10 @@
             return;
         }
 
-        if (mContactDrawer.isExpanded() || mContactDrawer.isAnchored()) {
+        /*if (mContactDrawer.isExpanded() || mContactDrawer.isAnchored()) {
             mContactDrawer.collapsePane();
             return;
-        }
+        }*/
 
         if (getFragmentManager().getBackStackEntryCount() > 1) {
             popCustomBackStack();
@@ -347,20 +375,7 @@
             return;
         }
 
-        if (isClosing) {
-            super.onBackPressed();
-            t.cancel();
-            finish();
-        } else {
-            t.schedule(new TimerTask() {
-                @Override
-                public void run() {
-                    isClosing = false;
-                }
-            }, 3000);
-            Toast.makeText(this, getResources().getString(R.string.close_msg), Toast.LENGTH_SHORT).show();
-            isClosing = true;
-        }
+        super.onBackPressed();
     }
 
     private void popCustomBackStack() {
@@ -376,20 +391,20 @@
     @Override
     protected void onPause() {
         super.onPause();
-
-        if (mBound) {
-            unbindService(mConnection);
-            mBound = false;
-        }
+        Log.d(TAG, "onPause");
     }
 
     /* activity finishes itself or is being killed by the system */
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        Log.i(TAG, "onDestroy: destroying service...");
-        Intent sipServiceIntent = new Intent(this, SipService.class);
-        stopService(sipServiceIntent);
+        if (mBound) {
+            unbindService(mConnection);
+            mBound = false;
+        }
+        //Log.i(TAG, "onDestroy: destroying service...");
+        //Intent sipServiceIntent = new Intent(this, SipService.class);
+        //stopService(sipServiceIntent);
     }
 
     public void launchCallActivity(SipCall infos) {
@@ -410,9 +425,13 @@
     private ServiceConnection mConnection = new ServiceConnection() {
 
         @Override
-        public void onServiceConnected(ComponentName className, IBinder binder) {
-            service = ISipService.Stub.asInterface(binder);
-            fContent = new HomeFragment();
+        public void onServiceConnected(ComponentName className, IBinder s) {
+            Log.i(TAG, "onServiceConnected " + className.getClassName());
+            LocalService.LocalBinder binder = (LocalService.LocalBinder) s;
+            service = binder.getService();
+
+            //service = ISipService.Stub.asInterface(binder);
+            fContent = new CallListFragment();
             if (fMenuHead != null)
                 fMenu.removeHeaderView(fMenuHead.getView());
             fMenu.inflateHeaderView(R.layout.menuheader);
@@ -420,18 +439,19 @@
 
             getFragmentManager().beginTransaction().replace(R.id.main_frame, fContent, "Home").addToBackStack("Home").commit();
             mBound = true;
-            Log.d(TAG, "Service connected service=" + service);
+            Log.i(TAG, "Service connected service=" + service);
         }
 
         @Override
-        public void onServiceDisconnected(ComponentName arg0) {
+        public void onServiceDisconnected(ComponentName className) {
+            Log.i(TAG, "onServiceConnected " + className.getClassName());
             if (fMenuHead != null) {
                 fMenu.removeHeaderView(fMenuHead.getView());
                 fMenuHead = null;
             }
 
             mBound = false;
-            Log.d(TAG, "Service disconnected service=" + service);
+            Log.i(TAG, "Service disconnected service=" + service);
         }
     };
 
@@ -442,8 +462,17 @@
         if (mDrawerToggle.onOptionsItemSelected(item)) {
             return true;
         }
-
-        return super.onOptionsItemSelected(item);
+        switch (item.getItemId()) {
+            case R.id.menu_clear_history:
+                // TODO clean Database!
+                //mHistoryManager.clearDB();
+                //getLoaderManager().restartLoader(LoaderConstants.HISTORY_LOADER, null, this);
+                HistoryManager m = new HistoryManager(this);
+                m.clearDB();
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
     }
 
     @Override
@@ -466,10 +495,16 @@
     }
 
     @Override
-    public ISipService getService() {
+    public ISipService getRemoteService() {
+        return service.getRemoteService();
+    }
+
+    @Override
+    public LocalService getService() {
         return service;
     }
 
+    /*
     @Override
     public void onTextContact(final CallContact c) {
         // TODO
@@ -483,6 +518,7 @@
         startActivity(intent);
     }
 
+
     @Override
     public void onCallContact(final CallContact c) {
 
@@ -506,10 +542,10 @@
             public void run() {
 
                 Bundle args = new Bundle();
-                args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
+                //args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
                 args.putParcelable(SipCall.ACCOUNT, fMenuHead.getSelectedAccount());
-                args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_NONE);
-                args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
+                args.putInt(SipCall.STATE, SipCall.State.NONE);
+                args.putInt(SipCall.TYPE, SipCall.Direction.OUTGOING);
 
                 Cursor cPhones = getContentResolver().query(Phone.CONTENT_URI, CONTACTS_PHONES_PROJECTION, Phone.CONTACT_ID + " =" + c.getId(),
                         null, null);
@@ -533,10 +569,10 @@
             }
         });
         launcher.start();
-        mContactDrawer.collapsePane();
+        //mContactDrawer.collapsePane();
 
     }
-
+*/
     @Override
     public void onCallHistory(HistoryEntry to) {
 
@@ -549,10 +585,10 @@
 
         if (usedAccount.isRegistered()) {
             Bundle args = new Bundle();
-            args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
+            //args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
             args.putParcelable(SipCall.ACCOUNT, usedAccount);
-            args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_NONE);
-            args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
+            args.putInt(SipCall.STATE, SipCall.State.NONE);
+            args.putInt(SipCall.TYPE, SipCall.Direction.OUTGOING);
             args.putParcelable(SipCall.CONTACT, to.getContact());
 
             try {
@@ -567,7 +603,15 @@
 
     @Override
     public void onCallDialed(String to) {
-        Account usedAccount = fMenuHead.getSelectedAccount();
+        Intent intent = new Intent()
+                .setClass(this, CallActivity.class)
+                .setAction(Intent.ACTION_CALL)
+                .setData(Uri.parse(to));
+        /*intent.putExtra("conference", tmp);
+        intent.putExtra("resuming", false);*/
+        startActivityForResult(intent, REQUEST_CODE_CALL);
+
+        /*Account usedAccount = fMenuHead.getSelectedAccount();
 
         if (usedAccount == null) {
             createAccountDialog().show();
@@ -576,10 +620,14 @@
 
         if (usedAccount.isRegistered() || usedAccount.isIP2IP()) {
             Bundle args = new Bundle();
-            args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
+
+            Matcher m = RING_ID_REGEX.matcher(to);
+            if (m.matches() && m.groupCount() > 0) {
+                to = "ring:"+m.group(1);
+            }
             args.putParcelable(SipCall.ACCOUNT, usedAccount);
-            args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_NONE);
-            args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
+            args.putInt(SipCall.STATE, SipCall.State.NONE);
+            args.putInt(SipCall.TYPE, SipCall.Direction.OUTGOING);
             args.putParcelable(SipCall.CONTACT, CallContact.ContactBuilder.buildUnknownContact(to));
 
             try {
@@ -589,7 +637,7 @@
             }
         } else {
             createNotRegisteredDialog().show();
-        }
+        }*/
     }
 
     private AlertDialog createNotRegisteredDialog() {
@@ -634,6 +682,7 @@
         return alertDialog;
     }
 
+    /*
     @Override
     public void onContactDragged() {
         mContactDrawer.collapsePane();
@@ -661,7 +710,7 @@
     public void setDragView(RelativeLayout relativeLayout) {
         mContactDrawer.setDragView(relativeLayout);
     }
-
+*/
     @Override
     public boolean onNavigationItemSelected(MenuItem pos) {
         pos.setChecked(true);
@@ -670,7 +719,7 @@
         switch (pos.getItemId()) {
             case R.id.menuitem_home:
 
-                if (fContent instanceof HomeFragment)
+                if (fContent instanceof CallListFragment)
                     break;
 
                 if (getFragmentManager().getBackStackEntryCount() == 1)
diff --git a/ring-android/app/src/main/java/cx/ring/client/NewConversationActivity.java b/ring-android/app/src/main/java/cx/ring/client/NewConversationActivity.java
new file mode 100644
index 0000000..9ccde78
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/client/NewConversationActivity.java
@@ -0,0 +1,141 @@
+package cx.ring.client;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.RelativeLayout;
+import android.widget.SearchView;
+
+import cx.ring.R;
+import cx.ring.fragments.ContactListFragment;
+import cx.ring.model.CallContact;
+
+public class NewConversationActivity extends Activity implements ContactListFragment.Callbacks {
+
+    //private SearchView searchView = null;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getActionBar().setDisplayHomeAsUpEnabled(true);
+        setContentView(R.layout.activity_new_conversation);
+    }
+/*
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.newconv_option_menu, menu);
+        //searchView = (SearchView) menu.findItem(R.id.contact_search).getActionView();
+        return true;
+    }
+*/
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                finish();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public void onCallContact(final CallContact c) {
+        if (c.getPhones().size() > 1) {
+            final CharSequence colors[] = new CharSequence[c.getPhones().size()];
+            int i = 0;
+            for (CallContact.Phone p : c.getPhones())
+                colors[i++] = p.getNumber();
+
+            AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            builder.setTitle("Choose a number");
+            builder.setItems(colors, new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    CharSequence selected = colors[which];
+                    Intent intent = new Intent()
+                            .setClass(NewConversationActivity.this, ConversationActivity.class)
+                            .setAction(Intent.ACTION_VIEW)
+                            .setData(Uri.withAppendedPath(ConversationActivity.CONTENT_URI, c.getIds().get(0)))
+                            .putExtra("number", selected);
+                    startActivityForResult(intent, HomeActivity.REQUEST_CODE_CONVERSATION);
+                }
+            });
+            builder.show();
+        } else {
+            Intent intent = new Intent()
+                    .setClass(this, ConversationActivity.class)
+                    .setAction(Intent.ACTION_VIEW)
+                    .setData(Uri.withAppendedPath(ConversationActivity.CONTENT_URI, c.getIds().get(0)));
+            startActivityForResult(intent, HomeActivity.REQUEST_CODE_CONVERSATION);
+        }
+    }
+
+    @Override
+    public void onTextContact(final CallContact c) {
+        if (c.getPhones().size() > 1) {
+            final CharSequence colors[] = new CharSequence[c.getPhones().size()];// {"red", "green", "blue", "black"};
+            int i = 0;
+            for (CallContact.Phone p : c.getPhones())
+                colors[i++] = p.getNumber();
+
+            AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            builder.setTitle("Choose a number");
+            builder.setItems(colors, new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    CharSequence selected = colors[which];
+                    Intent intent = new Intent()
+                            .setClass(NewConversationActivity.this, ConversationActivity.class)
+                            .setAction(Intent.ACTION_VIEW)
+                            .setData(Uri.withAppendedPath(ConversationActivity.CONTENT_URI, c.getIds().get(0)))
+                            .putExtra("number", selected);
+                    startActivityForResult(intent, HomeActivity.REQUEST_CODE_CONVERSATION);
+                }
+            });
+            builder.show();
+        } else {
+            Intent intent = new Intent()
+                    .setClass(this, ConversationActivity.class)
+                    .setAction(Intent.ACTION_VIEW)
+                    .setData(Uri.withAppendedPath(ConversationActivity.CONTENT_URI, c.getIds().get(0)));
+            startActivityForResult(intent, HomeActivity.REQUEST_CODE_CONVERSATION);
+        }
+    }
+
+    @Override
+    public void onContactDragged() {
+
+    }
+
+    @Override
+    public void toggleDrawer() {
+
+    }
+
+    @Override
+    public void onEditContact(CallContact item) {
+
+    }
+
+    @Override
+    public void setDragView(RelativeLayout relativeLayout) {
+
+    }
+
+    @Override
+    public void toggleForSearchDrawer() {
+
+    }
+/*
+    @Override
+    public SearchView getSearchView() {
+        return searchView;
+    }*/
+}
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AccountWrapperFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AccountWrapperFragment.java
deleted file mode 100644
index e22fb0c..0000000
--- a/ring-android/app/src/main/java/cx/ring/fragments/AccountWrapperFragment.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
- *
- *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
- *
- *  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, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Additional permission under GNU GPL version 3 section 7:
- *
- *  If you modify this program, or any covered work, by linking or
- *  combining it with the OpenSSL project's OpenSSL library (or a
- *  modified version of that library), containing parts covered by the
- *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
- *  grants you additional permission to convey the resulting work.
- *  Corresponding Source for a non-source form of such a combination
- *  shall include the source code for the parts of OpenSSL used as well
- *  as that of the covered work.
- */
-
-package cx.ring.fragments;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.app.Fragment;
-import android.util.Log;
-import cx.ring.interfaces.AccountsInterface;
-import cx.ring.service.ConfigurationManagerCallback;
-
-public abstract class AccountWrapperFragment extends Fragment implements AccountsInterface
-{
-    static final String TAG = "AccountWrapperFragment";
-
-    private AccountsReceiver mReceiver;
-
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mReceiver = new AccountsReceiver();
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(ConfigurationManagerCallback.ACCOUNT_STATE_CHANGED);
-        intentFilter.addAction(ConfigurationManagerCallback.ACCOUNTS_CHANGED);
-        getActivity().registerReceiver(mReceiver, intentFilter);
-    }
-
-    @Override
-    public void accountsChanged() {
-        Log.i(TAG, "accountsChanged");
-    }
-
-    @Override
-    public void accountStateChanged(String accoundID, String state, int code) {
-        Log.i(TAG, "accountStateChanged" + accoundID + " " + state + " " + code);
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        getActivity().unregisterReceiver(mReceiver);
-    }
-
-    public class AccountsReceiver extends BroadcastReceiver {
-
-        private final String TAG = AccountsReceiver.class.getSimpleName();
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().contentEquals(ConfigurationManagerCallback.ACCOUNT_STATE_CHANGED)) {
-                Log.i(TAG, "Received " + intent.getAction() + " " + intent.getStringExtra("Account") + " " + intent.getStringExtra("state") + " " + intent.getIntExtra("code", 0));
-                accountStateChanged(intent.getStringExtra("Account"), intent.getStringExtra("state"), intent.getIntExtra("code", 0));
-            } else if (intent.getAction().contentEquals(ConfigurationManagerCallback.ACCOUNTS_CHANGED)) {
-                Log.i(TAG, "Received" + intent.getAction());
-                accountsChanged();
-            }
-
-        }
-    }
-
-
-}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java
index d9b2570..f8ca5ab 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java
@@ -2,7 +2,8 @@
  *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *
  *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
- *      Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *          Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *          Adrien Béraud <adrien.beraud@savoirfairelinux.com>
  *
  *  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
@@ -35,11 +36,12 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.app.Activity;
-import android.app.LoaderManager;
-import android.content.AsyncTaskLoader;
+import android.app.Fragment;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.Loader;
+import android.content.IntentFilter;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.support.design.widget.FloatingActionButton;
@@ -53,28 +55,25 @@
 import cx.ring.client.AccountEditionActivity;
 import cx.ring.client.AccountWizard;
 import cx.ring.client.HomeActivity;
-import cx.ring.loaders.AccountsStateLoader;
-import cx.ring.loaders.AccountsLoader;
-import cx.ring.loaders.LoaderConstants;
 import cx.ring.model.account.Account;
-import cx.ring.model.account.AccountDetailAdvanced;
 import cx.ring.model.account.AccountDetailBasic;
-import cx.ring.service.ISipService;
+import cx.ring.service.LocalService;
 import cx.ring.views.dragsortlv.DragSortListView;
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.Map;
+import java.util.List;
 
-public class AccountsManagementFragment extends AccountWrapperFragment implements LoaderManager.LoaderCallbacks<Bundle> {
-    static final String TAG = "AccountManagementFrag";
-    static final String DEFAULT_ACCOUNT_ID = "IP2IP";
-    static final int ACCOUNT_CREATE_REQUEST = 1;
+public class AccountsManagementFragment extends Fragment {
+    static final String TAG = AccountsManagementFragment.class.getSimpleName();
+
+    private static final String DEFAULT_ACCOUNT_ID = "IP2IP";
+    public static final int ACCOUNT_CREATE_REQUEST = 1;
     public static final int ACCOUNT_EDIT_REQUEST = 2;
-    AccountsAdapter mAccountsAdapter;
-    AccountsAdapter mIP2IPAdapter;
+    private AccountsAdapter mAccountsAdapter;
+    private AccountsAdapter mIP2IPAdapter;
 
-    DragSortListView mDnDListView;
+    private DragSortListView mDnDListView;
     private View mLoadingView;
     private int mShortAnimationDuration;
 
@@ -86,46 +85,31 @@
                 mAccountsAdapter.remove(item);
                 mAccountsAdapter.insert(item, to);
                 try {
-                    mCallbacks.getService().setAccountOrder(mAccountsAdapter.generateAccountOrder());
+                    mCallbacks.getService().getRemoteService().setAccountOrder(mAccountsAdapter.generateAccountOrder());
                 } catch (RemoteException e) {
                     e.printStackTrace();
                 }
             }
         }
-
     };
 
-    private Callbacks mCallbacks = sDummyCallbacks;
-    private Account ip2ip;
-    private static Callbacks sDummyCallbacks = new Callbacks() {
-
-        @Override
-        public ISipService getService() {
-            return null;
-        }
-    };
-    private AccountsLoader accountsLoader;
-
-    public interface Callbacks {
-
-        public ISipService getService();
-
-    }
+    private LocalService.Callbacks mCallbacks = LocalService.DUMMY_CALLBACKS;
+    //private Account ip2ip;
 
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
-        if (!(activity instanceof Callbacks)) {
+        if (!(activity instanceof LocalService.Callbacks)) {
             throw new IllegalStateException("Activity must implement fragment's callbacks.");
         }
 
-        mCallbacks = (Callbacks) activity;
+        mCallbacks = (LocalService.Callbacks) activity;
     }
 
     @Override
     public void onDetach() {
         super.onDetach();
-        mCallbacks = sDummyCallbacks;
+        mCallbacks = LocalService.DUMMY_CALLBACKS;
     }
 
     @Override
@@ -133,13 +117,23 @@
         super.onCreate(savedInstanceState);
 
         Log.i(TAG, "Create Account Management Fragment");
-        mAccountsAdapter = new AccountsAdapter(getActivity(), new ArrayList<Account>());
-        mIP2IPAdapter = new AccountsAdapter(getActivity(), new ArrayList<Account>());
+        mAccountsAdapter = new AccountsAdapter(getActivity());
+        mIP2IPAdapter = new AccountsAdapter(getActivity());
         this.setHasOptionsMenu(true);
 
         mShortAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);
         Log.i(TAG, "anim time: " + mShortAnimationDuration);
-        getLoaderManager().initLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);
+        //getLoaderManager().initLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(LocalService.ACTION_ACCOUNT_UPDATE);
+        getActivity().registerReceiver(mReceiver, intentFilter);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        getActivity().unregisterReceiver(mReceiver);
     }
 
     @Override
@@ -170,8 +164,7 @@
 
             @Override
             public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
-                launchAccountEditActivity(ip2ip);
-
+                launchAccountEditActivity(mIP2IPAdapter.accounts.get(0));
             }
         });
 
@@ -185,7 +178,8 @@
 
     public void onResume() {
         super.onResume();
-        accountsLoader.onContentChanged();
+        //accountsLoader.onContentChanged();
+        refreshAccountList();
         ((HomeActivity) getActivity()).setToolbarState(true, R.string.menu_item_accounts);
         FloatingActionButton btn = ((HomeActivity) getActivity()).getActionButton();
         btn.setImageResource(R.drawable.ic_add_white_24dp);
@@ -196,6 +190,7 @@
                 startActivityForResult(intent, ACCOUNT_CREATE_REQUEST);
             }
         });
+        crossfade();
     }
 
     @Override
@@ -220,29 +215,17 @@
     private void launchAccountEditActivity(Account acc) {
         Log.i(TAG, "Launch account edit activity");
 
-        Intent intent = new Intent().setClass(getActivity(), AccountEditionActivity.class);
-        Bundle bundle = new Bundle();
-        bundle.putParcelable("account", acc);
-
-        intent.putExtras(bundle);
-
+        Intent intent = new Intent()
+                .setClass(getActivity(), AccountEditionActivity.class)
+                .setAction(Intent.ACTION_EDIT)
+                .setData(Uri.withAppendedPath(AccountEditionActivity.CONTENT_URI, acc.getAccountID()));
         startActivityForResult(intent, ACCOUNT_EDIT_REQUEST);
     }
 
     @Override
-    public void accountsChanged() {
-        accountsLoader.onContentChanged();
-    }
-
-    @Override
-    public void accountStateChanged(String accoundID, String state, int code) {
-        mAccountsAdapter.updateAccount(accoundID, state, code);
-    }
-
-    @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
-        accountsLoader.onContentChanged();
+        refreshAccountList();
     }
 
     /**
@@ -254,13 +237,12 @@
 
         // private static final String TAG = AccountSelectionAdapter.class.getSimpleName();
 
-        ArrayList<Account> accounts;
-        Context mContext;
+        private final ArrayList<Account> accounts = new ArrayList<>();
+        private final Context mContext;
 
-        public AccountsAdapter(Context cont, ArrayList<Account> newList) {
+        public AccountsAdapter(Context c) {
             super();
-            accounts = newList;
-            mContext = cont;
+            mContext = c;
         }
 
         public void insert(Account item, int to) {
@@ -335,7 +317,7 @@
                     public void onClick(View v) {
                         item.setEnabled(!item.isEnabled());
                         try {
-                            mCallbacks.getService().setAccountDetails(item.getAccountID(), item.getDetails());
+                            mCallbacks.getService().getRemoteService().setAccountDetails(item.getAccountID(), item.getDetails());
                         } catch (RemoteException e) {
                             e.printStackTrace();
                         }
@@ -381,39 +363,27 @@
 
         }
 
-        public void addAll(ArrayList<Account> results) {
+        public void addAll(List<Account> results) {
             Log.i(TAG, "AccountsAdapter addAll " + results.size());
             accounts.addAll(results);
-            /*for (final Account a : results) {
-                final String acc_id = a.getAccountID();
-                getLoaderManager().initLoader((int)(Long.parseLong(acc_id.substring(0, 8), 16) & 0x00000000FFFFFFFFL), null, new LoaderManager.LoaderCallbacks<Map<String, String>>() {
-                    @Override
-                    public Loader<Map<String, String>> onCreateLoader(int id, Bundle args) {
-                        Log.i(TAG, "AccountsAdapter addAll onCreateLoader " + id + " " + acc_id);
-                        return new AccountsStateLoader(getActivity(), mCallbacks.getService(), acc_id);
-                    }
-                    @Override
-                    public void onLoadFinished(Loader<Map<String, String>> loader, Map<String, String> data) {
-                        Log.w(TAG, "onLoadFinished");
-                        a.setRegistered_state(data.get(AccountDetailAdvanced.CONFIG_ACCOUNT_REGISTRATION_STATUS), Integer.getInteger(data.get(AccountDetailAdvanced.CONFIG_ACCOUNT_REGISTRATION_STATE_CODE)));
-                        notifyDataSetChanged();
-                    }
-                    @Override
-                    public void onLoaderReset(Loader<Map<String, String>> loader) {
-                    }
-                });
-            }*/
+            notifyDataSetChanged();
+        }
+
+        public void replaceAll(List<Account> results) {
+            Log.i(TAG, "AccountsAdapter replaceAll " + results.size());
+            accounts.clear();
+            accounts.addAll(results);
             notifyDataSetChanged();
         }
 
         /**
-         * Modify state of specific account
+         * Modify State of specific account
          */
         public void updateAccount(String accoundID, String state, int code) {
             Log.i(TAG, "updateAccount:" + state);
             for (Account a : accounts) {
                 if (a.getAccountID().contentEquals(accoundID)) {
-                    a.setRegistered_state(state, code);
+                    a.setRegistrationState(state, code);
                     notifyDataSetChanged();
                     return;
                 }
@@ -453,33 +423,24 @@
         });
     }
 
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().contentEquals(LocalService.ACTION_ACCOUNT_UPDATE)) {
+                refreshAccountList();
+            }
+        }
+    };
 
-    @Override
-    public AsyncTaskLoader<Bundle> onCreateLoader(int arg0, Bundle arg1) {
-        accountsLoader = new AccountsLoader(getActivity(), mCallbacks.getService());
-        return accountsLoader;
-    }
-
-    @Override
-    public void onLoadFinished(Loader<Bundle> bundleLoader, Bundle results) {
-        mAccountsAdapter.removeAll();
-        ArrayList<Account> tmp = results.getParcelableArrayList(AccountsStateLoader.ACCOUNTS);
-        ip2ip = results.getParcelable(AccountsStateLoader.ACCOUNT_IP2IP);
-        mAccountsAdapter.addAll(tmp);
-        mIP2IPAdapter.removeAll();
-        mIP2IPAdapter.insert(ip2ip, 0);
+    private void refreshAccountList() {
+        Log.i(TAG, "refreshAccountList");
+        mAccountsAdapter.replaceAll(mCallbacks.getService().getAccounts());
         if (mAccountsAdapter.isEmpty()) {
             mDnDListView.setEmptyView(getView().findViewById(R.id.empty_account_list));
         }
-        for (Account acc : tmp) {
-
-        }
-        crossfade();
+        mIP2IPAdapter.replaceAll(mCallbacks.getService().getIP2IPAccount());
+        Log.i(TAG, "refreshAccountList DONE");
+        mAccountsAdapter.notifyDataSetChanged();
+        mIP2IPAdapter.notifyDataSetChanged();
     }
-
-    @Override
-    public void onLoaderReset(Loader<Bundle> bundleLoader) {
-
-    }
-
 }
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AudioManagementFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AudioManagementFragment.java
index ec688e0..4f90c00 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AudioManagementFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AudioManagementFragment.java
@@ -42,6 +42,7 @@
 import cx.ring.model.account.Account;
 import cx.ring.model.Codec;
 import cx.ring.service.ISipService;
+import cx.ring.service.LocalService;
 import cx.ring.views.dragsortlv.DragSortListView;
 
 import android.app.Activity;
@@ -73,26 +74,23 @@
     ArrayList<Codec> codecs;
     private DragSortListView mCodecList;
     CodecAdapter listAdapter;
-    private static Callbacks sDummyCallbacks = new Callbacks() {
-
+    private static final Callbacks sDummyCallbacks = new Callbacks() {
         @Override
-        public ISipService getService() {
+        public ISipService getRemoteService() {
             return null;
         }
-
+        @Override
+        public LocalService getService() {
+            return null;
+        }
         @Override
         public Account getAccount() {
             return null;
         }
-
     };
 
-    public interface Callbacks {
-
-        public ISipService getService();
-
-        public Account getAccount();
-
+    public interface Callbacks extends LocalService.Callbacks {
+        Account getAccount();
     }
 
     @Override
@@ -104,7 +102,7 @@
 
         mCallbacks = (Callbacks) activity;
         try {
-            codecs = (ArrayList<Codec>) mCallbacks.getService().getAudioCodecList(mCallbacks.getAccount().getAccountID());
+            codecs = (ArrayList<Codec>) mCallbacks.getRemoteService().getAudioCodecList(mCallbacks.getAccount().getAccountID());
             //mCallbacks.getService().getRingtoneList();
         } catch (RemoteException e) {
             e.printStackTrace();
@@ -125,7 +123,7 @@
                 listAdapter.remove(item);
                 listAdapter.insert(item, to);
                 try {
-                    mCallbacks.getService().setActiveCodecList(getActiveCodecList(), mCallbacks.getAccount().getAccountID());
+                    mCallbacks.getRemoteService().setActiveCodecList(getActiveCodecList(), mCallbacks.getAccount().getAccountID());
                 } catch (RemoteException e) {
                     e.printStackTrace();
                 }
@@ -193,7 +191,7 @@
                 listAdapter.getItem(pos).toggleState();
                 listAdapter.notifyDataSetChanged();
                 try {
-                    mCallbacks.getService().setActiveCodecList(getActiveCodecList(), mCallbacks.getAccount().getAccountID());
+                    mCallbacks.getRemoteService().setActiveCodecList(getActiveCodecList(), mCallbacks.getAccount().getAccountID());
                 } catch (RemoteException e) {
                     e.printStackTrace();
                 }
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
index 24bd94f..1abbce9 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
@@ -33,59 +33,68 @@
 
 import android.app.Activity;
 import android.app.FragmentManager;
+import android.net.Uri;
+import android.support.design.widget.FloatingActionButton;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationManagerCompat;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.PointF;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.os.RemoteException;
-import android.util.FloatMath;
 import android.util.Log;
 import android.view.*;
-import android.view.SurfaceHolder.Callback;
 import android.view.View.OnClickListener;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.*;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 import cx.ring.R;
+import cx.ring.adapters.ContactPictureTask;
+import cx.ring.client.CallActivity;
+import cx.ring.client.ConversationActivity;
+import cx.ring.client.HomeActivity;
 import cx.ring.interfaces.CallInterface;
-import cx.ring.service.ISipService;
 
 import java.util.ArrayList;
 import java.util.Locale;
+import java.util.Random;
 
-import cx.ring.model.Attractor;
-import cx.ring.model.Bubble;
 import cx.ring.model.BubbleContact;
-import cx.ring.model.BubbleModel;
-import cx.ring.model.BubbleUser;
-import cx.ring.model.BubblesView;
 import cx.ring.model.CallContact;
 import cx.ring.model.Conference;
 import cx.ring.model.SecureSipCall;
 import cx.ring.model.SipCall;
+import cx.ring.model.account.Account;
+import cx.ring.service.LocalService;
+import cx.ring.service.SipService;
 
-public class CallFragment extends CallableWrapperFragment implements CallInterface, Callback {
+public class CallFragment extends CallableWrapperFragment implements CallInterface {
 
     static final String TAG = "CallFragment";
 
-
-
     private float bubbleSize = 75; // dip
     private float attractorSize = 40;
     public static final int REQUEST_TRANSFER = 10;
 
     // Screen wake lock for incoming call
     private WakeLock mScreenWakeLock;
+    private ImageView contactBubbleView;
+    private TextView contactBubbleTxt;
+    private View acceptButton;
+    private View refuseButton;
+    private View hangupButton;
 
+    private View securityIndicator;
+
+    /*
     private BubblesView mBubbleView;
     private BubbleModel mBubbleModel;
 
@@ -95,15 +104,15 @@
     private Bitmap buttonUnhold;
     private Bitmap buttonTransfer;
     private Bitmap buttonHangUp;
-
+*/
     private final int BTN_MSG_IDX = 0;
     private final int BTN_HOLD_IDX = 1;
     private final int BTN_TRANSFER_IDX = 2;
     private final int BTN_HUNGUP_IDX = 3;
-
+/*
     private BubbleModel.ActionGroup userActions;
     private BubbleModel.ActionGroup callActions;
-
+*/
     ViewSwitcher mSecuritySwitch;
     private TextView mCallStatusTxt;
     private ToggleButton mToggleSpeakers;
@@ -124,10 +133,11 @@
 
     @Override
     public void onCreate(Bundle savedBundle) {
+        Log.i(TAG, "onCreate");
         super.onCreate(savedBundle);
 
         Resources r = getResources();
-
+/*
         bubbleSize = r.getDimension(R.dimen.bubble_size);
         attractorSize = r.getDimension(R.dimen.bubble_action_size);
         float attractorMargin = r.getDimension(R.dimen.bubble_action_margin);
@@ -203,7 +213,6 @@
 
             @Override
             public boolean bubbleEjected(Bubble b) {
-                //if (b.isUser) {
                 try {
                     if (b.isConference())
                         mCallbacks.getService().hangUpConference(b.getCallID());
@@ -214,15 +223,13 @@
                     e.printStackTrace();
                 }
                 return true;
-                /*}
-                return false;*/
             }
-        });
+        });*/
 
         setHasOptionsMenu(true);
         PowerManager powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
         mScreenWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE,
-                "org.sflphone.onIncomingCall");
+                "cx.ring.onIncomingCall");
         mScreenWakeLock.setReferenceCounted(false);
 
         Log.d(TAG, "Acquire wake up lock");
@@ -240,65 +247,38 @@
     }
 
     /**
+     * The Activity calling this fragment has to implement this interface
+     */
+    public interface Callbacks extends LocalService.Callbacks {
+        void onFragmentCreated();
+        void startTimer();
+        void terminateCall();
+        Conference getDisplayedConference();
+        void updateDisplayedConference(Conference c);
+    }
+
+    /**
      * A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity.
      */
-    private static Callbacks sDummyCallbacks = new Callbacks() {
-
+    private static class DummyCallbacks extends LocalService.DummyCallbacks implements Callbacks {
         @Override
-        public void onFragmentCreated() {
-
-        }
-
+        public void onFragmentCreated() {}
         @Override
-        public ISipService getService() {
-            return null;
-        }
-
-        @Override
-        public void terminateCall() {
-        }
-
+        public void terminateCall() {}
         @Override
         public Conference getDisplayedConference() {
             return null;
         }
-
         @Override
-        public void updateDisplayedConference(Conference c) {
-        }
-
+        public void updateDisplayedConference(Conference c) { }
         @Override
-        public void startTimer() {
-        }
-
-        @Override
-        public void slideChatScreen() {
-        }
-
-    };
-
-    /**
-     * The Activity calling this fragment has to implement this interface
-     */
-    public interface Callbacks {
-
-        public void onFragmentCreated();
-
-        public ISipService getService();
-
-        public void startTimer();
-
-        public void slideChatScreen();
-
-        public void terminateCall();
-
-        public Conference getDisplayedConference();
-
-        public void updateDisplayedConference(Conference c);
+        public void startTimer() { }
     }
+    private static final Callbacks sDummyCallbacks = new DummyCallbacks();
 
     @Override
     public void onAttach(Activity activity) {
+        Log.i(TAG, "onAttach");
         super.onAttach(activity);
 
         if (!(activity instanceof Callbacks)) {
@@ -312,6 +292,30 @@
 
     }
 
+    public void refreshState() {
+        Conference conf = getConference();
+        if (conf == null)  {
+            contactBubbleView.setImageBitmap(null);
+            contactBubbleTxt.setText("");
+            acceptButton.setVisibility(View.GONE);
+            refuseButton.setVisibility(View.GONE);
+            hangupButton.setVisibility(View.GONE);
+        } else if (conf.getParticipants().size() == 1) {
+            SipCall call = conf.getParticipants().get(0);
+            if (call.isIncoming() && call.isRinging()) {
+                Log.w(TAG, "CallFragment refreshState INCOMING " + call.getCallId());
+                initIncomingCallDisplay();
+            } else if (conf.getParticipants().get(0).isRinging()) {
+                Log.w(TAG, "CallFragment refreshState RINGING " + call.getCallId());
+                initOutGoingCallDisplay();
+            } else if (call.isOngoing()) {
+                initNormalStateDisplay();
+            }
+        } else if (conf.getParticipants().size() > 1) {
+            initNormalStateDisplay();
+        }
+    }
+
     @Override
     public void onCreateOptionsMenu(Menu m, MenuInflater inf) {
         super.onCreateOptionsMenu(m, inf);
@@ -323,7 +327,15 @@
         super.onOptionsItemSelected(item);
         switch (item.getItemId()) {
             case R.id.menuitem_chat:
-                mCallbacks.slideChatScreen();
+                //mCallbacks.slideChatScreen();
+                Intent intent = new Intent()
+                        .setClass(getActivity(), ConversationActivity.class)
+                        .setAction(Intent.ACTION_VIEW)
+                        .setData(Uri.withAppendedPath(ConversationActivity.CONTENT_URI, getConference().getParticipants().get(0).getContact().getIds().get(0)));
+                intent.putExtra("resuming", true);
+                //intent.putExtra("contact", ((Conversation) v.getTag()).getContact());
+                //intent.putExtra("conversation", (Conversation) v.getTag());
+                startActivityForResult(intent, HomeActivity.REQUEST_CODE_CONVERSATION);
                 break;
         }
 
@@ -345,6 +357,7 @@
     public void onResume() {
         super.onResume();
         initializeWiFiListener();
+        refreshState();
     }
 
     @Override
@@ -358,7 +371,13 @@
 
     @Override
     public void callStateChanged(Conference updated, String callID, String newState) {
-        mCallbacks.updateDisplayedConference(updated);
+        Conference cur = getConference();
+        if (cur.getId().equals(callID) || cur.getCallById(callID) != null) {
+            mCallbacks.updateDisplayedConference(updated);
+        } else {
+            return;
+        }
+
         Log.i(TAG, "Call :" + callID + " " + newState);
 
         if (getConference().isOnGoing()) {
@@ -371,6 +390,8 @@
             } else
                 initOutGoingCallDisplay();
         } else {
+            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
+            notificationManager.cancel(getConference().notificationId);
             mCallStatusTxt.setText(newState);
             mCallbacks.terminateCall();
         }
@@ -420,7 +441,7 @@
                     transfer = data.getParcelableExtra("transfer");
                     try {
 
-                        mCallbacks.getService().attendedTransfer(transfer.getCallId(), c.getParticipants().get(0).getCallId());
+                        mCallbacks.getRemoteService().attendedTransfer(transfer.getCallId(), c.getParticipants().get(0).getCallId());
 
                     } catch (RemoteException e) {
                         e.printStackTrace();
@@ -431,17 +452,17 @@
                     String to = data.getStringExtra("to_number");
                     transfer = data.getParcelableExtra("transfer");
                     try {
-                        mCallbacks.getService().transfer(transfer.getCallId(), to);
-                        mCallbacks.getService().hangUp(transfer.getCallId());
+                        mCallbacks.getRemoteService().transfer(transfer.getCallId(), to);
+                        mCallbacks.getRemoteService().hangUp(transfer.getCallId());
                     } catch (RemoteException e) {
                         e.printStackTrace();
                     }
                     break;
                 case Activity.RESULT_CANCELED:
                 default:
-                    synchronized (mBubbleModel) {
+                    /*synchronized (mBubbleModel) {
                         mBubbleModel.clear();
-                    }
+                    }*/
                     initNormalStateDisplay();
                     break;
             }
@@ -453,10 +474,17 @@
         Log.i(TAG, "onCreateView");
         final ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.frag_call, container, false);
 
+/*
         mBubbleView = (BubblesView) rootView.findViewById(R.id.main_view);
         //mBubbleView.setFragment(this);
         mBubbleView.setModel(mBubbleModel);
         mBubbleView.getHolder().addCallback(this);
+*/
+        contactBubbleView = (ImageView) rootView.findViewById(R.id.contact_bubble);
+        contactBubbleTxt = (TextView) rootView.findViewById(R.id.contact_bubble_txt);
+        acceptButton  = rootView.findViewById(R.id.call_accept_btn);
+        refuseButton  = rootView.findViewById(R.id.call_refuse_btn);
+        hangupButton  = rootView.findViewById(R.id.call_hangup_btn);
 
         mCallStatusTxt = (TextView) rootView.findViewById(R.id.call_status_txt);
 
@@ -468,18 +496,18 @@
             @Override
             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                 try {
-                    mCallbacks.getService().toggleSpeakerPhone(isChecked);
+                    mCallbacks.getRemoteService().toggleSpeakerPhone(isChecked);
                 } catch (RemoteException e) {
                     e.printStackTrace();
                 }
 
             }
         });
-
+/*
         synchronized (mBubbleModel) {
             mBubbleModel.setSize(mBubbleView.getWidth(), mBubbleView.getHeight() - mToggleSpeakers.getHeight(), bubbleSize);
-        }
-
+        }*/
+/*
         rootView.findViewById(R.id.dialpad_btn).setOnClickListener(new OnClickListener() {
 
             @Override
@@ -487,7 +515,9 @@
                 InputMethodManager lManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                 lManager.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_IMPLICIT_ONLY);
             }
-        });
+        });*/
+
+        securityIndicator = rootView.findViewById(R.id.security_indicator);
 
         return rootView;
     }
@@ -498,7 +528,49 @@
 
     private void initNormalStateDisplay() {
         Log.i(TAG, "Start normal display");
-        synchronized (mBubbleModel) {
+        mCallbacks.startTimer();
+        acceptButton.setVisibility(View.GONE);
+        refuseButton.setVisibility(View.GONE);
+
+        final SipCall call = getConference().getParticipants().get(0);
+        CallContact contact = call.getContact();
+        //contactBubbleView.setImageBitmap(getContactPhoto(contact, contactBubbleView.getWidth()));
+        new ContactPictureTask(getActivity(), contactBubbleView, contact).run();
+        contactBubbleTxt.setText(contact.getDisplayName());
+
+        hangupButton.setVisibility(View.VISIBLE);
+        hangupButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    mCallbacks.getRemoteService().hangUp(call.getCallId());
+                    mCallbacks.terminateCall();
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+
+        NotificationCompat.Builder noti = new NotificationCompat.Builder(getActivity())
+                .setContentTitle("Current call with " + contact.getDisplayName())
+                .setOngoing(true)
+                .setSmallIcon(R.drawable.ic_launcher)
+                .setContentText("call")
+                .setContentIntent(PendingIntent.getActivity(getActivity(), new Random().nextInt(),
+                        new Intent(getActivity(), CallActivity.class).putExtra("conference", getConference()), PendingIntent.FLAG_ONE_SHOT))
+                .addAction(R.drawable.ic_call_end_white_24dp, "Hangup",
+                        PendingIntent.getService(getActivity(), new Random().nextInt(),
+                                new Intent(getActivity(), SipService.class)
+                                        .setAction(SipService.ACTION_CALL_END)
+                                        .putExtra("conf", call.getCallId()),
+                                PendingIntent.FLAG_ONE_SHOT));
+        Log.w("CallNotification ", "Updating " + getConference().notificationId + " for " + contact.getDisplayName());
+        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
+        notificationManager.notify(getConference().notificationId, noti.build());
+
+        getActivity().getActionBar().setTitle(contact.getDisplayName());
+
+        /*synchronized (mBubbleModel) {
             mCallbacks.startTimer();
             mBubbleModel.clearAttractors();
             PointF c = mBubbleModel.getCircleCenter();
@@ -513,19 +585,28 @@
                 if (partee == null) {
                     continue;
                 }
-                float dX = FloatMath.cos(angle_part * i + angle_shift) * radiusCalls;
-                float dY = FloatMath.sin(angle_part * i + angle_shift) * radiusCalls;
+                double dX = Math.cos(angle_part * i + angle_shift) * radiusCalls;
+                double dY = Math.sin(angle_part * i + angle_shift) * radiusCalls;
                 getBubbleFor(partee, (int) (c.x + dX), (int) (c.y + dY));
             }
         }
-        mBubbleModel.curState = BubbleModel.State.Incall;
+        mBubbleModel.curState = BubbleModel.State.Incall;*/
         updateSecurityDisplay();
     }
 
     private void updateSecurityDisplay() {
-
         //First we check if at least one participant use a security layer.
-        if (!getConference().useSecureLayer())
+        boolean secure_call = false;
+        for (SipCall c : getConference().getParticipants()) {
+            Account acc = mCallbacks.getService().getAccount(c.getAccount());
+            if (acc != null && (acc.isRing() || acc.useSecureLayer())) {
+                secure_call = true;
+                break;
+            }
+        }
+
+        securityIndicator.setVisibility(secure_call ? View.VISIBLE : View.GONE);
+        if (!secure_call)
             return;
 
         Log.i(TAG, "Enable security display");
@@ -550,7 +631,7 @@
                         @Override
                         public void onClick(View v) {
                             try {
-                                mCallbacks.getService().confirmSAS(secured.getCallId());
+                                mCallbacks.getRemoteService().confirmSAS(secured.getCallId());
                                 showLock(R.drawable.green_lock);
                             } catch (RemoteException e) {
                                 e.printStackTrace();
@@ -573,18 +654,86 @@
         mSecuritySwitch.setVisibility(View.VISIBLE);
     }
 
+    protected Bitmap getContactPhoto(CallContact contact, int size) {
+        if (contact.getPhotoId() > 0) {
+            return ContactPictureTask.loadContactPhoto(getActivity().getContentResolver(), contact.getId());
+        } else {
+            return ContactPictureTask.decodeSampledBitmapFromResource(getResources(), R.drawable.ic_contact_picture, size, size);
+        }
+    }
+
     private void initIncomingCallDisplay() {
         Log.i(TAG, "Start incoming display");
-        if (getConference().getParticipants().get(0).getAccount().isAutoanswerEnabled()) {
+        if (mCallbacks.getService().getAccount(getConference().getParticipants().get(0).getAccount()).isAutoanswerEnabled()) {
             try {
-                mCallbacks.getService().accept(getConference().getParticipants().get(0).getCallId());
+                mCallbacks.getRemoteService().accept(getConference().getParticipants().get(0).getCallId());
             } catch (RemoteException e) {
                 e.printStackTrace();
             } catch (NullPointerException e) {
                 e.printStackTrace();
             }
         } else {
-            getBubbleFor(getConference().getParticipants().get(0), mBubbleModel.getWidth() / 2, 2 * mBubbleModel.getHeight() / 3);
+            final SipCall call = getConference().getParticipants().get(0);
+            CallContact contact = call.getContact();
+            //contactBubbleView.setImageBitmap(getContactPhoto(contact, contactBubbleView.getWidth()));
+            new ContactPictureTask(getActivity(), contactBubbleView, contact).run();
+            contactBubbleTxt.setText(contact.getDisplayName());
+            acceptButton.setVisibility(View.VISIBLE);
+            acceptButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    acceptButton.setOnClickListener(null);
+                    refuseButton.setOnClickListener(null);
+                    try {
+                        mCallbacks.getRemoteService().accept(call.getCallId());
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                }
+            });
+            refuseButton.setVisibility(View.VISIBLE);
+            refuseButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    acceptButton.setOnClickListener(null);
+                    refuseButton.setOnClickListener(null);
+                    try {
+                        mCallbacks.getRemoteService().refuse(call.getCallId());
+                        mCallbacks.terminateCall();
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                }
+            });
+            hangupButton.setVisibility(View.GONE);
+
+            NotificationCompat.Builder noti = new NotificationCompat.Builder(getActivity())
+                    .setContentTitle("Incoming call with " + contact.getDisplayName())
+                    .setContentText("incoming call")
+                    .setOngoing(true)
+                    .setSmallIcon(R.drawable.ic_launcher)
+                    .setContentIntent(PendingIntent.getActivity(getActivity(), new Random().nextInt(),
+                            new Intent(getActivity(), CallActivity.class).putExtra("conference", getConference()), PendingIntent.FLAG_ONE_SHOT))
+                    .addAction(R.drawable.ic_action_accept, "Accept",
+                            PendingIntent.getService(getActivity(), new Random().nextInt(),
+                                    new Intent(getActivity(), SipService.class)
+                                            .setAction(SipService.ACTION_CALL_ACCEPT)
+                                            .putExtra("conf", call.getCallId()),
+                                    PendingIntent.FLAG_ONE_SHOT))
+                    .addAction(R.drawable.ic_call_end_white_24dp, "Refuse",
+                            PendingIntent.getService(getActivity(), new Random().nextInt(),
+                                    new Intent(getActivity(), SipService.class)
+                                            .setAction(SipService.ACTION_CALL_REFUSE)
+                                            .putExtra("conf", call.getCallId()),
+                                    PendingIntent.FLAG_ONE_SHOT));
+            Log.w("CallNotification ", "Updating for incoming " + getConference().notificationId);
+            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
+            notificationManager.notify(getConference().notificationId, noti.build());
+
+            getActivity().getActionBar().setTitle(contact.getDisplayName());
+
+
+            /*getBubbleFor(getConference().getParticipants().get(0), mBubbleModel.getWidth() / 2, 2 * mBubbleModel.getHeight() / 3);
             synchronized (mBubbleModel) {
                 mBubbleModel.clearAttractors();
                 mBubbleModel.addAttractor(new Attractor(new PointF(3 * mBubbleModel.getWidth() / 4, 2 * mBubbleModel.getHeight() / 3), attractorSize, new Attractor.Callback() {
@@ -616,13 +765,56 @@
                     }
                 }, buttonHangUp));
             }
-            mBubbleModel.curState = BubbleModel.State.Incoming;
+            mBubbleModel.curState = BubbleModel.State.Incoming;*/
         }
     }
 
     private void initOutGoingCallDisplay() {
         Log.i(TAG, "Start outgoing display");
-        synchronized (mBubbleModel) {
+
+        final SipCall call = getConference().getParticipants().get(0);
+        CallContact contact = call.getContact();
+        //contactBubbleView.setImageBitmap(getContactPhoto(contact, contactBubbleView.getWidth()));
+        new ContactPictureTask(getActivity(), contactBubbleView, contact).run();
+        contactBubbleTxt.setText(contact.getDisplayName());
+
+        acceptButton.setVisibility(View.GONE);
+        refuseButton.setVisibility(View.GONE);
+
+        hangupButton.setVisibility(View.VISIBLE);
+        hangupButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    mCallbacks.getRemoteService().hangUp(call.getCallId());
+                    mCallbacks.terminateCall();
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+
+        NotificationCompat.Builder noti = new NotificationCompat.Builder(getActivity())
+                .setContentTitle("Outgoing call with " + contact.getDisplayName())
+                .setOngoing(true)
+                .setSmallIcon(R.drawable.ic_launcher)
+                .setContentText("Outgoing call")
+                .setContentIntent(PendingIntent.getActivity(getActivity(), new Random().nextInt(),
+                        new Intent(getActivity(), CallActivity.class).putExtra("conference", getConference()), PendingIntent.FLAG_ONE_SHOT))
+                .addAction(R.drawable.ic_call_end_white_24dp, "Cancel",
+                        PendingIntent.getService(getActivity(), new Random().nextInt(),
+                                new Intent(getActivity(), SipService.class)
+                                        .setAction(SipService.ACTION_CALL_END)
+                                        .putExtra("conf", call.getCallId()),
+                                PendingIntent.FLAG_ONE_SHOT));
+
+        Log.w("CallNotification ", "Updating for outgoing " + getConference().notificationId);
+        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
+        notificationManager.notify(getConference().notificationId, noti.build());
+
+        getActivity().getActionBar().setTitle(contact.getDisplayName());
+
+        /*synchronized (mBubbleModel) {
             PointF c = mBubbleModel.getCircleCenter();
             float radiusCalls = mBubbleModel.getCircleSize();
             getBubbleForUser(getConference(), c.x, c.y);
@@ -634,18 +826,18 @@
             }
             mBubbleModel.clearAttractors();
         }
-        mBubbleModel.curState = BubbleModel.State.Outgoing;
+        mBubbleModel.curState = BubbleModel.State.Outgoing;*/
     }
-
-    /**
-     * Retrieves or create a bubble for a given contact. If the bubble exists, it is moved to the new location.
-     *
-     * @param call The call associated to a contact
-     * @param x    Initial or new x position.
-     * @param y    Initial or new y position.
-     * @return Bubble corresponding to the contact.
-     */
-    private Bubble getBubbleFor(SipCall call, float x, float y) {
+    /*
+        /**
+         * Retrieves or create a bubble for a given contact. If the bubble exists, it is moved to the new location.
+         *
+         * @param call The call associated to a contact
+         * @param x    Initial or new x position.
+         * @param y    Initial or new y position.
+         * @return Bubble corresponding to the contact.
+         */
+   /*  private Bubble getBubbleFor(SipCall call, float x, float y) {
         Bubble contact_bubble = mBubbleModel.getBubble(call.getCallId());
         if (contact_bubble != null) {
             ((BubbleContact) contact_bubble).setCall(call);
@@ -670,31 +862,41 @@
 
         contact_bubble = new BubbleUser(getActivity(), CallContact.ContactBuilder.buildUserContact(getActivity().getContentResolver()), conf, x, y,
                 bubbleSize * 1.3f);
-/*
-        try {
-            ((BubbleUser) contact_bubble).setMute(mCallbacks.getService().isCaptureMuted());
-        } catch (RemoteException e) {
-            e.printStackTrace();
-        } catch (NullPointerException e1) {
-            e1.printStackTrace();
-        }*/
         mBubbleModel.addBubble(contact_bubble);
         return contact_bubble;
     }
 
+
     public boolean canOpenIMPanel() {
         return mBubbleModel.curState == BubbleModel.State.Incall && (mBubbleView == null || !mBubbleView.isDraggingBubble());
     }
 
+
     @Override
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
         synchronized (mBubbleModel) {
             mBubbleModel.setSize(width, height, bubbleSize);
         }
+        Log.w(TAG, "CallFragment surfaceChanged " + getConference().getParticipants().size());
         if (getConference().getParticipants().size() == 1) {
             if (getConference().getParticipants().get(0).isIncoming() && getConference().getParticipants().get(0).isRinging()) {
+                Log.w(TAG, "CallFragment surfaceChanged INCOMING" + getConference().getParticipants().get(0).getCallId());
                 initIncomingCallDisplay();
             } else if (getConference().getParticipants().get(0).isRinging()) {
+                Log.w(TAG, "CallFragment surfaceChanged RINGING" + getConference().getParticipants().get(0).getCallId());
+                initOutGoingCallDisplay();
+            } else if (getConference().getParticipants().get(0).isOngoing()) {
+                initNormalStateDisplay();
+            }
+        } else if (getConference().getParticipants().size() > 1) {
+            initNormalStateDisplay();
+        }
+        if (getConference().getParticipants().size() == 1) {
+            if (getConference().getParticipants().get(0).isIncoming() && getConference().getParticipants().get(0).isRinging()) {
+                Log.w(TAG, "CallFragment surfaceChanged INCOMING" + getConference().getParticipants().get(0).getCallId());
+                initIncomingCallDisplay();
+            } else if (getConference().getParticipants().get(0).isRinging()) {
+                Log.w(TAG, "CallFragment surfaceChanged RINGING" + getConference().getParticipants().get(0).getCallId());
                 initOutGoingCallDisplay();
             } else if (getConference().getParticipants().get(0).isOngoing()) {
                 initNormalStateDisplay();
@@ -703,13 +905,13 @@
             initNormalStateDisplay();
         }
     }
-
+*/
     public void makeTransfer(BubbleContact contact) {
         FragmentManager fm = getFragmentManager();
         editName = TransferDFragment.newInstance();
         Bundle b = new Bundle();
         try {
-            b.putParcelableArrayList("calls", (ArrayList<Conference>) mCallbacks.getService().getConcurrentCalls());
+            b.putParcelableArrayList("calls", (ArrayList<Conference>) mCallbacks.getRemoteService().getConcurrentCalls());
             b.putParcelable("call_selected", contact.associated_call);
             editName.setArguments(b);
             editName.setTargetFragment(this, REQUEST_TRANSFER);
@@ -719,7 +921,7 @@
         }
 
     }
-
+/*
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
 
@@ -738,10 +940,10 @@
     public BubblesView getBubbleView() {
         return mBubbleView;
     }
-
+*/
     public void updateTime() {
         if (getConference() != null) {
-            long duration = System.currentTimeMillis() - getConference().getParticipants().get(0).getTimestampStart_();
+            long duration = System.currentTimeMillis() - getConference().getParticipants().get(0).getTimestampStart();
             duration = duration / 1000;
             if (getConference().isOnGoing())
                 mCallStatusTxt.setText(String.format("%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60));
@@ -760,7 +962,7 @@
                     String toSend = Character.toString(event.getDisplayLabel());
                     toSend = toSend.toUpperCase(Locale.getDefault());
                     Log.d(TAG, "toSend " + toSend);
-                    mCallbacks.getService().playDtmf(toSend);
+                    mCallbacks.getRemoteService().playDtmf(toSend);
                     break;
             }
         } catch (RemoteException e) {
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallListFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallListFragment.java
index 997085e..36a19db 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/CallListFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/CallListFragment.java
@@ -31,60 +31,124 @@
 package cx.ring.fragments;
 
 import android.app.Activity;
+import android.app.Fragment;
+import android.content.BroadcastReceiver;
 import android.content.ClipData;
 import android.content.ClipData.Item;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.net.Uri;
 import android.os.*;
+import android.support.design.widget.FloatingActionButton;
 import android.util.Log;
+import android.util.LruCache;
 import android.view.DragEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.DragShadowBuilder;
 import android.view.View.OnDragListener;
 import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
 import android.widget.*;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemLongClickListener;
 
-import cx.ring.client.CallActivity;
+import cx.ring.R;
+import cx.ring.adapters.ContactPictureTask;
+import cx.ring.client.ConversationActivity;
 import cx.ring.client.HomeActivity;
+import cx.ring.client.NewConversationActivity;
 import cx.ring.model.Conference;
-import cx.ring.service.ISipService;
+import cx.ring.model.Conversation;
+import cx.ring.service.LocalService;
 
+import java.lang.ref.WeakReference;
+import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
-import java.util.Observable;
-import java.util.Observer;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
-public class CallListFragment extends CallableWrapperFragment {
+public class CallListFragment extends Fragment {
 
     private static final String TAG = CallListFragment.class.getSimpleName();
 
-    private Callbacks mCallbacks = sDummyCallbacks;
-    private TextView mConversationsTitleTextView;
-    CallListAdapter mConferenceAdapter;
+    private LocalService.Callbacks mCallbacks = LocalService.DUMMY_CALLBACKS;
+    //private TextView mConversationsTitleTextView;
+    private CallListAdapter mConferenceAdapter;
+    private FloatingActionButton newconv_btn = null;
+
+    @Override
+    public void onStart() {
+        Log.i(TAG, "onStart");
+        super.onStart();
+        // Bind to LocalService
+        /*Intent intent = new Intent(getActivity(), LocalService.class);
+        getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);*/
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(LocalService.ACTION_CONF_UPDATE);
+        getActivity().registerReceiver(receiver, intentFilter);
+        updateLists();
+    }
+
+    @Override
+    public void onStop() {
+        Log.i(TAG, "onStop");
+        super.onStop();
+        // Unbind from the service
+        /*if (mBound) {
+            getActivity().unbindService(mConnection);
+            mBound = false;
+        }*/
+        getActivity().unregisterReceiver(receiver);
+    }
+
+    final BroadcastReceiver receiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.w(TAG, "onReceive " + intent.getAction() + " " + intent.getDataString());
+            updateLists();
+        }
+    };
+/*
+    private ServiceConnection mConnection = new ServiceConnection() {
+
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            Log.w(TAG, "onServiceConnected " + className.getClassName());
+            // We've bound to LocalService, cast the IBinder and get LocalService instance
+            LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
+            mService = binder.getService();
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(LocalService.ACTION_CONF_UPDATE);
+
+            getActivity().registerReceiver(receiver, intentFilter);
+            mBound = true;
+
+            updateLists();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName arg0) {
+            Log.w(TAG, "onServiceDisconnected " + arg0.getClassName());
+            getActivity().unregisterReceiver(receiver);
+            mBound = false;
+        }
+    };
+*/
 
     public static final int REQUEST_TRANSFER = 10;
     public static final int REQUEST_CONF = 20;
 
-    /**
-     * A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity.
-     */
-    private static Callbacks sDummyCallbacks = new Callbacks() {
-
-        @Override
-        public ISipService getService() {
-            Log.i(TAG, "I'm a dummy");
-            return null;
-        }
-
-    };
-
+    /*
     @Override
-    public void callStateChanged(Conference c, String callID, String state) {
-        Log.i(TAG, "callStateChanged" + callID + "    " + state);
+    public void callStateChanged(Conference c, String callID, String State) {
+        Log.i(TAG, "callStateChanged " + callID + "    " + State);
         updateLists();
     }
 
@@ -101,7 +165,7 @@
     }
 
     @Override
-    public void confChanged(Conference c, String id, String state) {
+    public void confChanged(Conference c, String id, String State) {
         Log.i(TAG, "confChanged");
         updateLists();
     }
@@ -111,26 +175,29 @@
         Log.i(TAG, "confChanged");
         updateLists();
     }
-
-    /**
-     * The Activity calling this fragment has to implement this interface
-     */
-    public interface Callbacks {
-        public ISipService getService();
-    }
+*/
 
     @Override
     public void onAttach(Activity activity) {
+        Log.i(TAG, "onAttach");
         super.onAttach(activity);
 
-        if (!(activity instanceof Callbacks)) {
+        if (!(activity instanceof LocalService.Callbacks)) {
             throw new IllegalStateException("Activity must implement fragment's callbacks.");
         }
 
-        mCallbacks = (Callbacks) activity;
-
+        mCallbacks = (LocalService.Callbacks) activity;
+        if (mCallbacks.getService() != null) {
+            /*mConvList = new ConversationList(getActivity(), mCallbacks.getService());
+            if (mConferenceAdapter != null) {
+                Log.i(TAG, "mConvList.addObserver");
+                mConferenceAdapter.updateDataset(mConvList.getConversations());
+                mConvList.addObserver(mConferenceAdapter);
+            }*/
+        }
     }
 
+    /*
     private Runnable mUpdateTimeTask = new Runnable() {
         public void run() {
             final long start = SystemClock.uptimeMillis();
@@ -142,52 +209,51 @@
             mConferenceAdapter.notifyDataSetChanged();
             mHandler.postAtTime(this, start + (((minutes * 60) + seconds + 1) * 1000));
         }
-    };
+    };*/
 
-    private Handler mHandler = new Handler();
+    //private Handler mHandler = new Handler();
 
+    /*9
     @Override
     public void onResume() {
         super.onResume();
         if (mCallbacks.getService() != null) {
+            if (mConvList != null)
+                mConvList.startListener();
 
             updateLists();
-            if (!mConferenceAdapter.isEmpty()) {
-                mHandler.postDelayed(mUpdateTimeTask, 0);
-            }
         }
 
     }
-
-    @SuppressWarnings("unchecked")
-    // No proper solution with HashMap runtime cast
+*/
     public void updateLists() {
-        try {
-            HashMap<String, Conference> confs = (HashMap<String, Conference>) mCallbacks.getService().getConferenceList();
-            String newTitle = getResources().getQuantityString(cx.ring.R.plurals.home_conferences_title, confs.size(), confs.size());
-            mConversationsTitleTextView.setText(newTitle);
-            mConferenceAdapter.updateDataset(new ArrayList<Conference>(confs.values()));
-        } catch (RemoteException e) {
-            e.printStackTrace();
-        }
+        if (mCallbacks.getService() != null)
+            mConferenceAdapter.updateDataset(mCallbacks.getService().getConversations());
     }
 
     @Override
     public void onDetach() {
+        Log.i(TAG, "onDetach");
         super.onDetach();
-        mCallbacks = sDummyCallbacks;
-
+        mCallbacks = LocalService.DUMMY_CALLBACKS;
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
     }
 
     @Override
     public void onPause() {
         super.onPause();
-        mHandler.removeCallbacks(mUpdateTimeTask);
+        //mHandler.removeCallbacks(mUpdateTimeTask);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        ((HomeActivity)getActivity()).setToolbarState(false, R.string.app_name);
     }
 
     @Override
@@ -200,24 +266,51 @@
         Log.i(TAG, "onCreateView");
         View inflatedView = inflater.inflate(cx.ring.R.layout.frag_call_list, container, false);
 
-        mConversationsTitleTextView = (TextView) inflatedView.findViewById(cx.ring.R.id.confs_counter);
+        newconv_btn = (FloatingActionButton) inflatedView.findViewById(R.id.newconv_fab);
+        newconv_btn.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                startActivity(new Intent().setClass(getActivity(), NewConversationActivity.class));
+            }
+        });
 
+        //mConversationsTitleTextView = (TextView) inflatedView.findViewById(cx.ring.R.id.confs_counter);
+/*
+        if (mConferenceAdapter != null && mConvList != null)
+            mConvList.deleteObserver(mConferenceAdapter);*/
         mConferenceAdapter = new CallListAdapter(getActivity());
-        ((ListView) inflatedView.findViewById(cx.ring.R.id.confs_list)).setAdapter(mConferenceAdapter);
-        ((ListView) inflatedView.findViewById(cx.ring.R.id.confs_list)).setOnItemClickListener(callClickListener);
-        ((ListView) inflatedView.findViewById(cx.ring.R.id.confs_list)).setOnItemLongClickListener(mItemLongClickListener);
+        /*if (mConvList != null) {
+            Log.i(TAG, "mConvList.addObserver");
+            mConferenceAdapter.updateDataset(mConvList.getConversations());
+            mConvList.addObserver(mConferenceAdapter);
+        }*/
+        /*if (mBound) {
+            mConferenceAdapter.updateDataset(mService.getConversations());
+        }*/
+        LocalService service = mCallbacks.getService();
+        if (service != null)
+            mConferenceAdapter.updateDataset(mCallbacks.getService().getConversations());
+
+        ListView list = (ListView) inflatedView.findViewById(cx.ring.R.id.confs_list);
+        list.setAdapter(mConferenceAdapter);
+        list.setOnItemClickListener(callClickListener);
+        list.setOnItemLongClickListener(mItemLongClickListener);
 
         return inflatedView;
     }
 
-    OnItemClickListener callClickListener = new OnItemClickListener() {
+    private final OnItemClickListener callClickListener = new OnItemClickListener() {
 
         @Override
         public void onItemClick(AdapterView<?> arg0, View v, int arg2, long arg3) {
-            Intent intent = new Intent().setClass(getActivity(), CallActivity.class);
+            Intent intent = new Intent()
+                    .setClass(getActivity(), ConversationActivity.class)
+                    .setAction(Intent.ACTION_VIEW)
+                    .setData(Uri.withAppendedPath(ConversationActivity.CONTENT_URI, ((CallListAdapter.ViewHolder) v.getTag()).conv.getContact().getIds().get(0)));
             intent.putExtra("resuming", true);
-            intent.putExtra("conference", (Conference) v.getTag());
-            startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL);
+            //intent.putExtra("contact", ((Conversation) v.getTag()).getContact());
+            //intent.putExtra("conversation", (Conversation) v.getTag());
+            startActivityForResult(intent, HomeActivity.REQUEST_CODE_CONVERSATION);
         }
     };
 
@@ -229,7 +322,8 @@
             vibe.vibrate(80);
             Intent i = new Intent();
             Bundle b = new Bundle();
-            b.putParcelable("conference", (Conference) adptv.getAdapter().getItem(pos));
+            //b.putParcelable("conference", (Conference) adptv.getAdapter().getItem(pos));
+            b.putParcelable("contact", ((Conversation) adptv.getAdapter().getItem(pos)).getContact());
             i.putExtra("bconference", b);
 
             DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
@@ -240,20 +334,32 @@
 
     };
 
-    public class CallListAdapter extends BaseAdapter implements Observer {
-
-        private ArrayList<Conference> calls;
+    public class CallListAdapter extends BaseAdapter /*implements Observer*/ {
+        final private ArrayList<Conversation> calls = new ArrayList<>();
+        final private ExecutorService infos_fetcher = Executors.newCachedThreadPool();
+        final private LruCache<Long, Bitmap> mMemoryCache;
+        final private HashMap<Long, WeakReference<ContactPictureTask>> running_tasks = new HashMap<>();
 
         private Context mContext;
 
         public CallListAdapter(Context act) {
             super();
             mContext = act;
-            calls = new ArrayList<Conference>();
-
+            final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
+            final int cacheSize = maxMemory / 8;
+            Log.i(TAG, "CallListAdapter created " + cacheSize);
+            mMemoryCache = new LruCache<Long, Bitmap>(cacheSize){
+                @Override
+                protected int sizeOf(Long key, Bitmap bitmap) {
+                    return bitmap.getByteCount() / 1024;
+                }
+            };
         }
 
-        public void updateDataset(ArrayList<Conference> list) {
+        public void updateDataset(Collection<Conversation> list) {
+            Log.i(TAG, "updateDataset " + list.size());
+            if (list.size() == 0 && calls.size() == 0)
+                return;
             calls.clear();
             calls.addAll(list);
             notifyDataSetChanged();
@@ -265,7 +371,7 @@
         }
 
         @Override
-        public Conference getItem(int position) {
+        public Conversation getItem(int position) {
             return calls.get(position);
         }
 
@@ -274,38 +380,82 @@
             return 0;
         }
 
+        private class ViewHolder {
+            TextView conv_title;
+            TextView conv_status;
+            ImageView photo;
+            int position;
+            Conversation conv;
+        }
+
         @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
+        public View getView(final int position, View convertView, ViewGroup parent) {
             if (convertView == null)
                 convertView = LayoutInflater.from(mContext).inflate(cx.ring.R.layout.item_calllist, null);
 
-            Conference call = calls.get(position);
-            if (call.getParticipants().size() == 1) {
-                ((TextView) convertView.findViewById(cx.ring.R.id.call_title)).setText(call.getParticipants().get(0).getmContact().getmDisplayName());
-
-                long duration = (System.currentTimeMillis() - (call.getParticipants().get(0).getTimestampStart_())) / 1000;
-
-                ((TextView) convertView.findViewById(cx.ring.R.id.call_time)).setText(String.format("%d:%02d:%02d", duration / 3600, (duration % 3600) / 60,
-                        (duration % 60)));
-            } else {
-//                String tmp = "Conference with " + call.getParticipants().size() + " participants";
-                ((TextView) convertView.findViewById(cx.ring.R.id.call_title)).setText(getString(cx.ring.R.string.home_conf_item, call.getParticipants().size()));
+            ViewHolder holder = (ViewHolder) convertView.getTag();
+            if (holder == null) {
+                holder = new ViewHolder();
+                holder.photo = (ImageView) convertView.findViewById(R.id.photo);
+                holder.conv_title = (TextView) convertView.findViewById(cx.ring.R.id.msg_txt);
+                holder.conv_status = (TextView) convertView.findViewById(cx.ring.R.id.call_status);
+                holder.position = -1;
+                convertView.setTag(holder);
             }
-            // ((TextView) convertView.findViewById(R.id.num_participants)).setText("" + call.getParticipants().size());
-            ((TextView) convertView.findViewById(cx.ring.R.id.call_status)).setText(call.getState());
+            final ViewHolder h = holder;
+            if (h.position == position && h.conv != null && h.conv == calls.get(position)) {
+                return convertView;
+            }
+            h.conv = calls.get(position);
+            h.position = position;
+            h.conv_title.setText(h.conv.getContact().getDisplayName());
+            h.conv_status.setText(DateFormat.getDateTimeInstance().format(h.conv.getLastInteraction()));
 
+            final Long cid = h.conv.getContact().getId();
+            Bitmap bmp = mMemoryCache.get(cid);
+            if (bmp != null) {
+                h.photo.setImageBitmap(bmp);
+            } else {
+                holder.photo.setImageBitmap(mMemoryCache.get(-1l));
+                final WeakReference<ViewHolder> wh = new WeakReference<>(holder);
+                final ContactPictureTask.PictureLoadedCallback cb = new ContactPictureTask.PictureLoadedCallback() {
+                    @Override
+                    public void onPictureLoaded(final Bitmap bmp) {
+                        final ViewHolder fh = wh.get();
+                        if (fh == null || fh.photo.getParent() == null)
+                            return;
+                        //if (fh.position == position) {
+                        if (fh.conv.getContact().getId() == cid) {
+                            fh.photo.post(new Runnable() {
+                                @Override
+                                public void run() {
+                                    fh.photo.setImageBitmap(bmp);
+                                    fh.photo.startAnimation(AnimationUtils.loadAnimation(fh.photo.getContext(), R.anim.contact_fadein));
+                                }
+                            });
+                        }
+                    }
+                };
+                WeakReference<ContactPictureTask> wtask = running_tasks.get(cid);
+                ContactPictureTask task = wtask == null ? null : wtask.get();
+                if (task != null) {
+                    task.addCallback(cb);
+                } else {
+                    task = new ContactPictureTask(mContext, h.photo, h.conv.getContact(), new ContactPictureTask.PictureLoadedCallback() {
+                        @Override
+                        public void onPictureLoaded(Bitmap bmp) {
+                            mMemoryCache.put(cid, bmp);
+                            running_tasks.remove(cid);
+                        }
+                    });
+                    task.addCallback(cb);
+                    running_tasks.put(cid, new WeakReference<>(task));
+                    infos_fetcher.execute(task);
+                }
+            }
             convertView.setOnDragListener(dragListener);
-            convertView.setTag(call);
-
             return convertView;
         }
-
-        @Override
-        public void update(Observable observable, Object data) {
-            Log.i(TAG, "Updating views...");
-            notifyDataSetChanged();
-        }
-
     }
 
     OnDragListener dragListener = new OnDragListener() {
@@ -335,8 +485,8 @@
                     Intent intent = i.getIntent();
                     intent.setExtrasClassLoader(Conference.class.getClassLoader());
 
-                    Conference initial = (Conference) view.getTag();
-                    Conference target = (Conference) v.getTag();
+                    Conversation initial = ((CallListAdapter.ViewHolder) view.getTag()).conv;
+                    Conversation target = ((CallListAdapter.ViewHolder) v.getTag()).conv;
 
                     if (initial == target) {
                         return true;
@@ -344,8 +494,8 @@
 
                     DropActionsChoice dialog = DropActionsChoice.newInstance();
                     Bundle b = new Bundle();
-                    b.putParcelable("call_initial", initial);
-                    b.putParcelable("call_targeted", target);
+                    b.putParcelable("call_initial", initial.getCurrentCall());
+                    b.putParcelable("call_targeted", target.getCurrentCall());
                     dialog.setArguments(b);
                     dialog.setTargetFragment(CallListFragment.this, 0);
                     dialog.show(getFragmentManager(), "dialog");
@@ -376,7 +526,7 @@
                     Conference c = data.getParcelableExtra("target");
                     transfer = data.getParcelableExtra("transfer");
                     try {
-                        mCallbacks.getService().attendedTransfer(transfer.getParticipants().get(0).getCallId(), c.getParticipants().get(0).getCallId());
+                        mCallbacks.getService().getRemoteService().attendedTransfer(transfer.getParticipants().get(0).getCallId(), c.getParticipants().get(0).getCallId());
                         mConferenceAdapter.notifyDataSetChanged();
                     } catch (RemoteException e) {
                         // TODO Auto-generated catch block
@@ -389,10 +539,10 @@
                     String to = data.getStringExtra("to_number");
                     transfer = data.getParcelableExtra("transfer");
                     try {
-                        Toast.makeText(getActivity(), getString(cx.ring.R.string.home_transfering, transfer.getParticipants().get(0).getmContact().getmDisplayName(), to),
+                        Toast.makeText(getActivity(), getString(cx.ring.R.string.home_transfering, transfer.getParticipants().get(0).getContact().getDisplayName(), to),
                                 Toast.LENGTH_SHORT).show();
-                        mCallbacks.getService().transfer(transfer.getParticipants().get(0).getCallId(), to);
-                        mCallbacks.getService().hangUp(transfer.getParticipants().get(0).getCallId());
+                        mCallbacks.getService().getRemoteService().transfer(transfer.getParticipants().get(0).getCallId(), to);
+                        mCallbacks.getService().getRemoteService().hangUp(transfer.getParticipants().get(0).getCallId());
                     } catch (RemoteException e) {
                         // TODO Auto-generated catch block
                         e.printStackTrace();
@@ -424,20 +574,20 @@
 
             if (call_target.hasMultipleParticipants() && !call_to_add.hasMultipleParticipants()) {
 
-                mCallbacks.getService().addParticipant(call_to_add.getParticipants().get(0), call_target.getId());
+                mCallbacks.getService().getRemoteService().addParticipant(call_to_add.getParticipants().get(0), call_target.getId());
 
             } else if (call_target.hasMultipleParticipants() && call_to_add.hasMultipleParticipants()) {
 
                 // We join two conferences
-                mCallbacks.getService().joinConference(call_to_add.getId(), call_target.getId());
+                mCallbacks.getService().getRemoteService().joinConference(call_to_add.getId(), call_target.getId());
 
             } else if (!call_target.hasMultipleParticipants() && call_to_add.hasMultipleParticipants()) {
 
-                mCallbacks.getService().addParticipant(call_target.getParticipants().get(0), call_to_add.getId());
+                mCallbacks.getService().getRemoteService().addParticipant(call_target.getParticipants().get(0), call_to_add.getId());
 
             } else {
                 // We join two single calls to create a conf
-                mCallbacks.getService().joinParticipant(call_to_add.getParticipants().get(0).getCallId(),
+                mCallbacks.getService().getRemoteService().joinParticipant(call_to_add.getParticipants().get(0).getCallId(),
                         call_target.getParticipants().get(0).getCallId());
             }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallableWrapperFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallableWrapperFragment.java
index eb0a632..3ea8dca 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/CallableWrapperFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/CallableWrapperFragment.java
@@ -46,19 +46,11 @@
 
 public abstract class CallableWrapperFragment extends Fragment implements CallInterface {
 
-
-    private CallReceiver mReceiver;
-
+    private final CallReceiver mReceiver = new CallReceiver();
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mReceiver = new CallReceiver();
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(CallManagerCallBack.INCOMING_CALL);
         intentFilter.addAction(CallManagerCallBack.INCOMING_TEXT);
@@ -76,10 +68,9 @@
         getActivity().registerReceiver(mReceiver, intentFilter);
     }
 
-
     @Override
-    public void onPause() {
-        super.onPause();
+    public void onDestroy() {
+        super.onDestroy();
         getActivity().unregisterReceiver(mReceiver);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ConferenceDFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/ConferenceDFragment.java
index 7bfbafa..1e70751 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/ConferenceDFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/ConferenceDFragment.java
@@ -26,7 +26,7 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
-public class ConferenceDFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<Bundle> {
+public class ConferenceDFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<ContactsLoader.Result> {
 
 
     SimpleCallListAdapter mAdapter;
@@ -75,7 +75,7 @@
 
         
 
-        final AlertDialog a = new AlertDialog.Builder(getActivity()).setView(rootView).setTitle("Transfer " + call_selected.getParticipants().get(0).getmContact())
+        final AlertDialog a = new AlertDialog.Builder(getActivity()).setView(rootView).setTitle("Transfer " + call_selected.getParticipants().get(0).getContact())
                 .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog, int whichButton) {
 
@@ -87,7 +87,7 @@
     }
 
     @Override
-    public Loader<Bundle> onCreateLoader(int id, Bundle args) {
+    public Loader<ContactsLoader.Result> onCreateLoader(int id, Bundle args) {
         Uri baseUri;
 
         if (args != null) {
@@ -101,14 +101,14 @@
     }
 
     @Override
-    public void onLoadFinished(Loader<Bundle> loader, Bundle data) {
+    public void onLoadFinished(Loader<ContactsLoader.Result> loader, ContactsLoader.Result data) {
 
 //        ArrayList<CallContact> tmp = data.getParcelableArrayList("Contacts");
 
     }
 
     @Override
-    public void onLoaderReset(Loader<Bundle> loader) {
+    public void onLoaderReset(Loader<ContactsLoader.Result> loader) {
         // Thi is called when the last Cursor provided to onLoadFinished
         // mListAdapter.swapCursor(null);
     }
@@ -136,7 +136,7 @@
             }
 
             if(calls.get(position).getParticipants().size() == 1){
-                tv.setText(calls.get(position).getParticipants().get(0).getmContact().getmDisplayName());
+                tv.setText(calls.get(position).getParticipants().get(0).getContact().getDisplayName());
             } else {
                 tv.setText("Conference with "+ calls.get(position).getParticipants().size() + " participants");
             }
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ContactListFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/ContactListFragment.java
index 9640452..d3ff53a 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/ContactListFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/ContactListFragment.java
@@ -39,9 +39,7 @@
 import cx.ring.loaders.ContactsLoader;
 import cx.ring.loaders.LoaderConstants;
 import cx.ring.model.CallContact;
-import cx.ring.service.ISipService;
-import cx.ring.views.SwipeListViewTouchListener;
-import cx.ring.views.stickylistheaders.StickyListHeadersListView;
+import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -51,14 +49,13 @@
 import android.os.Bundle;
 import android.provider.ContactsContract.Contacts;
 import android.util.Log;
-import android.view.DragEvent;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.DragShadowBuilder;
 import android.view.View.MeasureSpec;
-import android.view.View.OnClickListener;
-import android.view.View.OnDragListener;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
@@ -67,66 +64,58 @@
 import android.widget.GridView;
 import android.widget.LinearLayout;
 import android.widget.ListAdapter;
-import android.widget.ListView;
 import android.widget.RelativeLayout;
 import android.widget.SearchView;
 import android.widget.SearchView.OnQueryTextListener;
+import android.widget.TextView;
 
-public class ContactListFragment extends Fragment implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Bundle> {
-    private static final String TAG = "ContactListFragment";
+public class ContactListFragment extends Fragment implements OnQueryTextListener, LoaderManager.LoaderCallbacks<ContactsLoader.Result> {
+    public static final String TAG = "ContactListFragment";
     ContactsAdapter mListAdapter;
     StarredContactsAdapter mGridAdapter;
-    SearchView mQuickReturnSearchView;
+    //SearchView mQuickReturnSearchView;
     String mCurFilter;
     StickyListHeadersListView mContactList;
+
+    // favorite contacts
+    private LinearLayout llMain;
     private GridView mStarredGrid;
-    private SwipeListViewTouchListener mSwipeLvTouchListener;
+    private TextView favHeadLabel;
+    //private SwipeListViewTouchListener mSwipeLvTouchListener;
     private LinearLayout mHeader;
+    private ViewGroup newcontact;
 
     @Override
     public void onCreate(Bundle savedInBundle) {
         super.onCreate(savedInBundle);
         mGridAdapter = new StarredContactsAdapter(getActivity());
         mListAdapter = new ContactsAdapter(this);
+        setHasOptionsMenu(true);
     }
 
     public Callbacks mCallbacks = sDummyCallbacks;
-    private LinearLayout llMain;
     /**
      * A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity.
      */
-    private static Callbacks sDummyCallbacks = new Callbacks() {
+    private static final Callbacks sDummyCallbacks = new Callbacks() {
         @Override
         public void onCallContact(CallContact c) {
         }
-
         @Override
         public void onTextContact(CallContact c) {
         }
-
         @Override
         public void onEditContact(CallContact c) {
         }
-
-        @Override
-        public ISipService getService() {
-            Log.i(TAG, "Dummy");
-            return null;
-        }
-
         @Override
         public void onContactDragged() {
         }
-
         @Override
         public void toggleDrawer() {
         }
-
         @Override
         public void setDragView(RelativeLayout relativeLayout) {
-            
         }
-
         @Override
         public void toggleForSearchDrawer() {
         }
@@ -134,21 +123,12 @@
 
     public interface Callbacks {
         void onCallContact(CallContact c);
-
         void onTextContact(CallContact c);
-
-        public ISipService getService();
-
         void onContactDragged();
-
         void toggleDrawer();
-
         void onEditContact(CallContact item);
-
         void setDragView(RelativeLayout relativeLayout);
-
         void toggleForSearchDrawer();
-
     }
 
     @Override
@@ -157,9 +137,7 @@
         if (!(activity instanceof Callbacks)) {
             throw new IllegalStateException("Activity must implement fragment's callbacks.");
         }
-
         mCallbacks = (Callbacks) activity;
-        
     }
 
     @Override
@@ -169,10 +147,19 @@
     }
 
     @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        inflater.inflate(R.menu.newconv_option_menu, menu);
+        SearchView searchView = (SearchView) menu.findItem(R.id.contact_search).getActionView();
+        searchView.setOnQueryTextListener(ContactListFragment.this);
+    }
+
+    @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         View inflatedView = inflater.inflate(R.layout.frag_contact_list, container, false);
         mHeader = (LinearLayout) inflater.inflate(R.layout.frag_contact_list_header, null);
         mContactList = (StickyListHeadersListView) inflatedView.findViewById(R.id.contacts_stickylv);
+        //mContactList.setDividerHeight(0);
+        mContactList.setDivider(null);
 
         inflatedView.findViewById(R.id.drag_view).setOnTouchListener(new OnTouchListener() {
 
@@ -182,7 +169,7 @@
             }
         });
 
-        inflatedView.findViewById(R.id.contact_search_button).setOnClickListener(new OnClickListener() {
+        /*inflatedView.findViewById(R.id.contact_search_button).setOnClickListener(new OnClickListener() {
 
             @Override
             public void onClick(View v) {
@@ -203,10 +190,23 @@
         });
         
         mCallbacks.setDragView(((RelativeLayout) inflatedView.findViewById(R.id.slider_button)));
-
-        mQuickReturnSearchView = (SearchView) mHeader.findViewById(R.id.contact_search);
+*/
+        //mQuickReturnSearchView = (SearchView) mHeader.findViewById(R.id.contact_search);
         mStarredGrid = (GridView) mHeader.findViewById(R.id.favorites_grid);
         llMain = (LinearLayout) mHeader.findViewById(R.id.llMain);
+        favHeadLabel = (TextView) mHeader.findViewById(R.id.fav_head_label);
+        newcontact = (ViewGroup) mHeader.findViewById(R.id.newcontact_element);
+        newcontact.setVisibility(View.GONE);
+        newcontact.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                CallContact c = (CallContact) v.getTag();
+                if (c == null)
+                    return;
+                mCallbacks.onCallContact(c);
+            }
+        });
+
         return inflatedView;
     }
 
@@ -218,7 +218,7 @@
         mContactList.setAdapter(mListAdapter);
 
         mStarredGrid.setAdapter(mGridAdapter);
-        mQuickReturnSearchView.setIconifiedByDefault(false);
+        /*mQuickReturnSearchView.setIconifiedByDefault(false);
 
         mQuickReturnSearchView.setOnClickListener(new OnClickListener() {
 
@@ -228,7 +228,7 @@
                 mQuickReturnSearchView.setFocusable(true);
             }
         });
-        mQuickReturnSearchView.setOnQueryTextListener(ContactListFragment.this);
+        mQuickReturnSearchView.setOnQueryTextListener(ContactListFragment.this);*/
 
         getLoaderManager().initLoader(LoaderConstants.CONTACT_LOADER, null, this);
 
@@ -246,7 +246,7 @@
     };
 
     private void setGridViewListeners() {
-        mStarredGrid.setOnDragListener(dragListener);
+        //mStarredGrid.setOnDragListener(dragListener);
         mStarredGrid.setOnItemClickListener(new OnItemClickListener() {
 
             @Override
@@ -258,7 +258,7 @@
     }
 
     private void setListViewListeners() {
-        mSwipeLvTouchListener = new SwipeListViewTouchListener(mContactList.getWrappedList(), new SwipeListViewTouchListener.OnSwipeCallback() {
+        /*mSwipeLvTouchListener = new SwipeListViewTouchListener(mContactList.getWrappedList(), new SwipeListViewTouchListener.OnSwipeCallback() {
             @Override
             public void onSwipeLeft(ListView listView, int[] reverseSortedPositions) {
             }
@@ -270,21 +270,21 @@
                 down.findViewById(R.id.quick_starred).setClickable(true);
 
             }
-        }, true, false);
+        }, true, false);*/
 
-        mContactList.getWrappedList().setOnDragListener(dragListener);
-        mContactList.getWrappedList().setOnTouchListener(mSwipeLvTouchListener);
+        /*mContactList.getWrappedList().setOnDragListener(dragListener);
+        mContactList.getWrappedList().setOnTouchListener(mSwipeLvTouchListener);*/
         mContactList.getWrappedList().setOnItemLongClickListener(mItemLongClickListener);
-        mContactList.getWrappedList().setOnItemClickListener(new OnItemClickListener() {
+        /*mContactList.getWrappedList().setOnItemClickListener(new OnItemClickListener() {
 
             @Override
             public void onItemClick(AdapterView<?> arg0, View view, int pos, long id) {
                 Log.i(TAG, "Opening Item");
                 mSwipeLvTouchListener.openItem(view, pos, id);
             }
-        });
+        });*/
     }
-
+/*
     OnDragListener dragListener = new OnDragListener() {
 
         @Override
@@ -309,29 +309,36 @@
             return true;
         }
 
-    };
+    };*/
 
     @Override
     public boolean onQueryTextChange(String newText) {
+        mCurFilter = newText;
         if (newText.isEmpty()) {
             getLoaderManager().restartLoader(LoaderConstants.CONTACT_LOADER, null, this);
+            newcontact.setVisibility(View.GONE);
             return true;
         }
-        mCurFilter = newText;
         Bundle b = new Bundle();
         b.putString("filter", mCurFilter);
         getLoaderManager().restartLoader(LoaderConstants.CONTACT_LOADER, b, this);
+        newcontact.setVisibility(View.VISIBLE);
+        ((TextView)newcontact.findViewById(R.id.display_name)).setText("Call \"" + newText + "\"");
+        CallContact contact = CallContact.ContactBuilder.buildUnknownContact(newText);
+        newcontact.setTag(contact);
         return true;
     }
 
     @Override
     public boolean onQueryTextSubmit(String query) {
         // Return false to let the SearchView perform the default action
-        return false;
+        //return false;
+
+        return true;
     }
 
     @Override
-    public Loader<Bundle> onCreateLoader(int id, Bundle args) {
+    public Loader<ContactsLoader.Result> onCreateLoader(int id, Bundle args) {
         Uri baseUri;
 
         Log.i(TAG, "createLoader");
@@ -347,26 +354,27 @@
     }
 
     @Override
-    public void onLoadFinished(Loader<Bundle> loader, Bundle data) {
-
-        mGridAdapter.removeAll();
-        mListAdapter.clear();
-        ArrayList<CallContact> tmp = data.getParcelableArrayList("Contacts");
-        ArrayList<CallContact> tmp2 = data.getParcelableArrayList("Starred");
-        mListAdapter.addAll(tmp);
-        mGridAdapter.addAll(tmp2);
-
+    public void onLoadFinished(Loader<ContactsLoader.Result> loader, ContactsLoader.Result data) {
+        mListAdapter.setData(data.contacts);
         setListViewListeners();
-        setGridViewListeners();
 
-        mStarredGrid.post(new Runnable() {
+        if (data.starred.isEmpty()) {
+            llMain.setVisibility(View.GONE);
+            favHeadLabel.setVisibility(View.GONE);
+            mGridAdapter.removeAll();
+        } else {
+            llMain.setVisibility(View.VISIBLE);
+            favHeadLabel.setVisibility(View.VISIBLE);
+            mGridAdapter.setData(data.starred);
+            setGridViewListeners();
+            mStarredGrid.post(new Runnable() {
 
-            @Override
-            public void run() {
-                setGridViewHeight(mStarredGrid, llMain);
-            }
-        });
-
+                @Override
+                public void run() {
+                    setGridViewHeight(mStarredGrid, llMain);
+                }
+            });
+        }
     }
 
     // Sets the GridView holder's height to fully expand it
@@ -399,6 +407,6 @@
     }
 
     @Override
-    public void onLoaderReset(Loader<Bundle> loader) {
+    public void onLoaderReset(Loader<ContactsLoader.Result> loader) {
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/DetailsHistoryEntryFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/DetailsHistoryEntryFragment.java
index 608115b..5af66eb 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/DetailsHistoryEntryFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/DetailsHistoryEntryFragment.java
@@ -51,7 +51,6 @@
 import cx.ring.service.ISipService;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.NavigableMap;
 import java.util.Random;
@@ -126,7 +125,7 @@
         lvMain.setAdapter(mAdapter);
         iv = (RelativeLayout) inflatedView.findViewById(R.id.iv);
 
-        ((TextView) iv.findViewById(R.id.history_call_name)).setText(toDisplay.getContact().getmDisplayName());
+        ((TextView) iv.findViewById(R.id.history_call_name)).setText(toDisplay.getContact().getDisplayName());
 
         tasker = new ContactPictureTask(getActivity(), (ImageView) inflatedView.findViewById(R.id.contact_photo), toDisplay.getContact());
         tasker.run();
@@ -142,8 +141,8 @@
                     Bundle args = new Bundle();
                     args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
                     args.putParcelable(SipCall.ACCOUNT, new Account(toDisplay.getAccountID(), details, creds, state));
-                    args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_RINGING);
-                    args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
+                    args.putInt(SipCall.STATE, SipCall.State.RINGING);
+                    args.putInt(SipCall.TYPE, SipCall.Direction.OUTGOING);
                     args.putParcelable(SipCall.CONTACT, toDisplay.getContact());
 
                     mCallbacks.onCall(new SipCall(args));
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/DialingFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/DialingFragment.java
index 71425d4..7d434fc 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/DialingFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/DialingFragment.java
@@ -36,6 +36,7 @@
 import android.app.Fragment;
 import cx.ring.R;
 import cx.ring.service.ISipService;
+import cx.ring.service.LocalService;
 import cx.ring.views.ClearableEditText;
 
 import android.app.Activity;
@@ -65,30 +66,21 @@
     private Callbacks mCallbacks = sDummyCallbacks;
 
     /**
-     * A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity.
+     * The Activity calling this fragment has to implement this interface
+     *
      */
-    private static Callbacks sDummyCallbacks = new Callbacks() {
-        @Override
-        public void onCallDialed(String to) {
-        }
-
-        @Override
-        public ISipService getService() {
-            // TODO Auto-generated method stub
-            return null;
-        }
-    };
+    public interface Callbacks extends LocalService.Callbacks {
+        void onCallDialed(String account);
+    }
 
     /**
-     * The Activity calling this fragment has to implement this interface
-     * 
+     * A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity.
      */
-    public interface Callbacks {
-        void onCallDialed(String account);
-
-        public ISipService getService();
-
+    private static class DummyCallbacks extends LocalService.DummyCallbacks implements Callbacks {
+        @Override
+        public void onCallDialed(String to) {}
     }
+    private static final Callbacks sDummyCallbacks = new DummyCallbacks();
 
     @Override
     public void setUserVisibleHint(boolean isVisibleToUser) {
@@ -211,7 +203,7 @@
             try {
                 String toSend = Character.toString(s.charAt(start));
                 toSend.toUpperCase(Locale.getDefault());
-                mCallbacks.getService().playDtmf(toSend);
+                mCallbacks.getRemoteService().playDtmf(toSend);
             } catch (RemoteException e) {
                 e.printStackTrace();
             }
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/GeneralAccountFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/GeneralAccountFragment.java
index 6e9a5f2..7e1774c 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/GeneralAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/GeneralAccountFragment.java
@@ -60,7 +60,7 @@
 
     public interface Callbacks {
 
-        public Account getAccount();
+        Account getAccount();
 
     }
 
@@ -133,30 +133,31 @@
         @Override
         public boolean onPreferenceChange(Preference preference, Object newValue) {
 
-            Log.i(TAG, "Changing preference value:" + newValue);
+            Log.i(TAG, "Changing preference " + preference.getKey() + " to value:" + newValue);
+            final Account acc = mCallbacks.getAccount();
             if (preference instanceof CheckBoxPreference) {
-                mCallbacks.getAccount().getBasicDetails().setDetailString(preference.getKey(), newValue.toString());
+                acc.getBasicDetails().setDetailString(preference.getKey(), newValue.toString());
             } else {
                 if (preference instanceof PasswordPreference) {
                     String tmp = "";
                     for (int i = 0; i < ((String) newValue).length(); ++i) {
                         tmp += "*";
                     }
-                    if(mCallbacks.getAccount().isSip())
-                        mCallbacks.getAccount().getCredentials().get(0).setDetailString(preference.getKey(), newValue.toString());
+                    if(acc.isSip())
+                        acc.getCredentials().get(0).setDetailString(preference.getKey(), newValue.toString());
                     preference.setSummary(tmp);
                 } else if(preference.getKey().contentEquals(AccountDetailBasic.CONFIG_ACCOUNT_USERNAME)) {
-					if(mCallbacks.getAccount().isSip()){
-						mCallbacks.getAccount().getCredentials().get(0).setDetailString(preference.getKey(), newValue.toString());
+					if(acc.isSip()){
+                        acc.getCredentials().get(0).setDetailString(preference.getKey(), newValue.toString());
 					}
                     preference.setSummary((CharSequence) newValue);
                 } else {
                     preference.setSummary((CharSequence) newValue);
                 }
-                
-                mCallbacks.getAccount().getBasicDetails().setDetailString(preference.getKey(), newValue.toString());
+
+                acc.getBasicDetails().setDetailString(preference.getKey(), newValue.toString());
             }
-            mCallbacks.getAccount().notifyObservers();
+            acc.notifyObservers();
             return true;
         }
     };
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/HistoryFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/HistoryFragment.java
index c7221b3..6b05055 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/HistoryFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/HistoryFragment.java
@@ -46,7 +46,6 @@
 import cx.ring.loaders.HistoryLoader;
 import cx.ring.loaders.LoaderConstants;
 import cx.ring.history.HistoryEntry;
-import cx.ring.service.ISipService;
 
 import android.app.Activity;
 import android.content.Context;
@@ -71,27 +70,16 @@
     private Callbacks mCallbacks = sDummyCallbacks;
     HistoryManager mHistoryManager;
 
-    private static Callbacks sDummyCallbacks = new Callbacks() {
+    public interface Callbacks {
+        void onCallHistory(HistoryEntry to);
+    }
+    private static final Callbacks sDummyCallbacks = new Callbacks() {
         @Override
-        public void onCallHistory(HistoryEntry to) {
-        }
-
-        @Override
-        public ISipService getService() {
-            Log.i(TAG, "Dummy");
-            return null;
-        }
-
+        public void onCallHistory(HistoryEntry to) {}
     };
 
     public static String ARGS = "Bundle.args";
 
-    public interface Callbacks {
-        public void onCallHistory(HistoryEntry to);
-
-        public ISipService getService();
-
-    }
 
     @Override
     public void onAttach(Activity activity) {
@@ -216,11 +204,11 @@
             // to the view objects
 
             // SipCall call = (SipCall) mCallList.values().toArray()[position];
-            entryView.displayName.setText(dataset.get(pos).getContact().getmDisplayName());
+            entryView.displayName.setText(dataset.get(pos).getContact().getDisplayName());
             infos_fetcher.execute(new ContactPictureTask(mContext, entryView.photo, dataset.get(pos).getContact()));
 
-            entryView.incoming.setText(getString(R.string.hist_in_calls, dataset.get(pos).getIncoming_sum()));
-            entryView.outgoing.setText(getString(R.string.hist_out_calls, dataset.get(pos).getOutgoing_sum()));
+            entryView.incoming.setText(getString(R.string.hist_in_calls, dataset.get(pos).getIncomingSum()));
+            entryView.outgoing.setText(getString(R.string.hist_out_calls, dataset.get(pos).getOutgoingSum()));
 
             /*if (dataset.get(pos).getCalls().lastEntry().getValue().getRecordPath().length() > 0) {
                 entryView.replay.setVisibility(View.VISIBLE);
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/IMFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/IMFragment.java
deleted file mode 100644
index 0769d63..0000000
--- a/ring-android/app/src/main/java/cx/ring/fragments/IMFragment.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
- *
- *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
- *
- *  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, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Additional permission under GNU GPL version 3 section 7:
- *
- *  If you modify this program, or any covered work, by linking or
- *  combining it with the OpenSSL project's OpenSSL library (or a
- *  modified version of that library), containing parts covered by the
- *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
- *  grants you additional permission to convey the resulting work.
- *  Corresponding Source for a non-source form of such a combination
- *  shall include the source code for the parts of OpenSSL used as well
- *  as that of the covered work.
- */
-package cx.ring.fragments;
-
-import android.widget.*;
-import cx.ring.R;
-import cx.ring.adapters.DiscussArrayAdapter;
-import cx.ring.model.Conference;
-import cx.ring.model.SipMessage;
-import cx.ring.service.ISipService;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
-import android.widget.TextView.OnEditorActionListener;
-
-public class IMFragment extends CallableWrapperFragment {
-    static final String TAG = IMFragment.class.getSimpleName();
-
-    private Callbacks mCallbacks = sDummyCallbacks;
-
-    DiscussArrayAdapter mAdapter;
-    ListView list;
-
-    private EditText sendTextField;
-
-    @Override
-    public void onCreate(Bundle savedBundle) {
-        super.onCreate(savedBundle);
-
-        mAdapter = new DiscussArrayAdapter(getActivity(), getArguments());
-
-    }
-
-    @Override
-    public void incomingText(Conference updated, String ID, String from, String msg) {
-        mCallbacks.updateDisplayedConference(updated);
-        if(updated.equals(mCallbacks.getDisplayedConference())){
-            SipMessage sipMsg = new SipMessage(true, msg);
-            putMessage(sipMsg);
-        }
-
-    }
-
-
-    /**
-     * A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity.
-     */
-    private static Callbacks sDummyCallbacks = new Callbacks() {
-
-        @Override
-        public ISipService getService() {
-            return null;
-        }
-
-        @Override
-        public Conference getDisplayedConference() {
-            return null;
-        }
-
-        @Override
-        public boolean sendIM(SipMessage msg) {
-            return false;
-        }
-
-        @Override
-        public void updateDisplayedConference(Conference c) {
-
-        }
-
-    };
-
-    /**
-     * The Activity calling this fragment has to implement this interface
-     */
-    public interface Callbacks {
-        public ISipService getService();
-
-        public Conference getDisplayedConference();
-
-        public boolean sendIM(SipMessage msg);
-
-        public void updateDisplayedConference(Conference c);
-    }
-
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-
-        if (!(activity instanceof Callbacks)) {
-            throw new IllegalStateException("Activity must implement fragment's callbacks.");
-        }
-
-        mCallbacks = (Callbacks) activity;
-    }
-
-    @Override
-    public void onDetach() {
-        super.onDetach();
-        mCallbacks = sDummyCallbacks;
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.frag_imessaging, container, false);
-
-        list = (ListView) rootView.findViewById(R.id.message_list);
-        list.setAdapter(mAdapter);
-
-        sendTextField = (EditText) rootView.findViewById(R.id.send_im_edittext);
-
-        sendTextField.setOnEditorActionListener(new OnEditorActionListener() {
-
-            @Override
-            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-
-                if (actionId == EditorInfo.IME_ACTION_SEND) {
-                    sendMessage();
-                }
-                return true;
-            }
-        });
-
-        rootView.findViewById(R.id.send_im_button).setOnClickListener(new OnClickListener() {
-
-            @Override
-            public void onClick(View v) {
-                sendMessage();
-            }
-        });
-
-
-        return rootView;
-    }
-
-    private void sendMessage() {
-        if (sendTextField.getText().toString().length() > 0) {
-            SipMessage toSend = new SipMessage(false, sendTextField.getText().toString());
-            if (mCallbacks.sendIM(toSend)) {
-                putMessage(toSend);
-                sendTextField.setText("");
-            } else {
-                Toast.makeText(getActivity(), "Error sending message", Toast.LENGTH_SHORT).show();
-            }
-        }
-    }
-
-
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-    }
-
-    public void putMessage(SipMessage msg) {
-        mAdapter.add(msg);
-        Log.i(TAG, "Messages" + mAdapter.getCount());
-    }
-}
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/MenuFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/MenuFragment.java
index 42bc786..ad0ed23 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/MenuFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/MenuFragment.java
@@ -31,9 +31,13 @@
 package cx.ring.fragments;
 
 import android.app.Activity;
+import android.app.Fragment;
 import android.app.LoaderManager;
 import android.content.AsyncTaskLoader;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.Loader;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -46,28 +50,25 @@
 import cx.ring.R;
 import cx.ring.adapters.AccountSelectionAdapter;
 import cx.ring.adapters.ContactPictureTask;
+import cx.ring.client.HomeActivity;
 import cx.ring.loaders.AccountsLoader;
 import cx.ring.loaders.LoaderConstants;
 import cx.ring.model.account.Account;
 import cx.ring.model.CallContact;
+import cx.ring.service.ConfigurationManagerCallback;
 import cx.ring.service.ISipService;
+import cx.ring.service.LocalService;
 
 import java.util.ArrayList;
 
-public class MenuFragment extends AccountWrapperFragment implements LoaderManager.LoaderCallbacks<Bundle> {
+public class MenuFragment extends Fragment /*extends AccountWrapperFragment implements LoaderManager.LoaderCallbacks<Bundle>*/ {
 
     @SuppressWarnings("unused")
     private static final String TAG = MenuFragment.class.getSimpleName();
 
     AccountSelectionAdapter mAccountAdapter;
     private Spinner spinnerAccounts;
-    private Callbacks mCallbacks = sDummyCallbacks;
-    private static Callbacks sDummyCallbacks = new Callbacks() {
-        @Override
-        public ISipService getService() {
-            return null;
-        }
-    };
+    private LocalService.Callbacks mCallbacks = LocalService.DUMMY_CALLBACKS;
 
     public Account retrieveAccountById(String accountID) {
         Account toReturn;
@@ -79,23 +80,20 @@
         return toReturn;
     }
 
-    public interface Callbacks {
-        ISipService getService();
-    }
-
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
-        if (!(activity instanceof Callbacks)) {
+        if (!(activity instanceof LocalService.Callbacks)) {
             throw new IllegalStateException("Activity must implement fragment's callbacks.");
         }
-        mCallbacks = (Callbacks) activity;
+        mCallbacks = (LocalService.Callbacks) activity;
+        updateAllAccounts();
     }
 
     @Override
     public void onDetach() {
         super.onDetach();
-        mCallbacks = sDummyCallbacks;
+        mCallbacks = LocalService.DUMMY_CALLBACKS;
     }
 
     @Override
@@ -103,25 +101,34 @@
         super.onCreate(savedInstanceState);
     }
 
-    public void onResume() {
-        super.onResume();
-
-        Log.i(TAG, "Resuming");
-        getLoaderManager().restartLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);
-
-    }
-
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
-        getLoaderManager().restartLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);
+        //getLoaderManager().restartLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);
     }
 
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().contentEquals(LocalService.ACTION_ACCOUNT_UPDATE)) {
+                updateAllAccounts();
+            }
+        }
+    };
 
+    @Override
+    public void onResume() {
+        Log.i(TAG, "Resuming");
+        super.onResume();
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(LocalService.ACTION_ACCOUNT_UPDATE);
+        getActivity().registerReceiver(mReceiver, intentFilter);
+    }
 
     @Override
     public void onPause() {
         super.onPause();
+        getActivity().unregisterReceiver(mReceiver);
     }
 
     @Override
@@ -139,7 +146,7 @@
                 mAccountAdapter.setSelectedAccount(pos);
                 //view.findViewById(R.id.account_selected).setVisibility(View.GONE);
                 try {
-                    mCallbacks.getService().setAccountOrder(mAccountAdapter.getAccountOrder());
+                    mCallbacks.getRemoteService().setAccountOrder(mAccountAdapter.getAccountOrder());
                 } catch (RemoteException e) {
                     e.printStackTrace();
                 }
@@ -155,7 +162,9 @@
         CallContact user = CallContact.ContactBuilder.buildUserContact(getActivity().getContentResolver());
         new ContactPictureTask(getActivity(), (ImageView) inflatedView.findViewById(R.id.user_photo), user).run();
 
-        ((TextView) inflatedView.findViewById(R.id.user_name)).setText(user.getmDisplayName());
+        ((TextView) inflatedView.findViewById(R.id.user_name)).setText(user.getDisplayName());
+
+        updateAllAccounts();
 
         return inflatedView;
     }
@@ -172,10 +181,15 @@
     }
 
     public void updateAllAccounts() {
-        if (getActivity() != null)
-            getLoaderManager().restartLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);
+        /*if (getActivity() != null)
+            getLoaderManager().restartLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);*/
+        if (mAccountAdapter != null && mCallbacks.getService() != null) {
+            mAccountAdapter.removeAll();
+            mAccountAdapter.addAll(mCallbacks.getService().getAccounts());
+        }
     }
 
+    /*
     @Override
     public void accountsChanged() {
         updateAllAccounts();
@@ -183,16 +197,16 @@
     }
 
     @Override
-    public void accountStateChanged(String accoundID, String state, int code) {
-        Log.w(TAG, "accountStateChanged " + accoundID + " " + state);
+    public void accountStateChanged(String accoundID, String State, int code) {
+        Log.w(TAG, "accountStateChanged " + accoundID + " " + State);
 
         if (mAccountAdapter != null)
-            mAccountAdapter.updateAccount(accoundID, state, code);
+            mAccountAdapter.updateAccount(accoundID, State, code);
     }
 
     @Override
     public AsyncTaskLoader<Bundle> onCreateLoader(int arg0, Bundle arg1) {
-        AccountsLoader l = new AccountsLoader(getActivity(), mCallbacks.getService());
+        AccountsLoader l = new AccountsLoader(getActivity(), mCallbacks.getRemoteService());
         l.forceLoad();
         return l;
     }
@@ -208,6 +222,6 @@
     @Override
     public void onLoaderReset(Loader<Bundle> loader) {
 
-    }
+    }*/
 
 }
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/NestedSettingsFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/NestedSettingsFragment.java
index 87e3581..6d192f1 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/NestedSettingsFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/NestedSettingsFragment.java
@@ -47,6 +47,7 @@
 import cx.ring.model.account.TLSManager;
 import cx.ring.model.account.Account;
 import cx.ring.service.ISipService;
+import cx.ring.service.LocalService;
 
 import java.util.ArrayList;
 
@@ -62,23 +63,24 @@
     TLSManager mTlsManager;
 
     private static Callbacks sDummyCallbacks = new Callbacks() {
-
+        @Override
+        public ISipService getRemoteService() {
+            return null;
+        }
+        @Override
+        public LocalService getService() {
+            return null;
+        }
         @Override
         public Account getAccount() {
             return null;
         }
-
-        @Override
-        public ISipService getService() {
-            return null;
-        }
-
     };
 
     public String[] getTlsMethods() {
         ArrayList<String> methods = null;
         try {
-            methods = (ArrayList<String>) mCallbacks.getService().getTlsSupportedMethods();
+            methods = (ArrayList<String>) mCallbacks.getRemoteService().getTlsSupportedMethods();
         } catch (RemoteException e) {
             e.printStackTrace();
         }
@@ -105,12 +107,8 @@
         return false;
     }
 
-    public interface Callbacks {
-
-        public Account getAccount();
-
-        public ISipService getService();
-
+    public interface Callbacks extends LocalService.Callbacks {
+        Account getAccount();
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/SecurityAccountFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/SecurityAccountFragment.java
index 01042e6..f039995 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/SecurityAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/SecurityAccountFragment.java
@@ -50,8 +50,7 @@
     private static final String TAG = SecurityAccountFragment.class.getSimpleName();
 
     private Callbacks mCallbacks = sDummyCallbacks;
-    private static Callbacks sDummyCallbacks = new Callbacks() {
-
+    private static final Callbacks sDummyCallbacks = new Callbacks() {
         @Override
         public Account getAccount() {
             return null;
@@ -68,19 +67,13 @@
         @Override
         public void displayTLSScreen() {
         }
-
     };
 
     public interface Callbacks {
-
-        public Account getAccount();
-
-        public void displayCredentialsScreen();
-
-        public void displaySRTPScreen();
-
-        public void displayTLSScreen();
-
+        Account getAccount();
+        void displayCredentialsScreen();
+        void displaySRTPScreen();
+        void displayTLSScreen();
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/TransferDFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/TransferDFragment.java
index cb331de..a2d8a57 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/TransferDFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/TransferDFragment.java
@@ -70,7 +70,7 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-public class TransferDFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<Bundle> {
+public class TransferDFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<ContactsLoader.Result> {
     public static final int RESULT_TRANSFER_CONF = Activity.RESULT_FIRST_USER + 1;
     public static final int RESULT_TRANSFER_NUMBER = Activity.RESULT_FIRST_USER + 2;
 
@@ -124,7 +124,7 @@
         mEditText.setAdapter(autoCompleteAdapter);
 
         final AlertDialog a = new AlertDialog.Builder(getActivity()).setView(rootView)
-                .setTitle("Transfer " + call_selected.getmContact().getmDisplayName())
+                .setTitle("Transfer " + call_selected.getContact().getDisplayName())
                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int whichButton) {
@@ -165,7 +165,7 @@
     }
 
     @Override
-    public Loader<Bundle> onCreateLoader(int id, Bundle args) {
+    public Loader<ContactsLoader.Result> onCreateLoader(int id, Bundle args) {
         Uri baseUri;
 
         if (args != null) {
@@ -179,14 +179,14 @@
     }
 
     @Override
-    public void onLoadFinished(Loader<Bundle> loader, Bundle data) {
+    public void onLoadFinished(Loader<ContactsLoader.Result> loader, ContactsLoader.Result data) {
 
 //        ArrayList<CallContact> tmp = data.getParcelableArrayList("Contacts");
 
     }
 
     @Override
-    public void onLoaderReset(Loader<Bundle> loader) {
+    public void onLoaderReset(Loader<ContactsLoader.Result> loader) {
         // Thi is called when the last Cursor provided to onLoadFinished
         // mListAdapter.swapCursor(null);
     }
@@ -281,7 +281,7 @@
                 tv = (TextView) mInflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
             }
 
-            tv.setText(calls.get(position).getParticipants().get(0).getmContact().getmDisplayName());
+            tv.setText(calls.get(position).getParticipants().get(0).getContact().getDisplayName());
             return tv;
         }
 
diff --git a/ring-android/app/src/main/java/cx/ring/history/DatabaseHelper.java b/ring-android/app/src/main/java/cx/ring/history/DatabaseHelper.java
index a623e98..43c116f 100644
--- a/ring-android/app/src/main/java/cx/ring/history/DatabaseHelper.java
+++ b/ring-android/app/src/main/java/cx/ring/history/DatabaseHelper.java
@@ -48,13 +48,12 @@
  */
 public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
 
-    // name of the database file for your application -- change to something appropriate for your app
     private static final String DATABASE_NAME = "history.db";
     // any time you make changes to your database objects, you may have to increase the database version
-    private static final int DATABASE_VERSION = 2;
+    private static final int DATABASE_VERSION = 4;
 
-    // the DAO object we use to access the SimpleData table
     private Dao<HistoryCall, Integer> historyDao = null;
+    private Dao<HistoryText, Integer> historyTextDao = null;
 
     public DatabaseHelper(Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -67,8 +66,10 @@
     @Override
     public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
         try {
+            //TableUtils.dropTable(connectionSource, HistoryCall.class, true);
             Log.i(DatabaseHelper.class.getName(), "onCreate");
             TableUtils.createTable(connectionSource, HistoryCall.class);
+            TableUtils.createTable(connectionSource, HistoryText.class);
         } catch (SQLException e) {
             Log.e(DatabaseHelper.class.getName(), "Can't create database", e);
             throw new RuntimeException(e);
@@ -84,6 +85,7 @@
         try {
             Log.i(DatabaseHelper.class.getName(), "onUpgrade");
             TableUtils.dropTable(connectionSource, HistoryCall.class, true);
+            TableUtils.dropTable(connectionSource, HistoryText.class, true);
             // after we drop the old databases, we create the new ones
             onCreate(db, connectionSource);
         } catch (SQLException e) {
@@ -102,6 +104,12 @@
         }
         return historyDao;
     }
+    public Dao<HistoryText, Integer> getTextHistoryDao() throws SQLException {
+        if (historyTextDao == null) {
+            historyTextDao = getDao(HistoryText.class);
+        }
+        return historyTextDao;
+    }
 
     /**
      * Close the database connections and clear any cached DAOs.
@@ -110,5 +118,6 @@
     public void close() {
         super.close();
         historyDao = null;
+        historyTextDao = null;
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/history/HistoryCall.java b/ring-android/app/src/main/java/cx/ring/history/HistoryCall.java
index 2e76729..0e818d0 100644
--- a/ring-android/app/src/main/java/cx/ring/history/HistoryCall.java
+++ b/ring-android/app/src/main/java/cx/ring/history/HistoryCall.java
@@ -46,11 +46,11 @@
 public class HistoryCall implements Parcelable {
 
     @DatabaseField(index = true, columnName="TIMESTAMP_START")
-    long call_start;
+    public long call_start;
     @DatabaseField
-    long call_end;
+    public long call_end;
     @DatabaseField
-    String number;
+    public String number;
     @DatabaseField
     boolean missed;
     @DatabaseField
@@ -62,6 +62,8 @@
     @DatabaseField
     long contactID;
     @DatabaseField
+    String contactKey;
+    @DatabaseField
     String callID;
 
     public String getAccountID() {
@@ -73,14 +75,15 @@
     }
 
     public HistoryCall(SipCall call) {
-        call_start = call.getTimestampStart_();
-        call_end = call.getTimestampEnd_();
-        accountID = call.getAccount().getAccountID();
-        number = call.getmContact().getPhones().get(0).getNumber();
+        call_start = call.getTimestampStart();
+        call_end = call.getTimestampEnd();
+        accountID = call.getAccount();
+        number = call.getNumber();
         missed = call.isRinging() && call.isIncoming();
         direction = call.getCallType();
         recordPath = call.getRecordPath();
-        contactID = call.getmContact().getId();
+        contactID = call.getContact().getId();
+        contactKey = call.getContact().getKey();
         callID = call.getCallId();
     }
 
@@ -90,10 +93,10 @@
 
     public String getDirection() {
         switch (direction) {
-            case SipCall.direction.CALL_TYPE_INCOMING:
-                return "CALL_TYPE_INCOMING";
-            case SipCall.direction.CALL_TYPE_OUTGOING:
-                return "CALL_TYPE_OUTGOING";
+            case SipCall.Direction.INCOMING:
+                return "INCOMING";
+            case SipCall.Direction.OUTGOING:
+                return "OUTGOING";
             default:
                 return "CALL_TYPE_UNDETERMINED";
         }
@@ -102,9 +105,15 @@
     public String getDate() {
         return HistoryTimeModel.timeToHistoryConst(call_start);
     }
+    public Date getStartDate() {
+        return new Date(call_start);
+    }
+    public Date getEndDate() {
+        return new Date(call_end);
+    }
 
     public String getStartString(String format) {
-        Timestamp stamp = new Timestamp(call_start * 1000); // in milliseconds
+        Timestamp stamp = new Timestamp(call_start); // in milliseconds
         Date date = new Date(stamp.getTime());
         SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
         sdf.setTimeZone(TimeZone.getDefault());
@@ -114,7 +123,7 @@
 
     public String getDurationString() {
 
-        long duration = call_end - call_start;
+        long duration = (call_end - call_start)/1000;
         if (duration < 60)
             return String.format(Locale.getDefault(), "%02d secs", duration);
 
@@ -122,7 +131,6 @@
             return String.format(Locale.getDefault(), "%02d mins %02d secs", (duration % 3600) / 60, (duration % 60));
 
         return String.format(Locale.getDefault(), "%d h %02d mins %02d secs", duration / 3600, (duration % 3600) / 60, (duration % 60));
-
     }
 
     public long getDuration() {
@@ -152,6 +160,7 @@
         dest.writeInt(direction);
         dest.writeString(recordPath);
         dest.writeLong(contactID);
+        dest.writeString(contactKey);
         dest.writeString(callID);
     }
 
@@ -174,6 +183,7 @@
         direction = in.readInt();
         recordPath = in.readString();
         contactID = in.readLong();
+        contactKey = in.readString();
         callID = in.readString();
     }
 
@@ -182,11 +192,14 @@
     }
 
     public boolean isIncoming() {
-        return direction == SipCall.direction.CALL_TYPE_INCOMING;
+        return direction == SipCall.Direction.INCOMING;
     }
 
     public boolean isMissed() {
         return missed;
     }
 
+    public CharSequence getCallId() {
+        return callID;
+    }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/history/HistoryEntry.java b/ring-android/app/src/main/java/cx/ring/history/HistoryEntry.java
index 385355c..433db3c 100644
--- a/ring-android/app/src/main/java/cx/ring/history/HistoryEntry.java
+++ b/ring-android/app/src/main/java/cx/ring/history/HistoryEntry.java
@@ -34,15 +34,18 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import cx.ring.model.CallContact;
+import cx.ring.model.TextMessage;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.NavigableMap;
 import java.util.TreeMap;
 
 public class HistoryEntry implements Parcelable {
 
     private CallContact contact;
-    private NavigableMap<Long, HistoryCall> calls;
+    private final NavigableMap<Long, HistoryCall> calls = new TreeMap<>();
+    private final NavigableMap<Long, TextMessage> text_messages = new TreeMap<>();
     private String accountID;
     int missed_sum;
     int outgoing_sum;
@@ -50,7 +53,6 @@
 
     public HistoryEntry(String account, CallContact c) {
         contact = c;
-        calls = new TreeMap<Long, HistoryCall>();
         accountID = account;
         missed_sum = outgoing_sum = incoming_sum = 0;
     }
@@ -66,6 +68,9 @@
     public NavigableMap<Long, HistoryCall> getCalls() {
         return calls;
     }
+    public NavigableMap<Long, TextMessage> getTextMessages() {
+        return text_messages;
+    }
 
     public CallContact getContact() {
         return contact;
@@ -97,13 +102,24 @@
             setContact(linkedTo);
     }
 
+    public void addTextMessage(TextMessage text) {
+        text_messages.put(text.getTimestamp(), text);
+        if (contact.isUnknown() && !text.getContact().isUnknown())
+            setContact(text.getContact());
+    }
+    /*public void addTextMessage(HistoryText text) {
+        TextMessage txt = new TextMessage(text);
+        txt.setContact(contact);
+        text_messages.put(txt.getTimestamp(), txt);
+    }*/
+
     public String getNumber() {
         return calls.lastEntry().getValue().number;
     }
 
     public String getTotalDuration() {
         int duration = 0;
-        ArrayList<HistoryCall> all_calls = new ArrayList<HistoryCall>(calls.values());
+        ArrayList<HistoryCall> all_calls = new ArrayList<>(calls.values());
         for (HistoryCall all_call : all_calls) {
             duration += all_call.getDuration();
         }
@@ -114,15 +130,60 @@
         return duration / 60 + "min";
     }
 
-    public int getMissed_sum() {
+    public Date getLastCallDate() {
+        /*Date d = new Date(0);
+        for (Map.Entry<Long, HistoryCall> c : getCalls().entrySet()) {
+            Date nd = c.getValue().getStartDate();
+            if (d.compareTo(nd) < 0)
+                d = nd;
+        }
+        return d;*/
+        return new Date(calls.isEmpty() ? 0 : calls.lastEntry().getKey());
+    }
+    public Date getLastTextDate() {
+        return new Date(text_messages.isEmpty() ? 0 : text_messages.lastEntry().getKey());
+    }
+    public Date getLastInteraction() {
+        return new Date(Math.max(calls.isEmpty() ? 0 : calls.lastEntry().getKey(), text_messages.isEmpty() ? 0 : text_messages.lastEntry().getKey()));
+    }
+
+    public HistoryCall getLastOutgoingCall() {
+        for (HistoryCall c : calls.descendingMap().values())
+            if (!c.isIncoming())
+                return c;
+        return null;
+    }
+    public TextMessage getLastOutgoingText() {
+        for (TextMessage c : text_messages.descendingMap().values())
+            if (c.isOutgoing())
+                return c;
+        return null;
+    }
+
+    public String getLastNumberUsed() {
+        HistoryCall call = getLastOutgoingCall();
+        TextMessage text = getLastOutgoingText();
+        if (call == null && text == null)
+            return null;
+        if (call == null)
+            return text.getNumber();
+        if (text == null)
+            return call.getNumber();
+        if (call.call_start < text.getTimestamp())
+            return text.getNumber();
+        else
+            return call.getNumber();
+    }
+
+    public int getMissedSum() {
         return missed_sum;
     }
 
-    public int getOutgoing_sum() {
+    public int getOutgoingSum() {
         return outgoing_sum;
     }
 
-    public int getIncoming_sum() {
+    public int getIncomingSum() {
         return incoming_sum;
     }
 
@@ -136,8 +197,10 @@
 
         dest.writeParcelable(contact, 0);
 
-        dest.writeList(new ArrayList<HistoryCall>(calls.values()));
-        dest.writeList(new ArrayList<Long>(calls.keySet()));
+        dest.writeList(new ArrayList<>(calls.values()));
+        dest.writeList(new ArrayList<>(calls.keySet()));
+        dest.writeList(new ArrayList<>(text_messages.values()));
+        dest.writeList(new ArrayList<>(text_messages.keySet()));
 
         dest.writeString(accountID);
         dest.writeInt(missed_sum);
@@ -159,21 +222,24 @@
     private HistoryEntry(Parcel in) {
         contact = in.readParcelable(CallContact.class.getClassLoader());
 
-        ArrayList<HistoryCall> values = new ArrayList<HistoryCall>();
+        ArrayList<HistoryCall> values = new ArrayList<>();
         in.readList(values, HistoryCall.class.getClassLoader());
-
-        ArrayList<Long> keys = new ArrayList<Long>();
+        ArrayList<Long> keys = new ArrayList<>();
         in.readList(keys, Long.class.getClassLoader());
-
-        calls = new TreeMap<Long, HistoryCall>();
         for (int i = 0; i < keys.size(); ++i) {
             calls.put(keys.get(i), values.get(i));
         }
+        ArrayList<TextMessage> tvalues = new ArrayList<>();
+        in.readList(tvalues, TextMessage.class.getClassLoader());
+        ArrayList<Long> tkeys = new ArrayList<>();
+        in.readList(tkeys, Long.class.getClassLoader());
+        for (int i = 0; i < keys.size(); ++i) {
+            text_messages.put(tkeys.get(i), tvalues.get(i));
+        }
 
         accountID = in.readString();
         missed_sum = in.readInt();
         outgoing_sum = in.readInt();
         incoming_sum = in.readInt();
     }
-
 }
diff --git a/ring-android/app/src/main/java/cx/ring/history/HistoryManager.java b/ring-android/app/src/main/java/cx/ring/history/HistoryManager.java
index 591cbf0..07355c2 100644
--- a/ring-android/app/src/main/java/cx/ring/history/HistoryManager.java
+++ b/ring-android/app/src/main/java/cx/ring/history/HistoryManager.java
@@ -32,6 +32,8 @@
 package cx.ring.history;
 
 import android.content.Context;
+import android.util.Log;
+
 import com.j256.ormlite.android.apptools.OpenHelperManager;
 import com.j256.ormlite.stmt.QueryBuilder;
 import com.j256.ormlite.table.TableUtils;
@@ -53,9 +55,10 @@
 
     public boolean insertNewEntry(Conference toInsert){
         for (SipCall call : toInsert.getParticipants()) {
-            call.setTimestampEnd_(System.currentTimeMillis());
+            call.setTimestampEnd(System.currentTimeMillis());
             HistoryCall persistent = new HistoryCall(call);
             try {
+                Log.w("HistoryManager", "HistoryDao().create() " + persistent.getNumber() + " " + persistent.getStartDate().toString() + " " + persistent.getEndDate());
                 getHelper().getHistoryDao().create(persistent);
             } catch (SQLException e) {
                 e.printStackTrace();
@@ -65,6 +68,17 @@
         return true;
     }
 
+    public boolean insertNewTextMessage(HistoryText txt) {
+        try {
+            Log.w("HistoryManager", "HistoryDao().create() acc:" + txt.getAccountID() + " num:" + txt.getNumber() + " date:" + txt.getDate().toString() + " msg:" + txt.getMessage());
+            getHelper().getTextHistoryDao().create(txt);
+        } catch (SQLException e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
     /*
     * Necessary when user hang up a call in a Conference
     * The call creates an HistoryCall, but the conference still goes on
@@ -84,16 +98,21 @@
     }
 
     public List<HistoryCall> getAll() throws SQLException {
-
         QueryBuilder<HistoryCall, Integer> qb = getHelper().getHistoryDao().queryBuilder();
         qb.orderBy("TIMESTAMP_START", true);
-
         return getHelper().getHistoryDao().query(qb.prepare());
     }
 
+    public List<HistoryText> getAllTextMessages() throws SQLException {
+        QueryBuilder<HistoryText, Integer> qb = getHelper().getTextHistoryDao().queryBuilder();
+        qb.orderBy("TIMESTAMP", true);
+        return getHelper().getTextHistoryDao().query(qb.prepare());
+    }
+
     public boolean clearDB() {
         try {
             TableUtils.clearTable(getHelper().getConnectionSource(), HistoryCall.class);
+            TableUtils.clearTable(getHelper().getConnectionSource(), HistoryText.class);
         } catch (SQLException e) {
             e.printStackTrace();
             return false;
diff --git a/ring-android/app/src/main/java/cx/ring/history/HistoryText.java b/ring-android/app/src/main/java/cx/ring/history/HistoryText.java
new file mode 100644
index 0000000..372c203
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/history/HistoryText.java
@@ -0,0 +1,187 @@
+/*
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
+ *
+ *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ *  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, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+
+package cx.ring.history;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.j256.ormlite.field.DatabaseField;
+
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import cx.ring.model.CallContact;
+import cx.ring.model.TextMessage;
+
+public class HistoryText implements Parcelable {
+
+    @DatabaseField(index = true, columnName="id")
+    public String id;
+    @DatabaseField(index = true, columnName="TIMESTAMP")
+    public long time;
+    @DatabaseField
+    public String number;
+    @DatabaseField
+    int direction;
+    @DatabaseField
+    String accountID;
+    @DatabaseField
+    long contactID;
+    @DatabaseField
+    String contactKey;
+    @DatabaseField
+    String callID;
+    @DatabaseField
+    String message;
+
+    public HistoryText(TextMessage txt) {
+        id = txt.getId();
+        time = txt.getTimestamp();
+        accountID = txt.getAccount();
+        number = txt.getNumber();
+        direction = txt.getCallType();
+        message = txt.getMessage();
+        callID = txt.getCallId();
+        if (txt.getContact() != null) {
+            contactID = txt.getContact().getId();
+            contactKey = txt.getContact().getKey();
+        }
+    }
+
+    public String getAccountID() {
+        return accountID;
+    }
+
+    public long getContactID() {
+        return contactID;
+    }
+
+    /*
+    public HistoryText(String account, String from, String msg, CallContact contact, boolean incoming) {
+        time = System.currentTimeMillis();
+        accountID = account;
+        number = from;
+        direction = incoming ? TextMessage.direction.INCOMING : TextMessage.direction.OUTGOING;
+        if (contact != null) {
+            contactID = contact.getId();
+            contactKey = contact.getKey();
+        }
+        //callID = call.getCallId();
+        message = msg;
+    }*/
+
+    /* Needed by ORMLite */
+    public HistoryText() {
+    }
+
+    public String getDirection() {
+        switch (direction) {
+            case TextMessage.direction.INCOMING:
+                return "INCOMING";
+            case TextMessage.direction.OUTGOING:
+                return "OUTGOING";
+            default:
+                return "CALL_TYPE_UNDETERMINED";
+        }
+    }
+
+    public Date getDate() {
+        return new Date(time);
+    }
+
+    public String getTimeString(String format) {
+        Timestamp stamp = new Timestamp(time); // in milliseconds
+        Date date = new Date(stamp.getTime());
+        SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
+        sdf.setTimeZone(TimeZone.getDefault());
+        return sdf.format(date);
+
+    }
+
+    public String getNumber() {
+        return number;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(id);
+        dest.writeLong(time);
+        dest.writeString(accountID);
+        dest.writeString(number);
+        dest.writeInt(direction);
+        dest.writeLong(contactID);
+        dest.writeString(callID);
+        dest.writeString(message);
+    }
+
+    public static final Creator<HistoryText> CREATOR = new Creator<HistoryText>() {
+        public HistoryText createFromParcel(Parcel in) {
+            return new HistoryText(in);
+        }
+
+        public HistoryText[] newArray(int size) {
+            return new HistoryText[size];
+        }
+    };
+
+    public HistoryText(Parcel in) {
+        id = in.readString();
+        time = in.readLong();
+        accountID = in.readString();
+        number = in.readString();
+        direction = in.readInt();
+        contactID = in.readLong();
+        callID = in.readString();
+        message = in.readString();
+    }
+
+    public boolean isIncoming() {
+        return direction == TextMessage.direction.INCOMING;
+    }
+
+    public String getCallId() {
+        return callID;
+    }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/loaders/AccountsLoader.java b/ring-android/app/src/main/java/cx/ring/loaders/AccountsLoader.java
index 32c2cc7..b96b666 100644
--- a/ring-android/app/src/main/java/cx/ring/loaders/AccountsLoader.java
+++ b/ring-android/app/src/main/java/cx/ring/loaders/AccountsLoader.java
@@ -76,24 +76,23 @@
             Map<String, String> state;
             for (String id : accountIDs) {
 
+                details = (Map<String, String>) service.getAccountDetails(id);
+                state = (Map<String, String>) service.getVolatileAccountDetails(id);
                 if (id.contentEquals(ACCOUNT_IP2IP)) {
-                    details = (HashMap<String, String>) service.getAccountDetails(id);
-                    state = (Map<String, String>) service.getVolatileAccountDetails(id);
                     IP2IP = new Account(ACCOUNT_IP2IP, details, new ArrayList<Map<String, String>>(), state); // Empty credentials
                     //accounts.add(IP2IP);
                     continue;
                 }
-                details = (Map<String, String>) service.getAccountDetails(id);
+
                 credentials = (ArrayList<Map<String, String>>) service.getCredentials(id);
-                state = (Map<String, String>) service.getVolatileAccountDetails(id);
-                for (Map.Entry<String, String> entry : state.entrySet()) {
+                /*for (Map.Entry<String, String> entry : state.entrySet()) {
                     Log.i(TAG, "state:" + entry.getKey() + " -> " + entry.getValue());
-                }
+                }*/
                 Account tmp = new Account(id, details, credentials, state);
 
                 accounts.add(tmp);
 
-                Log.i(TAG, "account:" + tmp.getAlias() + " " + tmp.isEnabled());
+               // Log.i(TAG, "account:" + tmp.getAlias() + " " + tmp.isEnabled());
 
             }
         } catch (RemoteException | NullPointerException e) {
diff --git a/ring-android/app/src/main/java/cx/ring/loaders/ContactsLoader.java b/ring-android/app/src/main/java/cx/ring/loaders/ContactsLoader.java
index 3482d34..fd71e80 100644
--- a/ring-android/app/src/main/java/cx/ring/loaders/ContactsLoader.java
+++ b/ring-android/app/src/main/java/cx/ring/loaders/ContactsLoader.java
@@ -36,24 +36,32 @@
 import cx.ring.model.CallContact;
 
 import android.content.AsyncTaskLoader;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
+import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 import android.provider.ContactsContract.Contacts;
+import android.util.Log;
 
-public class ContactsLoader extends AsyncTaskLoader<Bundle> {
-    
-//    private static final String TAG = ContactsLoader.class.getSimpleName();
+public class ContactsLoader extends AsyncTaskLoader<ContactsLoader.Result>
+{
+    private static final String TAG = ContactsLoader.class.getSimpleName();
+
+    public class Result {
+        public final ArrayList<CallContact> contacts = new ArrayList<>();
+        public final ArrayList<CallContact> starred = new ArrayList<>();
+    }
 
     // These are the Contacts rows that we will retrieve.
-    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY, Contacts.STARRED };
+    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.LOOKUP_KEY, Contacts.DISPLAY_NAME, Contacts.PHOTO_ID, Contacts.STARRED };
     static final String[] CONTACTS_PHONES_PROJECTION = new String[] { Phone.NUMBER, Phone.TYPE };
     static final String[] CONTACTS_SIP_PROJECTION = new String[] { SipAddress.SIP_ADDRESS, SipAddress.TYPE };
 
-    String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))";
+    static private final String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))";
     Uri baseUri;
 
     public ContactsLoader(Context context, Uri u) {
@@ -62,52 +70,55 @@
     }
 
     @Override
-    public Bundle loadInBackground() {
-        ArrayList<CallContact> contacts = new ArrayList<CallContact>();
-        ArrayList<CallContact> starred = new ArrayList<CallContact>();
+    public Result loadInBackground() {
+        Result res = new Result();
 
-        Cursor result = getContext().getContentResolver().query(baseUri, CONTACTS_SUMMARY_PROJECTION, select, null,
-                Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
+        ContentResolver cr = getContext().getContentResolver();
+        Cursor result = cr.query(baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
+        if (result == null)
+            return res;
+
         int iID = result.getColumnIndex(Contacts._ID);
+        int iKey = result.getColumnIndex(ContactsContract.Data.LOOKUP_KEY);
         int iName = result.getColumnIndex(Contacts.DISPLAY_NAME);
         int iPhoto = result.getColumnIndex(Contacts.PHOTO_ID);
         int iStarred = result.getColumnIndex(Contacts.STARRED);
         CallContact.ContactBuilder builder = CallContact.ContactBuilder.getInstance();
-        
+
         while (result.moveToNext()) {
-            builder.startNewContact(result.getLong(iID), result.getString(iName), result.getLong(iPhoto));
+            long cid = result.getLong(iID);
+            builder.startNewContact(cid, result.getString(iKey), result.getString(iName), result.getLong(iPhoto));
             
-//            Cursor cPhones = getContext().getContentResolver().query(Phone.CONTENT_URI, CONTACTS_PHONES_PROJECTION,
-//                    Phone.CONTACT_ID + " =" + result.getLong(iID), null, null);
+            Cursor cPhones = cr.query(Phone.CONTENT_URI, CONTACTS_PHONES_PROJECTION, Phone.CONTACT_ID + " =" + cid, null, null);
+            if (cPhones != null) {
+                while (cPhones.moveToNext()) {
+                    builder.addPhoneNumber(cPhones.getString(cPhones.getColumnIndex(Phone.NUMBER)), cPhones.getInt(cPhones.getColumnIndex(Phone.TYPE)));
+                    Log.w(TAG,"Phone:"+cPhones.getString(cPhones.getColumnIndex(Phone.NUMBER)));
+                }
+                cPhones.close();
+            }
 
-//            while (cPhones.moveToNext()) {
-//                builder.addPhoneNumber(cPhones.getString(cPhones.getColumnIndex(Phone.NUMBER)), cPhones.getInt(cPhones.getColumnIndex(Phone.TYPE)));
-////                Log.i(TAG,"Phone:"+cPhones.getString(cPhones.getColumnIndex(Phone.NUMBER)));
-//            }
-//            cPhones.close();
-//
-//            Cursor cSip = getContext().getContentResolver().query(Phone.CONTENT_URI, CONTACTS_SIP_PROJECTION,
-//                    Phone.CONTACT_ID + "=" + result.getLong(iID), null, null);
-//
-//            while (cSip.moveToNext()) {
-//                builder.addSipNumber(cSip.getString(cSip.getColumnIndex(SipAddress.SIP_ADDRESS)), cSip.getInt(cSip.getColumnIndex(SipAddress.TYPE)));
-////                Log.i(TAG,"Phone:"+cSip.getString(cSip.getColumnIndex(SipAddress.SIP_ADDRESS)));
-//            }
-//            cSip.close();
+            //Cursor cSip = cr.query(Phone.CONTENT_URI, CONTACTS_SIP_PROJECTION, Phone.CONTACT_ID + "=" + cid, null, null);
+            Cursor cSip = cr.query(ContactsContract.Data.CONTENT_URI,
+                    CONTACTS_SIP_PROJECTION,
+                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "=?",
+                    new String[]{String.valueOf(cid), ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE}, null);
+            if (cSip != null) {
+                while (cSip.moveToNext()) {
+                    builder.addSipNumber(cSip.getString(cSip.getColumnIndex(SipAddress.SIP_ADDRESS)), cSip.getInt(cSip.getColumnIndex(SipAddress.TYPE)));
+                    Log.w(TAG, "SIP Phone for " + cid + " :" + cSip.getString(cSip.getColumnIndex(SipAddress.SIP_ADDRESS)));
+                }
+                cSip.close();
+            }
 
-            contacts.add(builder.build());
+            res.contacts.add(builder.build());
             if (result.getInt(iStarred) == 1) {
-                starred.add(builder.build());
+                res.starred.add(builder.build());
             }
            
-        }        
-        
+        }
         result.close();
-        Bundle toReturn = new Bundle();
-        
-       toReturn.putParcelableArrayList("Contacts", contacts);
-       toReturn.putParcelableArrayList("Starred", starred);
 
-        return toReturn;
+        return res;
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/loaders/HistoryLoader.java b/ring-android/app/src/main/java/cx/ring/loaders/HistoryLoader.java
index b6712ea..7606f2f 100644
--- a/ring-android/app/src/main/java/cx/ring/loaders/HistoryLoader.java
+++ b/ring-android/app/src/main/java/cx/ring/loaders/HistoryLoader.java
@@ -63,7 +63,7 @@
     @Override
     public ArrayList<HistoryEntry> loadInBackground() {
 
-        HashMap<String,HistoryEntry> historyEntries = new HashMap<String, HistoryEntry>();
+        HashMap<String,HistoryEntry> historyEntries = new HashMap<>();
 
         try {
             List<HistoryCall> list = historyManager.getAll();
@@ -77,11 +77,12 @@
                             ContactsContract.Contacts._ID + " = ?",
                             new String[]{String.valueOf(call.getContactID())}, null);
                     int iID = result.getColumnIndex(ContactsContract.Contacts._ID);
+                    int iKey = result.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
                     int iName = result.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
                     int iPhoto = result.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
 
                     if (result.moveToFirst()) {
-                        builder.startNewContact(result.getLong(iID), result.getString(iName), result.getLong(iPhoto));
+                        builder.startNewContact(result.getLong(iID), result.getString(iKey), result.getString(iName), result.getLong(iPhoto));
                         builder.addPhoneNumber(call.getNumber(), 0);
                         contact = builder.build();
                     } else {
diff --git a/ring-android/app/src/main/java/cx/ring/model/Bubble.java b/ring-android/app/src/main/java/cx/ring/model/Bubble.java
index 3cf6e8a..3387427 100644
--- a/ring-android/app/src/main/java/cx/ring/model/Bubble.java
+++ b/ring-android/app/src/main/java/cx/ring/model/Bubble.java
@@ -143,7 +143,7 @@
     }
 
     protected Bitmap getContactPhoto(Context context, CallContact contact, int size) {
-        if (contact.getPhoto_id() > 0) {
+        if (contact.getPhotoId() > 0) {
             return ContactPictureTask.loadContactPhoto(context.getContentResolver(), contact.getId());
         } else {
             return ContactPictureTask.decodeSampledBitmapFromResource(context.getResources(), R.drawable.ic_contact_picture, size, size);
diff --git a/ring-android/app/src/main/java/cx/ring/model/BubbleContact.java b/ring-android/app/src/main/java/cx/ring/model/BubbleContact.java
index e21f98a..7c0ce6e 100644
--- a/ring-android/app/src/main/java/cx/ring/model/BubbleContact.java
+++ b/ring-android/app/src/main/java/cx/ring/model/BubbleContact.java
@@ -38,7 +38,7 @@
     public SipCall associated_call;
 
     public BubbleContact(Context context, SipCall call, float x, float y, float size) {
-        super(context, call.getmContact(), x, y, size);
+        super(context, call.getContact(), x, y, size);
         associated_call = call;
     }
 
@@ -62,7 +62,7 @@
 
     @Override
     public String getName() {
-        return associated_call.getmContact().getmDisplayName();
+        return associated_call.getContact().getDisplayName();
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/model/BubblesView.java b/ring-android/app/src/main/java/cx/ring/model/BubblesView.java
index 8b465dd..890a2be 100644
--- a/ring-android/app/src/main/java/cx/ring/model/BubblesView.java
+++ b/ring-android/app/src/main/java/cx/ring/model/BubblesView.java
@@ -97,7 +97,7 @@
         SurfaceHolder holder = getHolder();

         holder.addCallback(this);

 

-        this.setZOrderOnTop(true); // necessary

+        //this.setZOrderOnTop(true); // necessary

         holder.setFormat(PixelFormat.TRANSLUCENT);

         // create thread only; it's started in surfaceCreated()

         createThread();

@@ -313,9 +313,9 @@
                     } else

                         canvas.drawBitmap(ic_bg, null, a.getBounds(showed * 2.f, b.getPos(), showed), action_paint);

                     canvas.drawBitmap(a.getBitmap(), null, a.getBounds(showed, b.getPos(), showed), null);

-                    float dist_raw = FloatMath.sqrt((b.pos.x - a.pos.x) * (b.pos.x - a.pos.x) + (b.pos.y - a.pos.y) * (b.pos.y - a.pos.y));

-                    float dist_min = a.radius + b.radius + bubbleActionTextDistMin;

-                    float dist = Math.max(0, dist_raw - dist_min);

+                    double dist_raw = Math.sqrt((b.pos.x - a.pos.x) * (b.pos.x - a.pos.x) + (b.pos.y - a.pos.y) * (b.pos.y - a.pos.y));

+                    double dist_min = a.radius + b.radius + bubbleActionTextDistMin;

+                    double dist = Math.max(0, dist_raw - dist_min);

                     if (actions.enabled && dist < dist_range) {

                         white_name_paint.setAlpha(255 - (int) (255 * dist / dist_range));

                         canvas.drawText(a.name, a.getBounds().centerX(), a.getBounds().centerY() - a.radius * 2.2f, white_name_paint);

@@ -343,7 +343,7 @@
             return true;

 

         if (action == MotionEvent.ACTION_UP) {

-            if (thread.suspendFlag) {

+            if (thread != null && thread.suspendFlag) {

                 Log.i(TAG, "Relaunch drawing thread");

                 thread.setPaused(false);

             }

@@ -354,7 +354,7 @@
                 }

             }

             dragging_bubble = false;

-        } else if (action != MotionEvent.ACTION_DOWN && !isDraggingBubble() && !thread.suspendFlag) {

+        } else if (action != MotionEvent.ACTION_DOWN && !isDraggingBubble() && thread != null && !thread.suspendFlag) {

             Log.i(TAG, "Not dragging thread should be stopped");

             thread.setPaused(true);

         }

diff --git a/ring-android/app/src/main/java/cx/ring/model/CallContact.java b/ring-android/app/src/main/java/cx/ring/model/CallContact.java
index c067a75..e11861c 100644
--- a/ring-android/app/src/main/java/cx/ring/model/CallContact.java
+++ b/ring-android/app/src/main/java/cx/ring/model/CallContact.java
@@ -32,6 +32,9 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import android.content.ContentResolver;
 import android.database.Cursor;
@@ -39,29 +42,70 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.ContactsContract.Profile;
+import android.support.annotation.NonNull;
+
+import cx.ring.client.ConversationActivity;
+import cx.ring.service.LocalService;
 
 public class CallContact implements Parcelable {
+    static public final Pattern ANGLE_BRACKETS_PATTERN = Pattern.compile("(?:[^<>]+<)?([^<>]+)>?\\s*");
+    public static final Pattern RING_ID_PATTERN = Pattern.compile("^\\s*(?:ring(?:[\\s\\:]+))?(\\p{XDigit}{40})(?:@ring\\.dht)?\\s*$", Pattern.CASE_INSENSITIVE);
 
     public static int DEFAULT_ID = 0;
 
     private long id;
+    private String key;
     private String mDisplayName;
     private long photo_id;
-    private ArrayList<Phone> phones, sip_phones;
+    private ArrayList<Phone> phones/*, sip_phones*/;
     private String mEmail;
     private boolean isUser;
-    private WeakReference<Bitmap> contact_photo = new WeakReference<Bitmap>(null);
+    private WeakReference<Bitmap> contact_photo = new WeakReference<>(null);
 
-    private CallContact(long cID, String displayName, long photoID, ArrayList<Phone> p, ArrayList<Phone> sip, String mail, boolean user) {
+    private CallContact(long cID, String k, String displayName, long photoID, ArrayList<Phone> p, String mail, boolean user) {
         id = cID;
+        key = k;
         mDisplayName = displayName;
         phones = p;
-        sip_phones = sip;
         mEmail = mail;
         photo_id = photoID;
         isUser = user;
     }
 
+    private static String nobracketsNumber(@NonNull String number) {
+        Matcher m = ANGLE_BRACKETS_PATTERN.matcher(number);
+        if (m.find())
+            return m.group(1);
+        return number;
+    }
+
+    public static String canonicalNumber(@NonNull String number) {
+        number = nobracketsNumber(number);
+        Matcher m = RING_ID_PATTERN.matcher(number);
+        if (m.find())
+            return "ring:"+m.group(1);
+        return number;
+    }
+
+    public ArrayList<String> getIds() {
+        ArrayList<String> ret = new ArrayList<>(1+phones.size());
+        if (id != -1)
+            ret.add("c:" + Long.toHexString(id));
+        for (Phone p : phones)
+            ret.add(canonicalNumber(p.getNumber()));
+        return ret;
+    }
+
+    public static long contactIdFromId(String id) {
+        if (!id.startsWith("c:"))
+            return -1;
+        try {
+            return Long.parseLong(id.substring(2), 16);
+        } catch (Exception e) {
+            return -1;
+        }
+    }
+
     public CallContact(Parcel in) {
         readFromParcel(in);
     }
@@ -70,15 +114,21 @@
         return id;
     }
 
-    public String getmDisplayName() {
-        return mDisplayName;
+    public String getDisplayName() {
+        if (!mDisplayName.isEmpty())
+            return mDisplayName;
+        if (!phones.isEmpty())
+            return phones.get(0).getNumber();
+        /*if (!sip_phones.isEmpty())
+            return sip_phones.get(0).getNumber();*/
+        return "";
     }
 
-    public long getPhoto_id() {
+    public long getPhotoId() {
         return photo_id;
     }
 
-    public void setPhoto_id(long photo_id) {
+    public void setPhotoId(long photo_id) {
         this.photo_id = photo_id;
     }
 
@@ -90,53 +140,56 @@
         this.phones = phones;
     }
 
-    public ArrayList<Phone> getSip_phones() {
-        return sip_phones;
-    }
-
-    public void setSip_phones(ArrayList<Phone> sip_phones) {
-        this.sip_phones = sip_phones;
-    }
-
-    public Phone getSipPhone() {
-        if (sip_phones.size() > 0) {
-            return sip_phones.get(0);
-        }
-        if (phones.size() > 0) {
-            return phones.get(0);
-        }
-        return null;
-    }
-
-    public String getmEmail() {
+    public String getEmail() {
         return mEmail;
     }
 
-    public void setmEmail(String mEmail) {
+    public void setEmail(String mEmail) {
         this.mEmail = mEmail;
     }
 
+    public boolean hasNumber(String number) {
+        if (number == null || number.isEmpty())
+            return false;
+        number = canonicalNumber(number);
+        for (Phone p : phones)
+            if (canonicalNumber(p.getNumber()).equals(number))
+                return true;
+        return false;
+    }
+
     @Override
     public String toString() {
         return mDisplayName;
     }
 
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public void setDisplayName(String displayName) {
+        this.mDisplayName = displayName;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
     public static class ContactBuilder {
 
         long contactID;
+        String key;
         String contactName;
         long contactPhoto;
         ArrayList<Phone> phones;
-        ArrayList<Phone> sip;
         String contactMail;
 
-        public ContactBuilder startNewContact(long id, String displayName, long photo_id) {
+        public ContactBuilder startNewContact(long id, String k, String displayName, long photo_id) {
             contactID = id;
-
+            key = k;
             contactName = displayName;
             contactPhoto = photo_id;
-            phones = new ArrayList<Phone>();
-            sip = new ArrayList<Phone>();
+            phones = new ArrayList<>();
             return this;
         }
 
@@ -146,12 +199,12 @@
         }
 
         public ContactBuilder addSipNumber(String num, int type) {
-            sip.add(new Phone(num, type));
+            phones.add(new Phone(num, type, NumberType.SIP));
             return this;
         }
 
         public CallContact build() {
-            return new CallContact(contactID, contactName, contactPhoto, phones, sip, contactMail, false);
+            return new CallContact(contactID, key, contactName, contactPhoto, phones, contactMail, false);
         }
 
         public static ContactBuilder getInstance() {
@@ -159,25 +212,30 @@
         }
 
         public static CallContact buildUnknownContact(String to) {
-            ArrayList<Phone> phones = new ArrayList<Phone>();
+            ArrayList<Phone> phones = new ArrayList<>();
             phones.add(new Phone(to, 0));
 
-            return new CallContact(-1, to, 0, phones, new ArrayList<CallContact.Phone>(), "", false);
+            return new CallContact(-1, null, to, 0, phones, "", false);
+        }
+        public static CallContact buildUnknownContact(String to, int type) {
+            ArrayList<Phone> phones = new ArrayList<>();
+            phones.add(new Phone(to, type));
+            return new CallContact(-1, null, to, 0, phones, "", false);
         }
 
         public static CallContact buildUserContact(ContentResolver cr) {
-            String[] mProjection = new String[] { Profile._ID, Profile.DISPLAY_NAME_PRIMARY, Profile.PHOTO_ID };
+            String[] mProjection = new String[] { Profile._ID, Profile.LOOKUP_KEY, Profile.DISPLAY_NAME_PRIMARY, Profile.PHOTO_ID };
             Cursor mProfileCursor = cr.query(Profile.CONTENT_URI, mProjection, null, null, null);
             CallContact result;
             if (mProfileCursor.getCount() > 0) {
                 mProfileCursor.moveToFirst();
+                String key = mProfileCursor.getString(mProfileCursor.getColumnIndex(Profile.LOOKUP_KEY));
                 String displayName = mProfileCursor.getString(mProfileCursor.getColumnIndex(Profile.DISPLAY_NAME_PRIMARY));
 
-                result = new CallContact(mProfileCursor.getLong(mProfileCursor.getColumnIndex(Profile._ID)), displayName,
-                        mProfileCursor.getLong(mProfileCursor.getColumnIndex(Profile.PHOTO_ID)), new ArrayList<Phone>(),
-                        new ArrayList<CallContact.Phone>(), "", true);
+                result = new CallContact(mProfileCursor.getLong(mProfileCursor.getColumnIndex(Profile._ID)), key, displayName,
+                        mProfileCursor.getLong(mProfileCursor.getColumnIndex(Profile.PHOTO_ID)), new ArrayList<Phone>(), "", true);
             } else {
-                result = new CallContact(-1, "Me", 0, new ArrayList<Phone>(), new ArrayList<CallContact.Phone>(), "", true);
+                result = new CallContact(-1, null, "Me", 0, new ArrayList<Phone>(), "", true);
             }
             mProfileCursor.close();
             return result;
@@ -193,26 +251,22 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeLong(id);
+        dest.writeString(key);
         dest.writeString(mDisplayName);
         dest.writeLong(photo_id);
         dest.writeTypedList(phones);
-
-        dest.writeTypedList(sip_phones);
-
         dest.writeString(mEmail);
         dest.writeByte((byte) (isUser ? 1 : 0));
 
     }
 
     private void readFromParcel(Parcel in) {
-
         id = in.readLong();
+        key = in.readString();
         mDisplayName = in.readString();
         photo_id = in.readLong();
-        phones = new ArrayList<CallContact.Phone>();
-        sip_phones = new ArrayList<CallContact.Phone>();
+        phones = new ArrayList<>();
         in.readTypedList(phones, Phone.CREATOR);
-        in.readTypedList(sip_phones, Phone.CREATOR);
         mEmail = in.readString();
         isUser = in.readByte() == 1;
     }
@@ -229,15 +283,48 @@
         }
     };
 
+    public enum NumberType {
+        UNKNOWN(0),
+        TEL(1),
+        SIP(2),
+        IP(2),
+        RING(3);
+
+        private final int type;
+        NumberType(int t) {
+            type = t;
+        }
+        private static final NumberType[] VALS = NumberType.values();
+        public static NumberType fromInteger(int _id)
+        {
+            for (NumberType v : VALS)
+                if (v.type == _id)
+                    return v;
+            return UNKNOWN;
+        }
+        /*public static NumberType guess(String num) {
+            String canon = canonicalNumber(num);
+            Matcher m = URI_NUMBER_REGEX.matcher(canon);
+
+            return UNKNOWN;
+        }*/
+    }
+
     public static class Phone implements Parcelable {
-
-        int type;
+        NumberType ntype;
         String number;
+        int category; // Home, work, custom etc.
 
-        public Phone(String num, int ty) {
-            type = ty;
+        public Phone(String num, int cat) {
+            ntype = NumberType.UNKNOWN;
+            category = cat;
             number = num;
         }
+        public Phone(String num, int cat, NumberType nty) {
+            ntype = nty;
+            number = num;
+            category = cat;
+        }
 
         public Phone(Parcel in) {
             readFromParcel(in);
@@ -250,13 +337,15 @@
 
         @Override
         public void writeToParcel(Parcel dest, int arg1) {
-            dest.writeInt(type);
+            dest.writeInt(ntype.type);
             dest.writeString(number);
+            dest.writeInt(category);
         }
 
         private void readFromParcel(Parcel in) {
-            type = in.readInt();
+            ntype = NumberType.fromInteger(in.readInt());
             number = in.readString();
+            category = in.readInt();
         }
 
         public static final Parcelable.Creator<Phone> CREATOR = new Parcelable.Creator<Phone>() {
@@ -271,12 +360,12 @@
             }
         };
 
-        public int getType() {
-            return type;
+        public NumberType getType() {
+            return ntype;
         }
 
         public void setType(int type) {
-            this.type = type;
+            this.ntype = NumberType.fromInteger(type);
         }
 
         public String getNumber() {
@@ -289,13 +378,12 @@
 
     }
 
-    public void addPhoneNumber(String tel, int type) {
-        phones.add(new Phone(tel, type));
+    public void addPhoneNumber(String tel, int car) {
+        phones.add(new Phone(tel, car));
 
     }
-
-    public void addSipNumber(String tel, int type) {
-        sip_phones.add(new Phone(tel, type));
+    public void addNumber(String tel, int cat, NumberType type) {
+        phones.add(new Phone(tel, cat, type));
 
     }
 
@@ -314,7 +402,7 @@
     }
 
     public void setPhoto(Bitmap externalBMP) {
-        contact_photo = new WeakReference<Bitmap>(externalBMP);
+        contact_photo = new WeakReference<>(externalBMP);
     }
 
     /**
diff --git a/ring-android/app/src/main/java/cx/ring/model/Conference.java b/ring-android/app/src/main/java/cx/ring/model/Conference.java
index db027f6..a604bb1 100644
--- a/ring-android/app/src/main/java/cx/ring/model/Conference.java
+++ b/ring-android/app/src/main/java/cx/ring/model/Conference.java
@@ -36,13 +36,20 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
 public class Conference implements Parcelable {
 
     private String id;
     private int mConfState;
     private ArrayList<SipCall> participants;
     private boolean recording;
-    private ArrayList<SipMessage> messages;
+    private ArrayList<TextMessage> messages;
+
+    public int notificationId;
+
+    private final static Random rand = new Random();
 
     public static String DEFAULT_ID = "-1";
 
@@ -54,13 +61,13 @@
         participants.remove(toRemove);
     }
 
-    public boolean useSecureLayer() {
+    /*public boolean useSecureLayer() {
         for(SipCall call : participants){
             if(call.getAccount().useSecureLayer())
                 return true;
         }
         return false;
-    }
+    }*/
 
     public interface state {
         int ACTIVE_ATTACHED = 0;
@@ -104,8 +111,8 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(id);
         out.writeInt(mConfState);
-        ArrayList<SipCall> normal_calls = new ArrayList<SipCall>();
-        ArrayList<SecureSipCall> secure_calls = new ArrayList<SecureSipCall>();
+        ArrayList<SipCall> normal_calls = new ArrayList<>();
+        ArrayList<SecureSipCall> secure_calls = new ArrayList<>();
 
         for(SipCall part : participants){
             if(part instanceof SecureSipCall)
@@ -117,6 +124,7 @@
         out.writeTypedList(normal_calls);
         out.writeByte((byte) (recording ? 1 : 0));
         out.writeTypedList(messages);
+        out.writeInt(notificationId);
     }
 
     public static final Parcelable.Creator<Conference> CREATOR = new Parcelable.Creator<Conference>() {
@@ -131,36 +139,38 @@
 
 
     private Conference(Parcel in) {
-        participants = new ArrayList<SipCall>();
+        participants = new ArrayList<>();
         id = in.readString();
         mConfState = in.readInt();
-        ArrayList<SecureSipCall> tmp = new ArrayList<SecureSipCall>();
+        ArrayList<SecureSipCall> tmp = new ArrayList<>();
         in.readTypedList(tmp, SecureSipCall.CREATOR);
         in.readTypedList(participants, SipCall.CREATOR);
         participants.addAll(tmp);
         recording = in.readByte() == 1;
-        messages = new ArrayList<SipMessage>();
-        in.readTypedList(messages, SipMessage.CREATOR);
+        messages = new ArrayList<>();
+        in.readTypedList(messages, TextMessage.CREATOR);
+        notificationId = in.readInt();
     }
 
     public Conference(SipCall call) {
         this(DEFAULT_ID);
         participants.add(call);
+        notificationId = rand.nextInt();
     }
 
     public Conference(String cID) {
         id = cID;
-        participants = new ArrayList<SipCall>();
+        participants = new ArrayList<>();
         recording = false;
-        messages = new ArrayList<SipMessage>();
+        messages = new ArrayList<>();
     }
 
     public Conference(Conference c) {
         id = c.id;
         mConfState = c.mConfState;
-        participants = new ArrayList<SipCall>(c.participants);
+        participants = new ArrayList<>(c.participants);
         recording = c.recording;
-        messages = new ArrayList<SipMessage>();
+        messages = new ArrayList<>();
     }
 
     public String getId() {
@@ -275,11 +285,11 @@
         return participants.size() == 1 && participants.get(0).isOngoing() || participants.size() > 1;
     }
 
-    public ArrayList<SipMessage> getMessages() {
+    public ArrayList<TextMessage> getMessages() {
         return messages;
     }
 
-    public void addSipMessage(SipMessage sipMessage) {
+    public void addSipMessage(TextMessage sipMessage) {
         messages.add(sipMessage);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/model/Conversation.java b/ring-android/app/src/main/java/cx/ring/model/Conversation.java
new file mode 100644
index 0000000..db311cd
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/model/Conversation.java
@@ -0,0 +1,232 @@
+package cx.ring.model;
+
+import android.database.ContentObservable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import cx.ring.history.HistoryCall;
+import cx.ring.history.HistoryEntry;
+import cx.ring.history.HistoryText;
+import cx.ring.model.account.Account;
+
+public class Conversation extends ContentObservable implements Parcelable
+{
+    static final String TAG = Conversation.class.getSimpleName();
+
+    public CallContact contact;
+    //private HistoryEntry history;
+    /** accountId -> histroy entries */
+    final private Map<String, HistoryEntry> history = new HashMap<>();
+
+    //private Conference current_call = null;
+    public final ArrayList<Conference> current_calls;
+
+    public String getLastNumberUsed(String accountID) {
+        HistoryEntry he = history.get(accountID);
+        if (he == null)
+            return null;
+        return he.getLastNumberUsed();
+    }
+
+    public Conference getConference(String id) {
+        for (Conference c : current_calls)
+            if (c.getId().contentEquals(id) || c.getCallById(id) != null)
+                return c;
+        return null;
+    }
+
+    public Pair<HistoryEntry, HistoryCall> findHistoryByCallId(String id) {
+        for (HistoryEntry e : history.values()) {
+            for (HistoryCall c : e.getCalls().values()) {
+                if (c.getCallId().equals(id))
+                    return new Pair<>(e, c);
+            }
+        }
+        return null;
+    }
+
+    public class ConversationElement {
+        public HistoryCall call = null;
+        public TextMessage text = null;
+        public ConversationElement(HistoryCall c) {
+            call = c;
+        }
+        public ConversationElement(TextMessage t) {
+            text = t;
+        }
+        public long getDate() {
+            if (text != null)
+                return text.getTimestamp();
+            else if (call != null)
+                return call.call_start;
+            return 0;
+        }
+    }
+
+    public Conversation(CallContact c) {
+        contact = c;
+        current_calls = new ArrayList<>();
+    }
+
+    public static final Creator<Conversation> CREATOR = new Creator<Conversation>() {
+        @Override
+        public Conversation createFromParcel(Parcel in) {
+            return new Conversation(in);
+        }
+
+        @Override
+        public Conversation[] newArray(int size) {
+            return new Conversation[size];
+        }
+    };
+
+    public CallContact getContact() {
+        return contact;
+    }
+
+    public Date getLastInteraction() {
+        if (!current_calls.isEmpty()) {
+            return new Date();
+        }
+        Date d = new Date(0);
+
+        //for (Map.Entry<String, HistoryEntry> e : history.entrySet()) {
+        for (HistoryEntry e : history.values()) {
+            Date nd = e.getLastInteraction();
+            if (d.compareTo(nd) < 0)
+                d = nd;
+        }
+        return d;
+    }
+
+    public void addHistoryCall(HistoryCall c) {
+        String accountId = c.getAccountID();
+        if (history.containsKey(accountId))
+            history.get(accountId).addHistoryCall(c, contact);
+        else {
+            HistoryEntry e = new HistoryEntry(accountId, contact);
+            e.addHistoryCall(c, contact);
+            history.put(accountId, e);
+        }
+    }
+    public void addTextMessage(TextMessage txt) {
+        if (txt.getCallId() != null && !txt.getCallId().isEmpty()) {
+            Conference conf = getConference(txt.getCallId());
+            if (conf == null)
+                return;
+            conf.addSipMessage(txt);
+        }// else {
+        if (txt.getContact() == null)
+            txt.setContact(contact);
+        String accountId = txt.getAccount();
+        if (history.containsKey(accountId))
+            history.get(accountId).addTextMessage(txt);
+        else {
+            HistoryEntry e = new HistoryEntry(accountId, contact);
+            e.addTextMessage(txt);
+            history.put(accountId, e);
+        }
+        //}
+    }
+
+    /*public HistoryEntry getHistory(String account_id) {
+        return history.get(account_id);
+    }*/
+
+    public ArrayList<ConversationElement> getHistory() {
+        ArrayList<ConversationElement> all = new ArrayList<>();
+        for (HistoryEntry e : history.values()) {
+            for (HistoryCall c : e.getCalls().values())
+                all.add(new ConversationElement(c));
+            for (TextMessage t : e.getTextMessages().values())
+                all.add(new ConversationElement(t));
+        }
+        Collections.sort(all, new Comparator<ConversationElement>() {
+            @Override
+            public int compare(ConversationElement lhs, ConversationElement rhs) {
+                return (int)((lhs.getDate() - rhs.getDate())/1000l);
+            }
+        });
+        return all;
+    }
+
+    public Set<String> getAccountsUsed() {
+        return history.keySet();
+    }
+
+    public String getLastAccountUsed() {
+        String last = null;
+        Date d = new Date(0);
+        for (Map.Entry<String, HistoryEntry> e : history.entrySet()) {
+            Date nd = e.getValue().getLastInteraction();
+            if (d.compareTo(nd) < 0) {
+                d = nd;
+                last = e.getKey();
+            }
+        }
+        return last;
+    }
+
+    public Conference getCurrentCall() {
+        if (current_calls.isEmpty())
+            return null;
+        return current_calls.get(0);
+    }
+    public void setCurrentCall(Conference c) {
+        current_calls.add(c);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(contact, flags);
+        //dest.writeParcelable(current_call, flags);
+        dest.writeList(current_calls);
+        dest.writeList(new ArrayList<>(history.values()));
+        dest.writeList(new ArrayList<>(history.keySet()));
+    }
+
+    protected Conversation(Parcel in) {
+        contact = in.readParcelable(CallContact.class.getClassLoader());
+        //current_call = in.readParcelable(Conference.class.getClassLoader());
+        current_calls = in.readArrayList(Conference.class.getClassLoader());
+
+        ArrayList<HistoryEntry> values = new ArrayList<>();
+        in.readList(values, HistoryEntry.class.getClassLoader());
+        ArrayList<String> keys = new ArrayList<>();
+        in.readList(keys, String.class.getClassLoader());
+        for (int i = 0; i < keys.size(); ++i)
+            history.put(keys.get(i), values.get(i));
+    }
+
+    public ArrayList<TextMessage> getTextMessages() {
+        ArrayList<TextMessage> texts = new ArrayList<>();
+        for (HistoryEntry h : history.values()) {
+            texts.addAll(h.getTextMessages().values());
+        }
+        Collections.sort(texts, new Comparator<TextMessage>() {
+            @Override
+            public int compare(TextMessage lhs, TextMessage rhs) {
+                return (int)((lhs.getTimestamp() - rhs.getTimestamp())/1000l);
+            }
+        });
+        return texts;
+    }
+
+}
diff --git a/ring-android/app/src/main/java/cx/ring/model/SecureSipCall.java b/ring-android/app/src/main/java/cx/ring/model/SecureSipCall.java
index c606cc1..8ca7ef1 100644
--- a/ring-android/app/src/main/java/cx/ring/model/SecureSipCall.java
+++ b/ring-android/app/src/main/java/cx/ring/model/SecureSipCall.java
@@ -55,10 +55,10 @@
 
     private boolean isInitialized;
 
-    public SecureSipCall(SipCall call) {
+    public SecureSipCall(SipCall call, String keyExchange) {
         super(call);
         isInitialized = false;
-        String keyExchange = getAccount().getSrtpDetails().getDetailString(AccountDetailSrtp.CONFIG_SRTP_KEY_EXCHANGE);
+        //String keyExchange = getAccount().getSrtpDetails().getDetailString(AccountDetailSrtp.CONFIG_SRTP_KEY_EXCHANGE);
         /*if (keyExchange.contentEquals("zrtp")) {
             mSecureLayerUsed = SecureLayer.ZRTP_LAYER;
         } else */if (keyExchange.contentEquals("sdes")) {
@@ -124,7 +124,7 @@
     }
 
     /*
-    * returns what state should be visible during call
+    * returns what State should be visible during call
     */
     public int displayModule() {
         /*if (isInitialized) {
diff --git a/ring-android/app/src/main/java/cx/ring/model/SipCall.java b/ring-android/app/src/main/java/cx/ring/model/SipCall.java
index 5524f20..0aa9c51 100644
--- a/ring-android/app/src/main/java/cx/ring/model/SipCall.java
+++ b/ring-android/app/src/main/java/cx/ring/model/SipCall.java
@@ -35,7 +35,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
-import cx.ring.model.account.Account;
 
 public class SipCall implements Parcelable {
 
@@ -43,24 +42,34 @@
     public static String ACCOUNT = "account";
     public static String CONTACT = "contact";
     public static String TYPE = "type";
-    public static String STATE = "state";
+    public static String STATE = "State";
+    public static String NUMBER = "number";
 
     private static final String TAG = SipCall.class.getSimpleName();
 
     private String mCallID = "";
-    private Account mAccount = null;
+    private String mAccount = "";
     private CallContact mContact = null;
+    private String mNumber = "";
     private boolean isRecording = false;
     private long timestampStart_ = 0;
     private long timestampEnd_ = 0;
 
     private int mCallType;
-    private int mCallState = state.CALL_STATE_NONE;
+    private int mCallState = State.NONE;
+
+    public SipCall(String id, String account, String number, int direction) {
+        mCallID = id;
+        mAccount = account;
+        mNumber = number;
+        mCallType = direction;
+    }
 
     public SipCall(SipCall call) {
         mCallID = call.mCallID;
         mAccount = call.mAccount;
         mContact = call.mContact;
+        mNumber = call.mNumber;
         isRecording = call.isRecording;
         timestampStart_ = call.timestampStart_;
         timestampEnd_ = call.timestampEnd_;
@@ -75,10 +84,10 @@
      */
 
     protected SipCall(Parcel in) {
-
         mCallID = in.readString();
-        mAccount = in.readParcelable(Account.class.getClassLoader());
+        mAccount = in.readString();
         mContact = in.readParcelable(CallContact.class.getClassLoader());
+        mNumber = in.readString();
         isRecording = in.readByte() == 1;
         mCallType = in.readInt();
         mCallState = in.readInt();
@@ -88,14 +97,11 @@
 
     public SipCall(Bundle args) {
         mCallID = args.getString(ID);
-        mAccount = args.getParcelable(ACCOUNT);
+        mAccount = args.getString(ACCOUNT);
         mCallType = args.getInt(TYPE);
         mCallState = args.getInt(STATE);
         mContact = args.getParcelable(CONTACT);
-    }
-
-    public long getTimestampEnd_() {
-        return timestampEnd_;
+        mNumber = args.getString(NUMBER);
     }
 
     public String getRecordPath() {
@@ -109,29 +115,29 @@
     public Bundle getBundle() {
         Bundle args = new Bundle();
         args.putString(SipCall.ID, mCallID);
-        args.putParcelable(SipCall.ACCOUNT, mAccount);
+        args.putString(SipCall.ACCOUNT, mAccount);
         args.putInt(SipCall.STATE, mCallState);
         args.putInt(SipCall.TYPE, mCallType);
         args.putParcelable(SipCall.CONTACT, mContact);
+        args.putString(SipCall.NUMBER, mNumber);
         return args;
     }
 
-
-    public interface direction {
-        int CALL_TYPE_INCOMING = 1;
-        int CALL_TYPE_OUTGOING = 2;
+    public interface Direction {
+        int INCOMING = 1;
+        int OUTGOING = 2;
     }
 
-    public interface state {
-        int CALL_STATE_NONE = 0;
-        int CALL_STATE_CONNECTING = 1;
-        int CALL_STATE_RINGING = 2;
-        int CALL_STATE_CURRENT = 3;
-        int CALL_STATE_HUNGUP = 4;
-        int CALL_STATE_BUSY = 5;
-        int CALL_STATE_FAILURE = 6;
-        int CALL_STATE_HOLD = 7;
-        int CALL_STATE_UNHOLD = 8;
+    public interface State {
+        int NONE = 0;
+        int CONNECTING = 1;
+        int RINGING = 2;
+        int CURRENT = 3;
+        int HUNGUP = 4;
+        int BUSY = 5;
+        int FAILURE = 6;
+        int HOLD = 7;
+        int UNHOLD = 8;
     }
 
     @Override
@@ -141,11 +147,10 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-
         out.writeString(mCallID);
-        out.writeParcelable(mAccount, 0);
-
+        out.writeString(mAccount);
         out.writeParcelable(mContact, 0);
+        out.writeString(mNumber);
         out.writeByte((byte) (isRecording ? 1 : 0));
         out.writeInt(mCallType);
         out.writeInt(mCallState);
@@ -171,32 +176,36 @@
         return mCallID;
     }
 
-    public long getTimestampStart_() {
+    public long getTimestampStart() {
         return timestampStart_;
     }
 
-    public void setTimestampStart_(long timestampStart_) {
-        this.timestampStart_ = timestampStart_;
+    public void setTimestampStart(long timestampStart) {
+        this.timestampStart_ = timestampStart;
     }
 
-    public void setTimestampEnd_(long timestampEnd_) {
-        this.timestampEnd_ = timestampEnd_;
+    public long getTimestampEnd() {
+        return timestampEnd_;
     }
 
-    public void setAccount(Account account) {
+    public void setTimestampEnd(long timestampEnd) {
+        this.timestampEnd_ = timestampEnd;
+    }
+
+    public void setAccount(String account) {
         mAccount = account;
     }
 
-    public Account getAccount() {
+    public String getAccount() {
         return mAccount;
     }
 
     public String getCallTypeString() {
         switch (mCallType) {
-            case direction.CALL_TYPE_INCOMING:
-                return "CALL_TYPE_INCOMING";
-            case direction.CALL_TYPE_OUTGOING:
-                return "CALL_TYPE_OUTGOING";
+            case Direction.INCOMING:
+                return "INCOMING";
+            case Direction.OUTGOING:
+                return "OUTGOING";
             default:
                 return "CALL_TYPE_UNDETERMINED";
         }
@@ -206,37 +215,49 @@
         mCallState = callState;
     }
 
-    public CallContact getmContact() {
+    public void setContact(CallContact c) {
+        mContact = c;
+    }
+
+    public CallContact getContact() {
         return mContact;
     }
 
+    public void setNumber(String n) {
+        mNumber = n;
+    }
+
+    public String getNumber() {
+        return mNumber;
+    }
+
     public String getCallStateString() {
 
         String text_state;
 
         switch (mCallState) {
-            case state.CALL_STATE_NONE:
+            case State.NONE:
                 text_state = "NONE";
                 break;
-            case state.CALL_STATE_RINGING:
+            case State.RINGING:
                 text_state = "RINGING";
                 break;
-            case state.CALL_STATE_CURRENT:
+            case State.CURRENT:
                 text_state = "CURRENT";
                 break;
-            case state.CALL_STATE_HUNGUP:
+            case State.HUNGUP:
                 text_state = "HUNGUP";
                 break;
-            case state.CALL_STATE_BUSY:
+            case State.BUSY:
                 text_state = "BUSY";
                 break;
-            case state.CALL_STATE_FAILURE:
+            case State.FAILURE:
                 text_state = "FAILURE";
                 break;
-            case state.CALL_STATE_HOLD:
+            case State.HOLD:
                 text_state = "HOLD";
                 break;
-            case state.CALL_STATE_UNHOLD:
+            case State.UNHOLD:
                 text_state = "UNHOLD";
                 break;
             default:
@@ -256,7 +277,7 @@
 
     public void printCallInfo() {
         Log.i(TAG, "CallInfo: CallID: " + mCallID);
-        Log.i(TAG, "          AccountID: " + mAccount.getAccountID());
+        Log.i(TAG, "          AccountID: " + mAccount);
         Log.i(TAG, "          CallState: " + mCallState);
         Log.i(TAG, "          CallType: " + mCallType);
     }
@@ -270,29 +291,29 @@
     }
 
     public boolean isOutGoing() {
-        return mCallType == direction.CALL_TYPE_OUTGOING;
+        return mCallType == Direction.OUTGOING;
     }
 
     public boolean isRinging() {
-        return mCallState == state.CALL_STATE_RINGING || mCallState == state.CALL_STATE_NONE;
+        return mCallState == State.RINGING || mCallState == State.NONE;
     }
 
     public boolean isIncoming() {
-        return mCallType == direction.CALL_TYPE_INCOMING;
+        return mCallType == Direction.INCOMING;
     }
 
     public boolean isOngoing() {
-        return !(mCallState == state.CALL_STATE_RINGING || mCallState == state.CALL_STATE_NONE || mCallState == state.CALL_STATE_FAILURE
-                || mCallState == state.CALL_STATE_BUSY || mCallState == state.CALL_STATE_HUNGUP);
+        return !(mCallState == State.RINGING || mCallState == State.NONE || mCallState == State.FAILURE
+                || mCallState == State.BUSY || mCallState == State.HUNGUP);
 
     }
 
     public boolean isOnHold() {
-        return mCallState == state.CALL_STATE_HOLD;
+        return mCallState == State.HOLD;
     }
 
     public boolean isCurrent() {
-        return mCallState == state.CALL_STATE_CURRENT;
+        return mCallState == State.CURRENT;
     }
 
 
diff --git a/ring-android/app/src/main/java/cx/ring/model/SipMessage.aidl b/ring-android/app/src/main/java/cx/ring/model/SipMessage.aidl
deleted file mode 100644
index 0729146..0000000
--- a/ring-android/app/src/main/java/cx/ring/model/SipMessage.aidl
+++ /dev/null
@@ -1,4 +0,0 @@
-package cx.ring.model;
-
-
-parcelable SipMessage;
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/model/SipMessage.java b/ring-android/app/src/main/java/cx/ring/model/SipMessage.java
deleted file mode 100644
index f8a43cc..0000000
--- a/ring-android/app/src/main/java/cx/ring/model/SipMessage.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
- *
- *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
- *
- *  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, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Additional permission under GNU GPL version 3 section 7:
- *
- *  If you modify this program, or any covered work, by linking or
- *  combining it with the OpenSSL project's OpenSSL library (or a
- *  modified version of that library), containing parts covered by the
- *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
- *  grants you additional permission to convey the resulting work.
- *  Corresponding Source for a non-source form of such a combination
- *  shall include the source code for the parts of OpenSSL used as well
- *  as that of the covered work.
- */
-package cx.ring.model;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class SipMessage implements Parcelable {
-    public boolean left;
-    public String comment;
-
-    public SipMessage(boolean left, String comment) {
-        super();
-        this.left = left;
-        this.comment = comment;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeByte((byte) (left ? 1 : 0));
-        out.writeString(comment);
-    }
-
-    public static final Parcelable.Creator<SipMessage> CREATOR = new Parcelable.Creator<SipMessage>() {
-        public SipMessage createFromParcel(Parcel in) {
-            return new SipMessage(in);
-        }
-
-        public SipMessage[] newArray(int size) {
-            return new SipMessage[size];
-        }
-    };
-
-    private SipMessage(Parcel in) {
-        left = (in.readByte() == 1);
-        comment = in.readString();
-    }
-
-}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/model/TextMessage.aidl b/ring-android/app/src/main/java/cx/ring/model/TextMessage.aidl
new file mode 100644
index 0000000..1af4f25
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/model/TextMessage.aidl
@@ -0,0 +1,4 @@
+package cx.ring.model;
+
+
+parcelable TextMessage;
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/model/TextMessage.java b/ring-android/app/src/main/java/cx/ring/model/TextMessage.java
new file mode 100644
index 0000000..e7d44df
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/model/TextMessage.java
@@ -0,0 +1,294 @@
+/*
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
+ *
+ *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux>
+ *          Alexandre Savard <alexandre.savard@gmail.com>
+ *
+ *  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, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+package cx.ring.model;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import cx.ring.history.HistoryText;
+
+public class TextMessage implements Parcelable {
+
+    public static String ID = "id";
+    public static String ACCOUNT = "account";
+    public static String CONTACT = "contact";
+    public static String NUMBER = "number";
+    public static String CALL = "call";
+    public static String TYPE = "type";
+    public static String STATE = "State";
+    public static String MESSAGE = "message";
+    public static String TIME = "time";
+
+    private static final String TAG = TextMessage.class.getSimpleName();
+
+    private String mID = "";
+    private String mAccount = null;
+    private CallContact mContact = null;
+    private String mNumber = null;
+    private long mTimestamp = 0;
+
+    private int mType;
+    private int mState = state.NONE;
+    private String mMessage;
+    private String mCallID = "";
+
+    public TextMessage(TextMessage msg) {
+        mID = msg.mID;
+        mAccount = msg.mAccount;
+        mContact = msg.mContact;
+        mNumber = msg.mNumber;
+        mTimestamp = msg.mTimestamp;
+        mType = msg.mType;
+        mState = msg.mState;
+        mMessage = msg.mMessage;
+        mCallID = msg.mCallID;
+    }
+
+    /**
+     * *********************
+     * Construtors
+     * *********************
+     */
+
+    /*public TextMessage(String account, String number, String message, boolean in) {
+        mAccount = account;
+        mNumber = number;
+        mMessage = message;
+        mTimestamp = System.currentTimeMillis();
+        mType = in ? direction.INCOMING : direction.OUTGOING;
+    }*/
+
+    public TextMessage(boolean in, String message) {
+        mMessage = message;
+        mType = in ? direction.INCOMING : direction.OUTGOING;
+        mTimestamp = System.currentTimeMillis();
+    }
+
+    public TextMessage(boolean in, String message, String number, String callid, String account) {
+        mAccount = account;
+        mNumber = number;
+        mMessage = message;
+        mTimestamp = System.currentTimeMillis();
+        mCallID = callid;
+        mType = in ? direction.INCOMING : direction.OUTGOING;
+    }
+
+    public TextMessage(HistoryText h) {
+        mID = h.id;
+        mAccount = h.getAccountID();
+        mNumber = h.getNumber();
+        mMessage = h.getMessage();
+        mTimestamp = h.getDate().getTime();
+        mType = h.isIncoming() ? direction.INCOMING : direction.OUTGOING;
+        mCallID = h.getCallId();
+    }
+
+    protected TextMessage(Parcel in) {
+        mID = in.readString();
+        mAccount = in.readString();
+        mContact = in.readParcelable(CallContact.class.getClassLoader());
+        mNumber = in.readString();
+        mCallID = in.readString();
+        mType = in.readInt();
+        mState = in.readInt();
+        mTimestamp = in.readLong();
+        mMessage = in.readString();
+    }
+
+    public TextMessage(Bundle args) {
+        mID = args.getString(ID);
+        mAccount = args.getParcelable(ACCOUNT);
+        mNumber = args.getString(NUMBER);
+        mCallID = args.getString(CALL);
+        mType = args.getInt(TYPE);
+        mState = args.getInt(STATE);
+        mContact = args.getParcelable(CONTACT);
+        mMessage = args.getString(MESSAGE);
+        mTimestamp = args.getLong(TIME);
+    }
+
+    public String getRecordPath() {
+        return "";
+    }
+
+    public int getCallType() {
+        return mType;
+    }
+
+    public Bundle getBundle() {
+        Bundle args = new Bundle();
+        args.putString(ID, mID);
+        args.putString(ACCOUNT, mAccount);
+        args.putString(NUMBER, mNumber);
+        args.putString(CALL, mCallID);
+        args.putInt(STATE, mState);
+        args.putInt(TYPE, mType);
+        args.putParcelable(CONTACT, mContact);
+        args.putString(MESSAGE, mMessage);
+        args.putLong(TIME, mTimestamp);
+        return args;
+    }
+
+    public String getMessage() {
+        return mMessage;
+    }
+
+    public void setContact(CallContact contact) {
+        mContact = contact;
+    }
+
+    public void setCallId(String callId) {
+        this.mCallID = callId;
+    }
+
+    public String getCallId() {
+        return mCallID;
+    }
+
+    public void setNumber(String number) {
+        this.mNumber = number;
+    }
+
+    public interface direction {
+        int INCOMING = 1;
+        int OUTGOING = 2;
+    }
+
+    public interface state {
+        int NONE = 0;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mID);
+        out.writeString(mAccount);
+        out.writeParcelable(mContact, 0);
+        out.writeString(mNumber);
+        out.writeString(mCallID);
+        out.writeInt(mType);
+        out.writeInt(mState);
+        out.writeLong(mTimestamp);
+        out.writeString(mMessage);
+    }
+
+    public static final Creator<TextMessage> CREATOR = new Creator<TextMessage>() {
+        public TextMessage createFromParcel(Parcel in) {
+            return new TextMessage(in);
+        }
+
+        public TextMessage[] newArray(int size) {
+            return new TextMessage[size];
+        }
+    };
+
+    public void setID(String id) {
+        mID = id;
+    }
+
+    public String getId() {
+        return mID;
+    }
+
+    public long getTimestamp() {
+        return mTimestamp;
+    }
+
+    public void setTimestamp(long timestamp) {
+        this.mTimestamp = timestamp;
+    }
+
+    public void setAccount(String account) {
+        mAccount = account;
+    }
+
+    public String getAccount() {
+        return mAccount;
+    }
+
+    public String getTypeString() {
+        switch (mType) {
+            case direction.INCOMING:
+                return "INCOMING";
+            case direction.OUTGOING:
+                return "OUTGOING";
+            default:
+                return "UNDETERMINED";
+        }
+    }
+
+    public void setState(int callState) {
+        mState = callState;
+    }
+
+    public CallContact getContact() {
+        return mContact;
+    }
+
+    public String getNumber() {
+        return mNumber;
+    }
+
+    public String getStateString() {
+        String text_state;
+        switch (mState) {
+            case state.NONE:
+                text_state = "NONE";
+                break;
+            default:
+                text_state = "NULL";
+        }
+        return text_state;
+    }
+
+    /**
+     * Compare sip calls based on call ID
+     */
+    @Override
+    public boolean equals(Object c) {
+        return c instanceof TextMessage && ((TextMessage) c).mID.contentEquals((mID));
+    }
+
+    public boolean isOutgoing() {
+        return mType == direction.OUTGOING;
+    }
+
+    public boolean isIncoming() {
+        return mType == direction.INCOMING;
+    }
+
+}
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/Account.java b/ring-android/app/src/main/java/cx/ring/model/account/Account.java
index 0f938c1..4c05299 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/Account.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/Account.java
@@ -57,10 +57,13 @@
         advancedDetails = new AccountDetailAdvanced(details);
         srtpDetails = new AccountDetailSrtp(details);
         tlsDetails = new AccountDetailTls(details);
-        volatileDetails = new AccountDetailVolatile(volatile_details);
-        credentialsDetails = new ArrayList<>();
-        for (int i = 0; i < credentials.size(); ++i) {
-            credentialsDetails.add(new AccountCredentials(credentials.get(i)));
+        if (volatile_details != null)
+            volatileDetails = new AccountDetailVolatile(volatile_details);
+        if (credentials != null) {
+            credentialsDetails = new ArrayList<>();
+            for (int i = 0; i < credentials.size(); ++i) {
+                credentialsDetails.add(new AccountCredentials(credentials.get(i)));
+            }
         }
     }
 
@@ -84,8 +87,8 @@
         return volatileDetails.getDetailString(AccountDetailVolatile.CONFIG_ACCOUNT_REGISTRATION_STATUS);
     }
 
-    public void setRegistered_state(String registered_state, int code) {
-        Log.i(TAG, "setRegistered_state " + registered_state + " " + code);
+    public void setRegistrationState(String registered_state, int code) {
+        Log.i(TAG, "setRegistrationState " + registered_state + " " + code);
         volatileDetails.setDetailString(AccountDetailVolatile.CONFIG_ACCOUNT_REGISTRATION_STATUS, registered_state);
         volatileDetails.setDetailString(AccountDetailVolatile.CONFIG_ACCOUNT_REGISTRATION_STATE_CODE, Integer.toString(code));
     }
@@ -141,7 +144,7 @@
         advancedDetails = new AccountDetailAdvanced((HashMap<String, String>) in.readSerializable());
         srtpDetails = new AccountDetailSrtp((HashMap<String, String>) in.readSerializable());
         tlsDetails = new AccountDetailTls((HashMap<String, String>) in.readSerializable());
-        credentialsDetails = new ArrayList<AccountCredentials>();
+        credentialsDetails = new ArrayList<>();
         int cred_count = in.readInt();
         for (int i = 0; i < cred_count; ++i) {
             credentialsDetails.add(new AccountCredentials((HashMap<String, String>) in.readSerializable()));
@@ -202,7 +205,7 @@
     }
 
     public HashMap<String, String> getDetails() {
-        HashMap<String, String> results = new HashMap<String, String>();
+        HashMap<String, String> results = new HashMap<>();
 
         results.putAll(basicDetails.getDetailsHashMap());
         results.putAll(advancedDetails.getDetailsHashMap());
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetail.java b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetail.java
index 54fce72..9ec2ef2 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetail.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetail.java
@@ -26,10 +26,12 @@
 
 public interface AccountDetail {
 
-    public static final String TRUE_STR = "true";
-    public static final String FALSE_STR = "false";
+    String TAG = AccountDetail.class.getSimpleName();
 
-    public static class PreferenceEntry {
+    String TRUE_STR = "true";
+    String FALSE_STR = "false";
+
+    class PreferenceEntry {
         public String mKey;
         public boolean isTwoState;
         public String mValue;
@@ -47,20 +49,19 @@
         }
 
         public boolean isChecked() {
-            return mValue.contentEquals("true");
+            return mValue.contentEquals(TRUE_STR);
         }
     }
 
-    public static final String TAG = "PreferenceHashMap";
 
-    public ArrayList<PreferenceEntry> getDetailValues();
+    ArrayList<PreferenceEntry> getDetailValues();
 
-    public ArrayList<String> getValuesOnly();
+    ArrayList<String> getValuesOnly();
 
-    public HashMap<String, String> getDetailsHashMap();
+    HashMap<String, String> getDetailsHashMap();
 
-    public String getDetailString(String key);
+    String getDetailString(String key);
 
-    public void setDetailString(String key, String newValue);
+    void setDetailString(String key, String newValue);
 
 }
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailAdvanced.java b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailAdvanced.java
index 5875505..0691d16 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailAdvanced.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailAdvanced.java
@@ -22,8 +22,11 @@
 package cx.ring.model.account;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 import android.util.Log;
 
@@ -51,12 +54,26 @@
     public static final String CONFIG_AUDIO_PORT_MIN = "Account.audioPortMin";
     public static final String CONFIG_AUDIO_PORT_MAX = "Account.audioPortMax";
 
+    private static final Set<String> CONFIG_KEYS = new HashSet<>(Arrays.asList(
+            CONFIG_ACCOUNT_MAILBOX,
+            CONFIG_ACCOUNT_REGISTRATION_EXPIRE,
+            CONFIG_CREDENTIAL_NUMBER,
+            CONFIG_ACCOUNT_DTMF_TYPE,
+            CONFIG_RINGTONE_PATH, CONFIG_RINGTONE_ENABLED,
+            CONFIG_KEEP_ALIVE_ENABLED,
+            CONFIG_LOCAL_INTERFACE, CONFIG_PUBLISHED_SAMEAS_LOCAL, CONFIG_LOCAL_PORT,
+            CONFIG_PUBLISHED_PORT, CONFIG_PUBLISHED_ADDRESS,
+            CONFIG_STUN_SERVER, CONFIG_STUN_ENABLE,
+            CONFIG_AUDIO_PORT_MIN, CONFIG_AUDIO_PORT_MAX));
+
     private ArrayList<AccountDetail.PreferenceEntry> privateArray;
 
     public AccountDetailAdvanced(Map<String, String> pref) {
-        privateArray = new ArrayList<AccountDetail.PreferenceEntry>();
+        privateArray = new ArrayList<>();
 
         for (String key : pref.keySet()) {
+            if (!CONFIG_KEYS.contains(key))
+                continue;
             PreferenceEntry p = new PreferenceEntry(key);
             p.mValue = pref.get(key);
 
@@ -75,7 +92,7 @@
     }
 
     public ArrayList<String> getValuesOnly() {
-        ArrayList<String> valueList = new ArrayList<String>();
+        ArrayList<String> valueList = new ArrayList<>();
 
         for (AccountDetail.PreferenceEntry p : privateArray) {
             Log.i(TAG, "" + p.mValue);
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailBasic.java b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailBasic.java
index 6e95f12..9170ed4 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailBasic.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailBasic.java
@@ -45,10 +45,25 @@
     public static final String CONFIG_ACCOUNT_ENABLE = "Account.enable";
     public static final String CONFIG_PRESENCE_ENABLE = "Account.presenceEnabled";
 
+    public static final String ACCOUNT_TYPE_RING = "RING";
+    public static final String ACCOUNT_TYPE_SIP = "SIP";
+    public static final String ACCOUNT_TYPE_IAX = "IAX";
+
     private ArrayList<AccountDetail.PreferenceEntry> privateArray;
 
+    public String getAlias() {
+        return getDetailString(CONFIG_ACCOUNT_ALIAS);
+    }
+    public String getUsername() {
+        return getDetailString(CONFIG_ACCOUNT_USERNAME);
+    }
+    public String getHostname() {
+        return getDetailString(CONFIG_ACCOUNT_HOSTNAME);
+    }
+
+
     public AccountDetailBasic(Map<String, String> pref) {
-        privateArray = new ArrayList<AccountDetail.PreferenceEntry>();
+        privateArray = new ArrayList<>();
 
         for (String key : pref.keySet()) {
             PreferenceEntry p = new PreferenceEntry(key);
@@ -66,7 +81,7 @@
     }
 
     public ArrayList<String> getValuesOnly() {
-        ArrayList<String> valueList = new ArrayList<String>();
+        ArrayList<String> valueList = new ArrayList<>();
 
         for (AccountDetail.PreferenceEntry p : privateArray) {
             Log.i(TAG, "" + p.mValue);
@@ -77,7 +92,7 @@
     }
 
     public HashMap<String, String> getDetailsHashMap() {
-        HashMap<String, String> map = new HashMap<String, String>();
+        HashMap<String, String> map = new HashMap<>();
 
         for (AccountDetail.PreferenceEntry p : privateArray) {
             map.put(p.mKey, p.mValue);
@@ -100,13 +115,14 @@
     }
 
     public void setDetailString(String key, String newValue) {
-        for (int i = 0; i < privateArray.size(); ++i) {
-            PreferenceEntry p = privateArray.get(i);
+        for (PreferenceEntry p : privateArray) {
             if (p.mKey.equals(key)) {
-                privateArray.get(i).mValue = newValue;
+                p.mValue = newValue;
+                Log.w(TAG, "setDetailString " + key + " -> " + newValue);
+                //return;
             }
         }
-
+        Log.w(TAG, "setDetailString FAIL" + key + " -> " + newValue);
     }
 
 }
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailSrtp.java b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailSrtp.java
index a709423..81d1bc7 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailSrtp.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailSrtp.java
@@ -41,7 +41,7 @@
     private ArrayList<AccountDetail.PreferenceEntry> privateArray;
 
     public static ArrayList<AccountDetail.PreferenceEntry> getPreferenceEntries() {
-        ArrayList<AccountDetail.PreferenceEntry> preference = new ArrayList<AccountDetail.PreferenceEntry>();
+        ArrayList<AccountDetail.PreferenceEntry> preference = new ArrayList<>();
 
         preference.add(new PreferenceEntry(CONFIG_SRTP_ENABLE, true));
         preference.add(new PreferenceEntry(CONFIG_SRTP_KEY_EXCHANGE, false));
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailTls.java b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailTls.java
index 595f9d8..9ebfa24 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailTls.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/AccountDetailTls.java
@@ -46,7 +46,7 @@
     private ArrayList<AccountDetail.PreferenceEntry> privateArray;
 
     public static ArrayList<AccountDetail.PreferenceEntry> getPreferenceEntries() {
-        ArrayList<AccountDetail.PreferenceEntry> preference = new ArrayList<AccountDetail.PreferenceEntry>();
+        ArrayList<AccountDetail.PreferenceEntry> preference = new ArrayList<>();
 
         preference.add(new PreferenceEntry(CONFIG_TLS_LISTENER_PORT));
         preference.add(new PreferenceEntry(CONFIG_TLS_ENABLE, true));
diff --git a/ring-android/app/src/main/java/cx/ring/service/CallManagerCallBack.java b/ring-android/app/src/main/java/cx/ring/service/CallManagerCallBack.java
index 66bc4ae..aaf7480 100644
--- a/ring-android/app/src/main/java/cx/ring/service/CallManagerCallBack.java
+++ b/ring-android/app/src/main/java/cx/ring/service/CallManagerCallBack.java
@@ -1,28 +1,33 @@
 package cx.ring.service;
 
+import android.support.v4.app.NotificationCompat;
+import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.Log;
+
+import cx.ring.R;
 import cx.ring.client.CallActivity;
+import cx.ring.history.HistoryText;
+import cx.ring.model.CallContact;
+import cx.ring.model.TextMessage;
 import cx.ring.model.account.Account;
+import cx.ring.model.account.AccountDetailSrtp;
 import cx.ring.utils.SwigNativeConverter;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Map;
 
-import cx.ring.model.CallContact;
 import cx.ring.model.Conference;
 import cx.ring.model.SecureSipCall;
 import cx.ring.model.SipCall;
-import cx.ring.model.SipMessage;
 
 public class CallManagerCallBack extends Callback {
 
     private static final String TAG = "CallManagerCallBack";
     private SipService mService;
 
-    static public final String CALL_STATE_CHANGED = "call-state-changed";
+    static public final String CALL_STATE_CHANGED = "call-State-changed";
     static public final String INCOMING_CALL = "incoming-call";
     static public final String INCOMING_TEXT = "incoming-text";
     static public final String CONF_CREATED = "conf_created";
@@ -46,11 +51,12 @@
 
     @Override
     public void callStateChanged(String callID, String newState, int detail_code) {
-        Log.d(TAG, "on_call_state_changed : (" + callID + ", " + newState + ")");
+        Log.w(TAG, "on_call_state_changed : (" + callID + ", " + newState + ")");
 
         Conference toUpdate = mService.findConference(callID);
 
         if (toUpdate == null) {
+            Log.w(TAG, "callStateChanged: can't find call " + callID);
             return;
         }
 
@@ -59,38 +65,52 @@
         intent.putExtra("State", newState);
         intent.putExtra("DetailCode", detail_code);
 
-        if (newState.equals("RINGING")) {
-            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_RINGING);
-        } else if (newState.equals("CURRENT")) {
-            if (toUpdate.isRinging()) {
-                toUpdate.getCallById(callID).setTimestampStart_(System.currentTimeMillis());
-            }
-            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_CURRENT);
-        } else if (newState.equals("HUNGUP")) {
-            Log.d(TAG, "Hanging up " + callID);
-            SipCall call = toUpdate.getCallById(callID);
-            if (!toUpdate.hasMultipleParticipants()) {
-                if (toUpdate.isRinging() && toUpdate.isIncoming()) {
-                    mService.mNotificationManager.publishMissedCallNotification(mService.getConferences().get(callID));
+        if (toUpdate.isRinging() && !newState.equals("RINGING")) {
+            Log.w(TAG, "Setting call start date " + callID);
+            toUpdate.getCallById(callID).setTimestampStart(System.currentTimeMillis());
+        }
+
+        switch (newState) {
+            case "CONNECTING":
+                toUpdate.setCallState(callID, SipCall.State.CONNECTING); break;
+            case "RINGING":
+                toUpdate.setCallState(callID, SipCall.State.RINGING); break;
+            case "CURRENT":
+                toUpdate.setCallState(callID, SipCall.State.CURRENT); break;
+            case "HOLD":
+                toUpdate.setCallState(callID, SipCall.State.HOLD); break;
+            case "UNHOLD":
+                toUpdate.setCallState(callID, SipCall.State.CURRENT); break;
+            case "HUNGUP":
+            case "INACTIVE":
+                Log.d(TAG, "Hanging up " + callID);
+                Log.w("CallNotification ", "Canceling " + toUpdate.notificationId);
+                mService.mNotificationManager.notificationManager.cancel(toUpdate.notificationId);
+                SipCall call = toUpdate.getCallById(callID);
+                if (!toUpdate.hasMultipleParticipants()) {
+                    if (toUpdate.isRinging() && toUpdate.isIncoming()) {
+                        mService.mNotificationManager.publishMissedCallNotification(mService.getConferences().get(callID));
+                    }
+                    toUpdate.setCallState(callID, SipCall.State.HUNGUP);
+                    mService.mHistoryManager.insertNewEntry(toUpdate);
+                    mService.getConferences().remove(toUpdate.getId());
+                } else {
+                    toUpdate.setCallState(callID, SipCall.State.HUNGUP);
+                    mService.mHistoryManager.insertNewEntry(call);
                 }
-                toUpdate.setCallState(callID, SipCall.state.CALL_STATE_HUNGUP);
-                mService.mHistoryManager.insertNewEntry(toUpdate);
+                break;
+            case "BUSY":
+                mService.mNotificationManager.notificationManager.cancel(toUpdate.notificationId);
+                toUpdate.setCallState(callID, SipCall.State.BUSY);
                 mService.getConferences().remove(toUpdate.getId());
-            } else {
-                toUpdate.setCallState(callID, SipCall.state.CALL_STATE_HUNGUP);
-                mService.mHistoryManager.insertNewEntry(call);
-            }
-        } else if (newState.equals("BUSY")) {
-            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_BUSY);
-            mService.getConferences().remove(toUpdate.getId());
-        } else if (newState.equals("FAILURE")) {
-            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_FAILURE);
-            mService.getConferences().remove(toUpdate.getId());
-            Ringservice.hangUp(callID);
-        } else if (newState.equals("HOLD")) {
-            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_HOLD);
-        } else if (newState.equals("UNHOLD")) {
-            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_CURRENT);
+                break;
+            case "FAILURE":
+                Log.w("CallNotification ", "Canceling " + toUpdate.notificationId);
+                mService.mNotificationManager.notificationManager.cancel(toUpdate.notificationId);
+                toUpdate.setCallState(callID, SipCall.State.FAILURE);
+                mService.getConferences().remove(toUpdate.getId());
+                Ringservice.hangUp(callID);
+                break;
         }
         intent.putExtra("conference", toUpdate);
         mService.sendBroadcast(intent);
@@ -99,32 +119,28 @@
 
     @Override
     public void incomingCall(String accountID, String callID, String from) {
-        Log.d(TAG, "on_incoming_call(" + accountID + ", " + callID + ", " + from + ")");
+        Log.w(TAG, "on_incoming_call(" + accountID + ", " + callID + ", " + from + ")");
 
         try {
             StringMap details = Ringservice.getAccountDetails(accountID);
-            VectMap credentials = Ringservice.getCredentials(accountID);
-            StringMap state = Ringservice.getVolatileAccountDetails(accountID);
-            Account acc = new Account(accountID, details.toNative(), credentials.toNative(), state.toNative());
-
-            Bundle args = new Bundle();
-            args.putString(SipCall.ID, callID);
-            args.putParcelable(SipCall.ACCOUNT, acc);
-            args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_RINGING);
-            args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_INCOMING);
-
-            CallContact unknow = CallContact.ContactBuilder.buildUnknownContact(from);
-            args.putParcelable(SipCall.CONTACT, unknow);
+            //VectMap credentials = Ringservice.getCredentials(accountID);
+            //StringMap state = Ringservice.getVolatileAccountDetails(accountID);
+            Account acc = new Account(accountID, details.toNative(), null, null);
 
             Intent toSend = new Intent(CallManagerCallBack.INCOMING_CALL);
             toSend.setClass(mService, CallActivity.class);
             toSend.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            SipCall newCall = new SipCall(args);
-            newCall.setTimestampStart_(System.currentTimeMillis());
+
+            CallContact unknown = CallContact.ContactBuilder.buildUnknownContact(from);
+
+            SipCall newCall = new SipCall(callID, accountID, from, SipCall.Direction.INCOMING);
+            newCall.setContact(unknown);
+            newCall.setCallState(SipCall.State.RINGING);
+            newCall.setTimestampStart(System.currentTimeMillis());
 
             Conference toAdd;
             if (acc.useSecureLayer()) {
-               SecureSipCall secureCall = new SecureSipCall(newCall);
+               SecureSipCall secureCall = new SecureSipCall(newCall, acc.getSrtpDetails().getDetailString(AccountDetailSrtp.CONFIG_SRTP_KEY_EXCHANGE));
                 toAdd = new Conference(secureCall);
             } else {
                 toAdd = new Conference(newCall);
@@ -132,6 +148,22 @@
 
             mService.getConferences().put(toAdd.getId(), toAdd);
 
+            NotificationCompat.Builder noti = new NotificationCompat.Builder(mService)
+                    .setContentTitle("Incoming call with " + from)
+                    .setContentText("incoming call")
+                    .setOngoing(true)
+                    .setSmallIcon(R.drawable.ic_launcher)
+                    .addAction(R.drawable.ic_call_end_white_24dp, "End call",
+                            PendingIntent.getService(mService, 4278,
+                                new Intent(mService, SipService.class)
+                                        .setAction(SipService.ACTION_CALL_END)
+                                        .putExtra("conf", toAdd.getId()),
+                                    PendingIntent.FLAG_ONE_SHOT));
+
+            //mService.startForeground(toAdd.notificationId, noti);
+            Log.w("CallNotification ", "Adding for incoming " + toAdd.notificationId);
+            mService.mNotificationManager.notificationManager.notify(toAdd.notificationId, noti.build());
+
             Bundle bundle = new Bundle();
             bundle.putParcelable("conference", toAdd);
             toSend.putExtra("resuming", false);
@@ -175,33 +207,37 @@
     }
 
     @Override
-    public void incomingMessage(String ID, String from, StringMap messages) {
+    public void incomingMessage(String id, String from, StringMap messages) {
         Log.w(TAG, "on_incoming_message:" + messages);
 
         String msg = messages.get("text/plain");
         if (msg == null)
             return;
 
-        Intent intent = new Intent(INCOMING_TEXT);
-        intent.putExtra("CallID", ID);
-        intent.putExtra("From", from);
-        intent.putExtra("Msg", msg);
-
-        if (mService.getConferences().get(ID) != null) {
-            mService.getConferences().get(ID).addSipMessage(new SipMessage(true, msg));
-            intent.putExtra("conference", mService.getConferences().get(ID));
-        } else {
-            for (Map.Entry<String, Conference> stringConferenceEntry : mService.getConferences().entrySet()) {
-                Conference tmp = stringConferenceEntry.getValue();
-                for (SipCall c : tmp.getParticipants()) {
-                    if (c.getCallId().contentEquals(ID)) {
-                        mService.getConferences().get(tmp.getId()).addSipMessage(new SipMessage(true, msg));
-                        intent.putExtra("conference", tmp);
-                    }
+        Conference conf = mService.getConferences().get(id);
+        if (conf == null) {
+            for (Conference tmp : mService.getConferences().values())
+                if (tmp.getCallById(id) != null) {
+                    conf = tmp;
+                    break;
                 }
+            if (conf == null) {
+                Log.w(TAG, "Discarding message for unknown call " + id);
+                return;
             }
-
         }
+
+        TextMessage message = new TextMessage(true, msg, from, id, conf.hasMultipleParticipants() ? null : conf.getParticipants().get(0).getAccount());
+        if (!conf.hasMultipleParticipants())
+            message.setContact(conf.getParticipants().get(0).getContact());
+
+        conf.addSipMessage(message);
+
+        mService.mHistoryManager.insertNewTextMessage(new HistoryText(message));
+
+        Intent intent = new Intent(INCOMING_TEXT);
+        intent.putExtra("txt", message);
+        intent.putExtra("conference", conf.getId());
         mService.sendBroadcast(intent);
     }
 
@@ -215,10 +251,21 @@
         for (SipCall call : toReInsert.getParticipants()) {
             mService.getConferences().put(call.getCallId(), new Conference(call));
         }
-        intent.putExtra("conference", mService.getConferences().get(confID));
+
+        Conference conf = mService.getConferences().get(confID);
+
+        Log.w("CallNotification ", "Canceling " + conf.notificationId);
+        //NotificationManager mNotifyMgr = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);
+        mService.mNotificationManager.notificationManager.cancel(conf.notificationId);
+
+        intent.putExtra("conference", conf);
         mService.getConferences().remove(confID);
         mService.sendBroadcast(intent);
 
+        if (mService.getConferences().size() == 0) {
+            mService.stopForeground(true);
+        }
+
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java b/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java
index ceb4969..e852a0d 100644
--- a/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java
+++ b/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java
@@ -26,13 +26,17 @@
 import android.content.Intent;
 import android.util.Log;
 
+import cx.ring.history.HistoryText;
+import cx.ring.model.TextMessage;
+
 public class ConfigurationManagerCallback extends ConfigurationCallback {
 
     private  SipService mService;
     private static final String TAG = "ConfigurationManagerCb";
 
     static public final String ACCOUNTS_CHANGED = "accounts-changed";
-    static public final String ACCOUNT_STATE_CHANGED = "account-state-changed";
+    static public final String ACCOUNT_STATE_CHANGED = "account-State-changed";
+    static public final String INCOMING_TEXT = "incoming--txt-msg";
 
     public ConfigurationManagerCallback(SipService context) {
         super();
@@ -58,7 +62,19 @@
 
     @Override
     public void registrationStateChanged(String account_id, String state, int code, String detail_str) {
-        sendAccountStateChangedMessage(account_id, state, 0);
+        Log.w(getClass().getName(), "registrationStateChanged: " + account_id + " " + state + " " + code + " " + detail_str);
+        sendAccountStateChangedMessage(account_id, state, code);
+    }
+
+    @Override
+    public void incomingAccountMessage(String accountID, String from, String msg) {
+        Log.w(TAG, "incomingAccountMessage : " + accountID + " " + from + " " + msg);
+
+        TextMessage message = new TextMessage(true, msg, from, null, accountID);
+        mService.mHistoryManager.insertNewTextMessage(new HistoryText(message));
+        Intent intent = new Intent(INCOMING_TEXT);
+        intent.putExtra("txt", message);
+        mService.sendBroadcast(intent);
     }
 
     @Override
@@ -69,7 +85,7 @@
     private void sendAccountStateChangedMessage(String accoundID, String state, int code) {
         Intent intent = new Intent(ACCOUNT_STATE_CHANGED);
         intent.putExtra("Account", accoundID);
-        intent.putExtra("state", state);
+        intent.putExtra("State", state);
         intent.putExtra("code", code);
         mService.sendBroadcast(intent);
     }
@@ -79,6 +95,7 @@
         OpenSlParams audioParams = OpenSlParams.createInstance(mService);
         ret.add(audioParams.getSampleRate());
         ret.add(audioParams.getBufferSize());
+        Log.w(getClass().getName(), "getHardwareAudioFormat: " + audioParams.getSampleRate() + " " + audioParams.getBufferSize());
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/service/ISipService.aidl b/ring-android/app/src/main/java/cx/ring/service/ISipService.aidl
index 4708062..5281c5e 100644
--- a/ring-android/app/src/main/java/cx/ring/service/ISipService.aidl
+++ b/ring-android/app/src/main/java/cx/ring/service/ISipService.aidl
@@ -1,8 +1,8 @@
 package cx.ring.service;
 
 import cx.ring.model.SipCall;
+import cx.ring.model.TextMessage;
 import cx.ring.model.Conference;
-import cx.ring.model.SipMessage;
 
 interface ISipService {
     
@@ -57,7 +57,7 @@
 	void playDtmf(in String key);
     
     /* IM */
-    void sendTextMessage(in String callID, in SipMessage message);
+    void sendTextMessage(in String callID, in TextMessage message);
     void sendAccountTextMessage(in String accountid, in String to, in String msg);
 
 
diff --git a/ring-android/app/src/main/java/cx/ring/service/LocalService.java b/ring-android/app/src/main/java/cx/ring/service/LocalService.java
new file mode 100644
index 0000000..02c22f2
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/service/LocalService.java
@@ -0,0 +1,813 @@
+package cx.ring.service;
+
+import android.app.Service;
+import android.content.AsyncTaskLoader;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.Loader;
+import android.content.ServiceConnection;
+import android.database.Cursor;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Pair;
+
+import java.lang.ref.WeakReference;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import cx.ring.BuildConfig;
+import cx.ring.history.HistoryCall;
+import cx.ring.history.HistoryEntry;
+import cx.ring.history.HistoryManager;
+import cx.ring.history.HistoryText;
+import cx.ring.model.CallContact;
+import cx.ring.model.Conference;
+import cx.ring.model.Conversation;
+import cx.ring.model.SipCall;
+import cx.ring.model.TextMessage;
+import cx.ring.model.account.Account;
+import cx.ring.utils.Utilities;
+
+
+public class LocalService extends Service {
+    static final String TAG = LocalService.class.getSimpleName();
+    static public final String ACTION_CONF_UPDATE = BuildConfig.APPLICATION_ID + ".action.CONF_UPDATE";
+    static public final String ACTION_ACCOUNT_UPDATE = BuildConfig.APPLICATION_ID + ".action.ACCOUNT_UPDATE";
+
+    public static final String AUTHORITY = "cx.ring";
+    public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+    private ISipService mService = null;
+
+    // Binder given to clients
+    private final IBinder mBinder = new LocalBinder();
+
+    private Map<String, Conversation> conversations = new HashMap<>();
+    private ArrayList<Account> all_accounts = new ArrayList<>();
+    private List<Account> accounts = all_accounts;
+    private List<Account> ip2ip_account = all_accounts;
+
+    private HistoryManager historyManager;
+
+    AccountsLoader mAccountLoader = null;
+
+    public interface Callbacks {
+        ISipService getRemoteService();
+        LocalService getService();
+    }
+    public static class DummyCallbacks implements Callbacks {
+        @Override
+        public ISipService getRemoteService() {
+            return null;
+        }
+        @Override
+        public LocalService getService() {
+            return null;
+        }
+    }
+    public static final Callbacks DUMMY_CALLBACKS = new DummyCallbacks();
+
+    @Override
+    public void onCreate() {
+        Log.e(TAG, "onCreate");
+        super.onCreate();
+        historyManager = new HistoryManager(this);
+        Intent intent = new Intent(this, SipService.class);
+        startService(intent);
+        bindService(intent, mConnection, BIND_AUTO_CREATE | BIND_IMPORTANT | BIND_ABOVE_CLIENT );
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.e(TAG, "onDestroy");
+        super.onDestroy();
+        stopListener();
+    }
+
+    private final Loader.OnLoadCompleteListener<ArrayList<Account>> onAccountsLoaded = new Loader.OnLoadCompleteListener<ArrayList<Account>>() {
+        @Override
+        public void onLoadComplete(Loader<ArrayList<Account>> loader, ArrayList<Account> data) {
+            Log.w(TAG, "AccountsLoader Loader.OnLoadCompleteListener");
+            all_accounts = data;
+            accounts = all_accounts.subList(0,data.size()-1);
+            ip2ip_account = all_accounts.subList(data.size()-1,data.size());
+            sendBroadcast(new Intent(ACTION_ACCOUNT_UPDATE));
+        }
+    };
+
+    private ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            Log.w(TAG, "onServiceConnected " + className.getClassName());
+            mService = ISipService.Stub.asInterface(service);
+            //mBound = true;
+            mAccountLoader = new AccountsLoader(LocalService.this);
+            mAccountLoader.registerListener(1, onAccountsLoaded);
+            mAccountLoader.startLoading();
+            mAccountLoader.forceLoad();
+            startListener();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName arg0) {
+            Log.w(TAG, "onServiceDisconnected " + arg0.getClassName());
+            if (mAccountLoader != null) {
+                mAccountLoader.unregisterListener(onAccountsLoaded);
+                mAccountLoader.cancelLoad();
+                mAccountLoader.stopLoading();
+            }
+            //mBound = false;
+            mService = null;
+        }
+    };
+
+    /**
+     * Class used for the client Binder.  Because we know this service always
+     * runs in the same process as its clients, we don't need to deal with IPC.
+     */
+    public class LocalBinder extends Binder {
+        public LocalService getService() {
+            // Return this instance of LocalService so clients can call public methods
+            return LocalService.this;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        Log.e(TAG, "onUnbind");
+        if (mConnection != null) {
+            unbindService(mConnection);
+            mConnection = null;
+        }
+        return super.onUnbind(intent);
+    }
+
+    public ISipService getRemoteService() {
+        return mService;
+    }
+
+    public List<Account> getAccounts() { return accounts; }
+    public List<Account> getIP2IPAccount() { return ip2ip_account; }
+    public Account getAccount(String account_id) {
+        for (Account acc : all_accounts)
+            if (acc.getAccountID().equals(account_id))
+                return acc;
+        return null;
+    }
+
+    public ArrayList<Conversation> getConversations() {
+        ArrayList<Conversation> convs = new ArrayList<>(conversations.values());
+        Collections.sort(convs, new Comparator<Conversation>() {
+            @Override
+            public int compare(Conversation lhs, Conversation rhs) {
+                return (int) ((rhs.getLastInteraction().getTime() - lhs.getLastInteraction().getTime())/1000l);
+            }
+        });
+        return convs;
+    }
+
+    public Conversation getConversation(String id) {
+        return conversations.get(id);
+    }
+
+    public Conference getConference(String id) {
+        for (Conversation conv : conversations.values()) {
+            Conference conf = conv.getConference(id);
+            if (conf != null)
+                return conf;
+        }
+        return null;
+    }
+
+    public Conversation getByContact(CallContact contact) {
+        ArrayList<String> keys = contact.getIds();
+        for (String k : keys) {
+            Conversation c = conversations.get(k);
+            if (c != null)
+                return c;
+        }
+        Log.w(TAG, "getByContact failed");
+        return null;
+    }
+    public Conversation getByCallId(String callId) {
+        for (Conversation conv : conversations.values()) {
+            Conference conf = conv.getConference(callId);
+            if (conf != null)
+                return conv;
+        }
+        return null;
+    }
+
+    public Conversation startConversation(CallContact contact) {
+        Conversation c = getByContact(contact);
+        if (c == null) {
+            c = new Conversation(contact);
+            conversations.put(contact.getIds().get(0), c);
+        }
+        return c;
+    }
+
+    public CallContact findContactByNumber(String number) {
+        for (Conversation conv : conversations.values()) {
+            if (conv.contact.hasNumber(number))
+                return conv.contact;
+        }
+        return findContactByNumber(getContentResolver(), number);
+    }
+
+    public CallContact findContactById(long id) {
+        return findById(getContentResolver(), id);
+    }
+
+    public Account guessAccount(CallContact c, String number) {
+        number = CallContact.canonicalNumber(number);
+        if (Utilities.isIpAddress(number))
+            return ip2ip_account.get(0);
+        /*Conversation conv = getByContact(c);
+        if (conv != null) {
+            return
+        }*/
+        return accounts.get(0);
+    }
+
+    public static final String[] DATA_PROJECTION = {
+            ContactsContract.Data._ID,
+            ContactsContract.RawContacts.CONTACT_ID,
+            ContactsContract.Data.LOOKUP_KEY,
+            ContactsContract.Data.DISPLAY_NAME_PRIMARY,
+            ContactsContract.Data.PHOTO_ID,
+            ContactsContract.Data.PHOTO_THUMBNAIL_URI
+    };
+    public static final String[] CONTACT_PROJECTION = {
+            ContactsContract.Data._ID,
+            ContactsContract.Data.LOOKUP_KEY,
+            ContactsContract.Data.DISPLAY_NAME_PRIMARY,
+            ContactsContract.Data.PHOTO_ID,
+    };
+
+    public static final String[] PHONELOOKUP_PROJECTION = {
+            ContactsContract.PhoneLookup._ID,
+            ContactsContract.PhoneLookup.LOOKUP_KEY,
+            ContactsContract.PhoneLookup.PHOTO_ID,
+            ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
+    };
+
+    private static final String[] CONTACTS_PHONES_PROJECTION = {
+            ContactsContract.CommonDataKinds.Phone.NUMBER,
+            ContactsContract.CommonDataKinds.Phone.TYPE
+    };
+    private static final String[] CONTACTS_SIP_PROJECTION = {
+            ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS,
+            ContactsContract.CommonDataKinds.SipAddress.TYPE
+    };
+   /* private static final String[] CONTACTS_PHOTO_PROJECTION = {
+            ContactsContract.CommonDataKinds.Photo.,
+            ContactsContract.CommonDataKinds.SipAddress.TYPE
+    };
+*/
+    private static final String ID_SELECTION = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?";
+    private static final String KEY_SELECTION = ContactsContract.Contacts.LOOKUP_KEY + "=?";
+
+    private static void lookupDetails(@NonNull ContentResolver res, @NonNull CallContact c) {
+        Log.w(TAG, "lookupDetails " + c.getKey());
+
+        Cursor cPhones = res.query(
+                ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
+                CONTACTS_PHONES_PROJECTION,
+                ID_SELECTION,
+                new String[]{String.valueOf(c.getId())}, null);
+        if (cPhones != null) {
+            final int iNum =  cPhones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
+            final int iType =  cPhones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
+            while (cPhones.moveToNext()) {
+                c.addNumber(cPhones.getString(iNum), cPhones.getInt(iType), CallContact.NumberType.TEL);
+                Log.w(TAG,"Phone:"+cPhones.getString(cPhones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
+            }
+            cPhones.close();
+        }
+
+        Uri baseUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, c.getId());
+        Uri targetUri = Uri.withAppendedPath(baseUri, ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
+        Cursor cSip = res.query(targetUri,
+                CONTACTS_SIP_PROJECTION,
+                ContactsContract.Data.MIMETYPE + "=?",
+                new String[]{ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE}, null);
+        if (cSip != null) {
+            final int iSip =  cSip.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS);
+            final int iType =  cSip.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.TYPE);
+            while (cSip.moveToNext()) {
+                c.addNumber(cSip.getString(iSip), cSip.getInt(iType), CallContact.NumberType.SIP);
+                Log.w(TAG, "SIP phone:" + cSip.getString(iSip));
+            }
+            cSip.close();
+        }
+
+        /*Cursor cPhoto = res.query(targetUri,
+                CONTACTS_SIP_PROJECTION,
+                ContactsContract.Data.MIMETYPE + "=?",
+                new String[]{ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE}, null);
+        if (cSip != null) {
+            final int iSip =  cSip.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS);
+            final int iType =  cSip.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.TYPE);
+            while (cSip.moveToNext()) {
+                c.addNumber(cSip.getString(iSip), cSip.getInt(iType), CallContact.NumberType.SIP);
+                Log.w(TAG, "SIP phone:" + cSip.getString(iSip));
+            }
+            cSip.close();
+        }*/
+    }
+
+    public static CallContact findByKey(@NonNull ContentResolver res, String key) {
+        Log.e(TAG, "findByKey " + key);
+
+        final CallContact.ContactBuilder builder = CallContact.ContactBuilder.getInstance();
+        Cursor result = res.query( Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, key), CONTACT_PROJECTION,
+                null, null, null);
+
+        CallContact contact = null;
+        if (result != null && result.moveToFirst()) {
+            int iID = result.getColumnIndex(ContactsContract.Data._ID);
+            int iKey = result.getColumnIndex(ContactsContract.Data.LOOKUP_KEY);
+            int iName = result.getColumnIndex(ContactsContract.Data.DISPLAY_NAME);
+            int iPhoto = result.getColumnIndex(ContactsContract.Data.PHOTO_ID);
+            long cid = result.getLong(iID);
+
+            Log.w(TAG, "Contact id:" + cid + " key:" + result.getString(iKey));
+
+            builder.startNewContact(cid, result.getString(iKey), result.getString(iName), result.getLong(iPhoto));
+            result.close();
+
+            contact = builder.build();
+            lookupDetails(res, contact);
+        }
+        return contact;
+    }
+
+     public static CallContact findById(@NonNull ContentResolver res, long id) {
+         Log.e(TAG, "findById " + id);
+
+         final CallContact.ContactBuilder builder = CallContact.ContactBuilder.getInstance();
+         Cursor result = res.query(ContactsContract.Contacts.CONTENT_URI, CONTACT_PROJECTION,
+                 ContactsContract.Contacts._ID + " = ?",
+                 new String[]{String.valueOf(id)}, null);
+         if (result == null)
+             return null;
+
+         CallContact contact = null;
+         if (result.moveToFirst()) {
+             int iID = result.getColumnIndex(ContactsContract.Data._ID);
+             int iKey = result.getColumnIndex(ContactsContract.Data.LOOKUP_KEY);
+             int iName = result.getColumnIndex(ContactsContract.Data.DISPLAY_NAME);
+             int iPhoto = result.getColumnIndex(ContactsContract.Data.PHOTO_ID);
+             long cid = result.getLong(iID);
+
+             Log.w(TAG, "Contact id:" + cid + " key:" + result.getString(iKey));
+
+             builder.startNewContact(cid, result.getString(iKey), result.getString(iName), result.getLong(iPhoto));
+             contact = builder.build();
+             lookupDetails(res, contact);
+         }
+         result.close();
+         return contact;
+    }
+    /*
+    public static int getRawContactId(@NonNull ContentResolver res, long contactId)
+    {
+        Cursor c= res.query(
+                ContactsContract.RawContacts.CONTENT_URI,
+                new String[]{ContactsContract.RawContacts._ID},
+                ContactsContract.RawContacts.CONTACT_ID+"=?",
+                new String[]{String.valueOf(contactId)},
+                null);
+        if (c == null)
+            return -1;
+        if (c.moveToFirst()) {
+            int rawContactId = c.getInt(c.getColumnIndex(ContactsContract.RawContacts._ID));
+            Log.d(TAG, "Contact Id: " + contactId + " Raw Contact Id: " + rawContactId);
+            return rawContactId;
+        }
+        c.close();
+        return -1;
+    }
+*/
+    @NonNull
+    public static CallContact findContactBySipNumber(@NonNull ContentResolver res, String number) {
+        final CallContact.ContactBuilder builder = CallContact.ContactBuilder.getInstance();
+        Cursor result = res.query(ContactsContract.Data.CONTENT_URI,
+                DATA_PROJECTION,
+                ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + "=?" + " AND " + ContactsContract.Data.MIMETYPE + "=?",
+                new String[]{number, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE}, null);
+        if (result == null)  {
+            Log.w(TAG, "findContactBySipNumber " + number + " can't find contact.");
+            return CallContact.ContactBuilder.buildUnknownContact(number);
+        }
+        int iID = result.getColumnIndex(ContactsContract.Data._ID);
+        int icID = result.getColumnIndex(ContactsContract.RawContacts.CONTACT_ID);
+        int iKey = result.getColumnIndex(ContactsContract.Data.LOOKUP_KEY);
+        int iName = result.getColumnIndex(ContactsContract.Data.DISPLAY_NAME);
+        int iPhoto = result.getColumnIndex(ContactsContract.Data.PHOTO_ID);
+        int iPhotoThumb = result.getColumnIndex(ContactsContract.Data.PHOTO_THUMBNAIL_URI);
+
+        ArrayList<CallContact> contacts = new ArrayList<>(1);
+        while (result.moveToNext()) {
+            long cid = result.getLong(icID);
+            long id = result.getLong(iID);
+            builder.startNewContact(cid, result.getString(iKey), result.getString(iName), result.getLong(iPhoto));
+            CallContact contact = builder.build();
+            //Log.w(TAG, "findContactBySipNumber " + number + " found name:" + contact.getDisplayName() + " id:" + contact.getId() + " key:" + contact.getKey() + " rawid:"+getRawContactId(res, contact.getId()) + " rid:"+id + " photo:"+result.getLong(iPhoto) + " thumb:" + result.getString(iPhotoThumb));
+            lookupDetails(res, contact);
+            contacts.add(contact);
+        }
+        result.close();
+
+        //lookupDetails(res, contact);
+        /*if (contact == null) {
+            Log.w(TAG, "Can't find contact with number " + number);
+            contact = CallContact.ContactBuilder.buildUnknownContact(number);
+        }*/
+        if (contacts.isEmpty()) {
+            Log.w(TAG, "findContactBySipNumber " + number + " can't find contact.");
+            return CallContact.ContactBuilder.buildUnknownContact(number);
+        }
+        return contacts.get(0);
+    }
+
+    @NonNull
+    public static CallContact findContactByNumber(@NonNull ContentResolver res, String number) {
+        //Log.w(TAG, "findContactByNumber " + number);
+
+        final CallContact.ContactBuilder builder = CallContact.ContactBuilder.getInstance();
+        Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
+        Cursor result = res.query(uri, PHONELOOKUP_PROJECTION, null, null, null);
+        if (result == null)  {
+            Log.w(TAG, "findContactByNumber " + number + " can't find contact.");
+            return findContactBySipNumber(res, number);
+        }
+        if (!result.moveToFirst())  {
+            result.close();
+            Log.w(TAG, "findContactByNumber " + number + " can't find contact.");
+            return findContactBySipNumber(res, number);
+        }
+        int iID = result.getColumnIndex(ContactsContract.Contacts._ID);
+        int iKey = result.getColumnIndex(ContactsContract.Data.LOOKUP_KEY);
+        int iName = result.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
+        int iPhoto = result.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
+        builder.startNewContact(result.getLong(iID), result.getString(iKey), result.getString(iName), result.getLong(iPhoto));
+        result.close();
+        CallContact contact = builder.build();
+        lookupDetails(res, contact);
+        /*if (contact == null) {
+            Log.w(TAG, "Can't find contact with number " + number);
+            contact = CallContact.ContactBuilder.buildUnknownContact(number);
+        }*/
+        Log.w(TAG, "findContactByNumber " + number + " found " + contact.getDisplayName());
+
+        return contact;
+    }
+
+    private class ConversationLoader extends AsyncTask<Void, Void, Map<String, Conversation>> {
+        private final ContentResolver cr;
+
+        public ConversationLoader(Context c) {
+            cr = c.getContentResolver();
+        }
+
+        private CallContact getByNumber(HashMap<String, CallContact> cache, String number) {
+            if (number == null || number.isEmpty())
+                return null;
+            number = CallContact.canonicalNumber(number);
+            CallContact c = cache.get(number);
+            if (c == null) {
+                c = findContactByNumber(cr, number);
+                //if (c != null)
+                cache.put(number, c);
+            }
+            return c;
+        }
+
+        Pair<HistoryEntry, HistoryCall> findHistoryByCallId(final Map<String, Conversation> confs, String id) {
+            for (Conversation c : confs.values()) {
+                Pair<HistoryEntry, HistoryCall> h = c.findHistoryByCallId(id);
+                if (h != null)
+                    return h;
+            }
+            return null;
+        }
+
+        @Override
+        protected Map<String, Conversation> doInBackground(Void... params) {
+            List<HistoryCall> history = null;
+            List<HistoryText> historyTexts = null;
+            Map<String, Conference> confs = null;
+            final Map<String, Conversation> ret = new HashMap<>();
+            final LongSparseArray<CallContact> localContactCache = new LongSparseArray<>(64);
+            final HashMap<String, CallContact> localNumberCache = new HashMap<>(64);
+
+
+            try {
+                history = historyManager.getAll();
+                historyTexts = historyManager.getAllTextMessages();
+                confs = mService.getConferenceList();
+            } catch (RemoteException | SQLException e) {
+                e.printStackTrace();
+            }
+
+            for (HistoryCall call : history) {
+                //Log.w(TAG, "History call : " + call.getNumber() + " " + call.call_start + " " + call.call_end + " " + call.getEndDate().toString());
+                CallContact contact;
+                if (call.getContactID() <= CallContact.DEFAULT_ID) {
+                    contact = getByNumber(localNumberCache, call.getNumber());
+                } else {
+                    contact = localContactCache.get(call.getContactID());
+                    if (contact == null) {
+                        contact = findById(cr, call.getContactID());
+                        if (contact != null)
+                            contact.addPhoneNumber(call.getNumber(), 0);
+                        else {
+                            Log.w(TAG, "Can't find contact with id " + call.getContactID());
+                            contact = getByNumber(localNumberCache, call.getNumber());
+                        }
+                        localContactCache.put(contact.getId(), contact);
+                    }
+                }
+
+                Map.Entry<String, Conversation> merge = null;
+                for (Map.Entry<String, Conversation> ce : ret.entrySet()) {
+                    Conversation c = ce.getValue();
+                    if ((contact.getId() > 0 && contact.getId() == c.contact.getId()) || c.contact.hasNumber(call.getNumber())) {
+                        merge = ce;
+                        break;
+                    }
+                }
+                if (merge != null) {
+                    Conversation c = merge.getValue();
+                    //Log.w(TAG, "        Join to " + merge.getKey() + " " + c.getContact().getDisplayName() + " " + call.getNumber());
+                    if (c.getContact().getId() <= 0 && contact.getId() > 0) {
+                        c.contact = contact;
+                        ret.remove(merge.getKey());
+                        ret.put(contact.getIds().get(0), c);
+                    }
+                    c.addHistoryCall(call);
+                    continue;
+                }
+                String key = contact.getIds().get(0);
+                if (ret.containsKey(key)) {
+                    ret.get(key).addHistoryCall(call);
+                } else {
+                    Conversation c = new Conversation(contact);
+                    c.addHistoryCall(call);
+                    ret.put(key, c);
+                }
+            }
+
+            for (HistoryText htext : historyTexts) {
+                CallContact contact;
+
+                if (htext.getContactID() <= CallContact.DEFAULT_ID) {
+                    contact = getByNumber(localNumberCache, htext.getNumber());
+                } else {
+                    contact = localContactCache.get(htext.getContactID());
+                    if (contact == null) {
+                        contact = findById(cr, htext.getContactID());
+                        if (contact != null)
+                            contact.addPhoneNumber(htext.getNumber(), 0);
+                        else {
+                            Log.w(TAG, "Can't find contact with id " + htext.getContactID());
+                            contact = getByNumber(localNumberCache, htext.getNumber());
+                        }
+                        localContactCache.put(contact.getId(), contact);
+                    }
+                }
+
+                Pair<HistoryEntry, HistoryCall> p = findHistoryByCallId(ret, htext.getCallId());
+
+                if (contact == null && p != null)
+                    contact = p.first.getContact();
+                if (contact == null)
+                    continue;
+
+                TextMessage msg = new TextMessage(htext);
+                msg.setContact(contact);
+
+                if (p  != null) {
+                    if (msg.getNumber() == null || msg.getNumber().isEmpty())
+                        msg.setNumber(p.second.getNumber());
+                    p.first.addTextMessage(msg);
+                }
+
+                String key = contact.getIds().get(0);
+                if (ret.containsKey(key)) {
+                    ret.get(key).addTextMessage(msg);
+                } else {
+                    Conversation c = new Conversation(contact);
+                    c.addTextMessage(msg);
+                    ret.put(key, c);
+                }
+            }
+
+            /*context.clear();
+            ctx = null;*/
+            for (Map.Entry<String, Conference> c : confs.entrySet()) {
+                //Log.w(TAG, "ConversationLoader handling " + c.getKey() + " " + c.getValue().getId());
+                Conference conf = c.getValue();
+                ArrayList<SipCall> calls = conf.getParticipants();
+                if (calls.size() >= 1) {
+                    CallContact contact = calls.get(0).getContact();
+                    //Log.w(TAG, "Contact : " + contact.getId() + " " + contact.getDisplayName());
+                    Conversation conv = null;
+                    ArrayList<String> ids = contact.getIds();
+                    for (String id : ids) {
+                        //Log.w(TAG, "    uri attempt : " + id);
+                        conv = ret.get(id);
+                        if (conv != null) break;
+                    }
+                    if (conv != null) {
+                        //Log.w(TAG, "Adding conference to existing conversation ");
+                        conv.current_calls.add(conf);
+                    } else {
+                        conv = new Conversation(contact);
+                        conv.current_calls.add(conf);
+                        ret.put(ids.get(0), conv);
+                    }
+                }
+            }
+            for (Conversation c : ret.values())
+                Log.w(TAG, "Conversation : " + c.getContact().getId() + " " + c.getContact().getDisplayName() + " " + c.getContact().getPhones().get(0).getNumber() + " " + c.getLastInteraction().toString());
+            return ret;
+        }
+    }
+
+    private void updated(Map<String, Conversation> res) {
+        Log.w(TAG, "Conversation list updated");
+        conversations = res;
+        sendBroadcast(new Intent(ACTION_CONF_UPDATE));
+    }
+
+    public class AccountsLoader extends AsyncTaskLoader<ArrayList<Account>> {
+        public static final String ACCOUNTS = "accounts";
+        public static final String ACCOUNT_IP2IP = "IP2IP";
+        public AccountsLoader(Context context) {
+            super(context);
+            Log.w(TAG, "AccountsLoader constructor");
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public ArrayList<Account> loadInBackground() {
+            Log.w(TAG, "AccountsLoader loadInBackground");
+            ArrayList<Account> accounts = new ArrayList<>();
+            Account IP2IP = null;
+            try {
+                ArrayList<String> accountIDs = (ArrayList<String>) mService.getAccountList();
+                Map<String, String> details;
+                ArrayList<Map<String, String>> credentials;
+                Map<String, String> state;
+                for (String id : accountIDs) {
+                    details = (Map<String, String>) mService.getAccountDetails(id);
+                    state = (Map<String, String>) mService.getVolatileAccountDetails(id);
+                    if (id.contentEquals(ACCOUNT_IP2IP)) {
+                        IP2IP = new Account(ACCOUNT_IP2IP, details, new ArrayList<Map<String, String>>(), state); // Empty credentials
+                        //accounts.add(IP2IP);
+                        continue;
+                    }
+                    credentials = (ArrayList<Map<String, String>>) mService.getCredentials(id);
+                /*for (Map.Entry<String, String> entry : State.entrySet()) {
+                    Log.i(TAG, "State:" + entry.getKey() + " -> " + entry.getValue());
+                }*/
+                    Account tmp = new Account(id, details, credentials, state);
+                    accounts.add(tmp);
+                    // Log.i(TAG, "account:" + tmp.getAlias() + " " + tmp.isEnabled());
+
+                }
+            } catch (RemoteException | NullPointerException e) {
+                Log.e(TAG, e.toString());
+            }
+            accounts.add(IP2IP);
+            return accounts;
+        }
+    }
+
+    final BroadcastReceiver receiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch(intent.getAction()) {
+                case ConnectivityManager.CONNECTIVITY_ACTION:
+                    Log.w(TAG, "ConnectivityManager.CONNECTIVITY_ACTION " + " " + intent.getStringExtra(ConnectivityManager.EXTRA_EXTRA_INFO) + " " + intent.getStringExtra(ConnectivityManager.EXTRA_EXTRA_INFO));
+                    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+                    NetworkInfo ni = cm.getActiveNetworkInfo();
+                    Log.w(TAG, "ActiveNetworkInfo: " + (ni == null ? "null" : ni.toString()));
+                    break;
+                case ConfigurationManagerCallback.ACCOUNT_STATE_CHANGED:
+                    Log.w(TAG, "Received " + intent.getAction() + " " + intent.getStringExtra("Account") + " " + intent.getStringExtra("State") + " " + intent.getIntExtra("code", 0));
+                    //accountStateChanged(intent.getStringExtra("Account"), intent.getStringExtra("State"), intent.getIntExtra("code", 0));
+                    for (Account a : accounts) {
+                        if (a.getAccountID().contentEquals(intent.getStringExtra("Account"))) {
+                            a.setRegistrationState(intent.getStringExtra("State"), intent.getIntExtra("code", 0));
+                            //notifyDataSetChanged();
+                            sendBroadcast(new Intent(ACTION_ACCOUNT_UPDATE));
+                            break;
+                        }
+                    }
+                    break;
+                case ConfigurationManagerCallback.ACCOUNTS_CHANGED:
+                    Log.w(TAG, "Received" + intent.getAction());
+                    //accountsChanged();
+                    mAccountLoader.onContentChanged();
+                    mAccountLoader.startLoading();
+                    break;
+                case CallManagerCallBack.INCOMING_TEXT:
+                case ConfigurationManagerCallback.INCOMING_TEXT:
+                    TextMessage txt = intent.getParcelableExtra("txt");
+                    String call = txt.getCallId();
+                    if (call != null && !call.isEmpty()) {
+                        Conversation conv = getByCallId(call);
+                        conv.addTextMessage(txt);
+                        /*Conference conf = conv.getConference(call);
+                        conf.addSipMessage(txt);
+                        Conversation conv = getByContact(conf.)*/
+                    } else {
+                        CallContact contact = findContactByNumber(txt.getNumber());
+                        Conversation conv = startConversation(contact);
+                        txt.setContact(conv.getContact());
+                        Log.w(TAG, "New text messsage " + txt.getAccount() + " " + txt.getContact().getId() + " " + txt.getMessage());
+                        conv.addTextMessage(txt);
+                    }
+                    sendBroadcast(new Intent(ACTION_CONF_UPDATE));
+                    break;
+                default:
+                    Log.w(TAG, "onReceive " + intent.getAction() + " " + intent.getDataString());
+                    new ConversationLoader(context){
+                        @Override
+                        protected void onPostExecute(Map<String, Conversation> res) {
+                            updated(res);
+                        }
+                    }.execute();
+            }
+        }
+    };
+
+    public void startListener() {
+        final WeakReference<LocalService> self = new WeakReference<>(this);
+        new ConversationLoader(this){
+            @Override
+            protected void onPreExecute() {
+                super.onPreExecute();
+                Log.w(TAG, "onPreExecute");
+            }
+
+            @Override
+            protected void onPostExecute(Map<String, Conversation> res) {
+                Log.w(TAG, "onPostExecute");
+                LocalService this_ = self.get();
+                if (this_ != null)
+                    this_.updated(res);
+                else
+                    Log.e(TAG, "AsyncTask finished but parent is destroyed..");
+            }
+        }.execute();
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ConfigurationManagerCallback.ACCOUNT_STATE_CHANGED);
+        intentFilter.addAction(ConfigurationManagerCallback.ACCOUNTS_CHANGED);
+        intentFilter.addAction(ConfigurationManagerCallback.INCOMING_TEXT);
+
+        intentFilter.addAction(CallManagerCallBack.INCOMING_CALL);
+        intentFilter.addAction(CallManagerCallBack.INCOMING_TEXT);
+        intentFilter.addAction(CallManagerCallBack.CALL_STATE_CHANGED);
+        intentFilter.addAction(CallManagerCallBack.CONF_CREATED);
+        intentFilter.addAction(CallManagerCallBack.CONF_CHANGED);
+        intentFilter.addAction(CallManagerCallBack.CONF_REMOVED);
+
+        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+
+        registerReceiver(receiver, intentFilter);
+    }
+
+    public void stopListener() {
+        unregisterReceiver(receiver);
+    }
+
+}
diff --git a/ring-android/app/src/main/java/cx/ring/service/SipService.java b/ring-android/app/src/main/java/cx/ring/service/SipService.java
index 8f9caae..1e3ea96 100644
--- a/ring-android/app/src/main/java/cx/ring/service/SipService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/SipService.java
@@ -24,6 +24,7 @@
  */
 package cx.ring.service;
 
+import android.app.Notification;
 import android.os.Handler;
 
 import java.util.ArrayList;
@@ -36,12 +37,21 @@
 import android.app.Service;
 import android.content.Intent;
 import android.os.*;
+import android.telecom.Call;
 import android.util.Log;
+
+import cx.ring.BuildConfig;
+import cx.ring.R;
 import cx.ring.history.HistoryManager;
+import cx.ring.history.HistoryText;
 import cx.ring.model.Codec;
 import cx.ring.model.Conference;
 import cx.ring.model.SecureSipCall;
-import cx.ring.model.SipMessage;
+import cx.ring.model.TextMessage;
+import cx.ring.model.account.AccountDetail;
+import cx.ring.model.account.AccountDetailBasic;
+import cx.ring.model.account.AccountDetailSrtp;
+import cx.ring.model.account.AccountDetailTls;
 import cx.ring.utils.MediaManager;
 import cx.ring.utils.SipNotifications;
 import cx.ring.utils.SwigNativeConverter;
@@ -54,8 +64,14 @@
     private SipServiceExecutor mExecutor;
     private static HandlerThread executorThread;
 
+    static public final String ACTION_CALL_ACCEPT = BuildConfig.APPLICATION_ID + ".action.CALL_ACCEPT";
+    static public final String ACTION_CALL_REFUSE = BuildConfig.APPLICATION_ID + ".action.CALL_REFUSE";
+    //static public final String ACTION_CALL_REFUSE = BuildConfig.APPLICATION_ID + ".action.CALL_REFUSE";
+
+    static public final String ACTION_CALL_END = BuildConfig.APPLICATION_ID + ".action.CALL_END";
+
     private Handler handler = new Handler();
-    private static int POLLING_TIMEOUT = 500;
+    private static int POLLING_TIMEOUT = 50;
     private Runnable pollEvents = new Runnable() {
         @Override
         public void run() {
@@ -74,7 +90,7 @@
     protected HistoryManager mHistoryManager;
     protected MediaManager mMediaManager;
 
-    private HashMap<String, Conference> mConferences = new HashMap<>();
+    private final HashMap<String, Conference> mConferences = new HashMap<>();
     private ConfigurationManagerCallback configurationCallback;
     private CallManagerCallBack callManagerCallBack;
 
@@ -141,8 +157,36 @@
     /* called for each startService() */
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        Log.i(TAG, "onStarted " + (intent == null ? "null" : intent.getAction()) + " " + flags);
-        super.onStartCommand(intent, flags, startId);
+        Log.i(TAG, "onStartCommand " + (intent == null ? "null" : intent.getAction()) + " " + flags + " " + startId);
+        String action = intent == null ? null : intent.getAction();
+        try {
+            if (action != null) {
+                if (action.equals(ACTION_CALL_END)) {
+                    Conference c = findConference(intent.getStringExtra("conf"));
+                    if (c != null) {
+                        for (SipCall call : c.getParticipants()) {
+                            mBinder.hangUp(call.getCallId());
+                        }
+                        mBinder.hangUpConference(c.getId());
+                        Log.w("CallNotification ", "Canceling " + c.notificationId);
+                        mNotificationManager.notificationManager.cancel(c.notificationId);
+                    }
+                } else if (action.equals(ACTION_CALL_ACCEPT)) {
+                    Conference c = findConference(intent.getStringExtra("conf"));
+                    if (c != null) {
+                        mBinder.accept(c.getParticipants().get(0).getCallId());
+                    }
+                } else if (action.equals(ACTION_CALL_REFUSE)) {
+                    Conference c = findConference(intent.getStringExtra("conf"));
+                    if (c != null) {
+                        mBinder.refuse(c.getParticipants().get(0).getCallId());
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
         return START_STICKY; /* started and stopped explicitly */
     }
 
@@ -265,6 +309,8 @@
             public void run() {
                 try {
                     mTask.run();
+                } catch(Exception e){
+                    e.printStackTrace();
                 } finally {
                     synchronized (this) {
                         mDone = true;
@@ -419,27 +465,59 @@
                 protected String doRun() throws SameThreadException {
                     Log.i(TAG, "SipService.placeCall() thread running...");
                     Conference toAdd;
-                    if(call.getAccount().useSecureLayer()){
-                        SecureSipCall secureCall = new SecureSipCall(call);
-                        toAdd = new Conference(secureCall);
-                    } else {
-                        toAdd = new Conference(call);
-                    }
-                    mConferences.put(toAdd.getId(), toAdd);
+                    //mConferences.put(toAdd.getId(), toAdd);
                     mMediaManager.obtainAudioFocus(false);
-                    return Ringservice.placeCall(call.getAccount().getAccountID(), call.getmContact().getPhones().get(0).getNumber());
+
+                    String number = call.getNumber();
+                    if ((number == null || number.isEmpty()) && call.getContact() != null) {
+                        number = call.getContact().getPhones().get(0).getNumber();
+                    }
+
+                    Log.i(TAG, "SipService.placeCall() calling... " + number);
+                    String call_id = Ringservice.placeCall(call.getAccount(), number);
+                    call.setCallID(call_id);
+                    if (!call_id.isEmpty()) {
+                        final Map<String, String> details = getAccountDetails(call.getAccount());
+                        if(details.get(AccountDetailBasic.CONFIG_ACCOUNT_TYPE).contentEquals(AccountDetailBasic.ACCOUNT_TYPE_RING)
+                                || details.get(AccountDetailSrtp.CONFIG_SRTP_ENABLE).contentEquals(AccountDetail.TRUE_STR)
+                                || details.get(AccountDetailTls.CONFIG_TLS_ENABLE).contentEquals(AccountDetail.TRUE_STR)) {
+                            Log.i(TAG, "SipService.placeCall() call is secure");
+                            SecureSipCall secureCall = new SecureSipCall(call, details.get(AccountDetailSrtp.CONFIG_SRTP_KEY_EXCHANGE));
+                            toAdd = new Conference(secureCall);
+                        } else {
+                            toAdd = new Conference(call);
+                        }
+                        Log.i(TAG, "SipService.placeCall() returned with call id " + call_id);
+                        mConferences.put(call_id, toAdd);
+                        Notification noti = new Notification.Builder(SipService.this)
+                                .setContentTitle("Ongoing call with " + call.getContact().getDisplayName())
+                                .setContentText("outgoing call")
+                                .setOngoing(true)
+                                .setSmallIcon(R.drawable.ic_launcher)
+                                //.setContentIntent()
+                                /*.setContentText(subject)
+                                .setSmallIcon(R.drawable.new_mail)
+                                .setLargeIcon(aBitmap)*/
+                                .build();
+                        //startForeground(toAdd.notificationId, noti);
+                        Log.w("CallNotification ", "Adding for outgoing " + toAdd.notificationId);
+                        mNotificationManager.notificationManager.notify(toAdd.notificationId, noti);
+                    }
+                    return call_id;
                 }
             });
         }
 
         @Override
         public void refuse(final String callID) {
-
+            mMediaManager.stopRing();
+            Log.e(TAG, "REFUSE");
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
                     Log.i(TAG, "SipService.refuse() thread running...");
                     Ringservice.refuse(callID);
+                    Ringservice.hangUp(callID);
                 }
             });
         }
@@ -447,6 +525,7 @@
         @Override
         public void accept(final String callID) {
             mMediaManager.stopRing();
+            Log.e(TAG, "ACCEPT");
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
@@ -925,28 +1004,38 @@
         }
 
         @Override
-        public void sendTextMessage(final String callID, final SipMessage message) throws RemoteException {
+        public void sendTextMessage(final String callID, final TextMessage message) throws RemoteException {
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
                     Log.i(TAG, "SipService.sendTextMessage() thread running...");
+                    message.setCallId(callID);
+                    //Conference conf = findConference(callID);
+                    mHistoryManager.insertNewTextMessage(new HistoryText(message));
                     StringMap messages  = new StringMap();
-                    messages.set("text/plain", message.comment);
+                    messages.set("text/plain", message.getMessage());
                     Ringservice.sendTextMessage(callID, messages, "", false);
                     if (getConferences().get(callID) != null)
                         getConferences().get(callID).addSipMessage(message);
+                    Intent intent = new Intent(CallManagerCallBack.INCOMING_TEXT);
+                    intent.putExtra("txt", message);
+                    sendBroadcast(intent);
                 }
             });
-
         }
 
         @Override
-        public void sendAccountTextMessage(final String accountid, final String to, final String msg) {
+        public void sendAccountTextMessage(final String accountID, final String to, final String msg) {
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.sendAccountTextMessage() thread running... " + accountid + " " + to + " " + msg);
-                    Ringservice.sendAccountTextMessage(accountid, to, msg);
+                    Log.i(TAG, "SipService.sendAccountTextMessage() thread running... " + accountID + " " + to + " " + msg);
+                    TextMessage message = new TextMessage(false, msg, to, null, accountID);
+                    mHistoryManager.insertNewTextMessage(new HistoryText(message));
+                    Ringservice.sendAccountTextMessage(accountID, to, msg);
+                    Intent intent = new Intent(ConfigurationManagerCallback.INCOMING_TEXT);
+                    intent.putExtra("txt", message);
+                    sendBroadcast(intent);
                 }
             });
         }
@@ -1271,22 +1360,22 @@
             getConferences().remove(conf.getId());
         else
             conf.removeParticipant(conf.getCallById(callID));
+        Log.w("CallNotification ", "Canceling " + conf.notificationId);
+        mNotificationManager.notificationManager.cancel(conf.notificationId);
     }
 
     protected Conference findConference(String callID) {
-        Conference result = null;
-        if (getConferences().get(callID) != null) {
-            result = getConferences().get(callID);
-        } else {
-            for (Entry<String, Conference> stringConferenceEntry : getConferences().entrySet()) {
-                Conference tmp = stringConferenceEntry.getValue();
-                for (SipCall c : tmp.getParticipants()) {
-                    if (c.getCallId().contentEquals(callID)) {
-                        result = tmp;
-                    }
+        Conference result = getConferences().get(callID);
+        if (result != null)
+            return result;
+        for (Entry<String, Conference> stringConferenceEntry : getConferences().entrySet()) {
+            Conference tmp = stringConferenceEntry.getValue();
+            for (SipCall c : tmp.getParticipants()) {
+                if (c.getCallId() != null && callID.contentEquals(c.getCallId())) {
+                    return tmp;
                 }
             }
         }
-        return result;
+        return null;
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java b/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java
index e1abe4e..c9b59cb 100644
--- a/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java
+++ b/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java
@@ -115,7 +115,7 @@
     }
     
     
-    /**
+    /**5
      * Start ringing announce for a given contact.
      * It will also focus audio for us.
      * @param remoteContact the contact to ring for. May resolve the contact ringtone if any.
diff --git a/ring-android/app/src/main/java/cx/ring/utils/SipNotifications.java b/ring-android/app/src/main/java/cx/ring/utils/SipNotifications.java
index 356552b..76fd929 100644
--- a/ring-android/app/src/main/java/cx/ring/utils/SipNotifications.java
+++ b/ring-android/app/src/main/java/cx/ring/utils/SipNotifications.java
@@ -41,8 +41,6 @@
 import cx.ring.model.Conference;
 import cx.ring.model.SipCall;
 
-import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -51,6 +49,7 @@
 import android.net.sip.SipProfile;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationCompat.Builder;
+import android.support.v4.app.NotificationManagerCompat;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
@@ -58,7 +57,7 @@
 
 public class SipNotifications {
 
-    private final NotificationManager notificationManager;
+    public final NotificationManagerCompat notificationManager;
     private final Context context;
 
     public static final String NOTIF_CREATION = "notif_creation";
@@ -76,7 +75,8 @@
 
     public SipNotifications(Context aContext) {
         context = aContext;
-        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        notificationManager = NotificationManagerCompat.from(aContext);
+        ;//(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
 
         if (!isInit) {
             cancelAll();
@@ -158,7 +158,7 @@
         nb.setTicker(tickerText);
         nb.setWhen(when);
         nb.setContentTitle(context.getString(R.string.notif_missed_call_title));
-        nb.setContentText(context.getString(R.string.notif_missed_call_content, missedConf.getParticipants().get(0).getmContact().getmDisplayName()));
+        nb.setContentText(context.getString(R.string.notif_missed_call_content, missedConf.getParticipants().get(0).getContact().getDisplayName()));
         Intent notificationIntent = new Intent(context, HomeActivity.class);
         notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
         PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
@@ -168,12 +168,11 @@
         nb.setOnlyAlertOnce(true);
         nb.setContentIntent(contentIntent);
 
-        Notification notification = nb.build();
         // We have to re-write content view because getNotification setLatestEventInfo implicitly
         // notification.contentView = contentView;
 
         // startForegroundCompat(CALL_NOTIF_ID, notification);
-        notificationManager.notify(CALL_NOTIF_ID, notification);
+        notificationManager.notify(CALL_NOTIF_ID, nb.build());
     }
 
     public void makeNotification(HashMap<String, SipCall> calls) {
@@ -183,21 +182,20 @@
         Intent notificationIntent = new Intent(context, HomeActivity.class);
         PendingIntent contentIntent = PendingIntent.getActivity(context, 007, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
 
-        NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-        nm.cancel(NOTIFICATION_ID); // clear previous notifications.
+        //NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        notificationManager.cancel(NOTIFICATION_ID); // clear previous notifications.
 
         NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
 
         builder.setContentIntent(contentIntent).setOngoing(true).setSmallIcon(R.drawable.ic_launcher)
                 .setContentTitle(calls.size() + " ongoing calls").setTicker("Pending calls").setWhen(System.currentTimeMillis()).setAutoCancel(false);
         builder.setPriority(NotificationCompat.PRIORITY_MAX);
-        Notification n = builder.build();
 
-        nm.notify(NOTIFICATION_ID, n);
+        notificationManager.notify(NOTIFICATION_ID, builder.build());
     }
 
     public void removeNotification() {
-        NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-        nm.cancel(NOTIFICATION_ID);
+        //NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        notificationManager.cancel(NOTIFICATION_ID);
     }
 }
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/utils/Utilities.java b/ring-android/app/src/main/java/cx/ring/utils/Utilities.java
new file mode 100644
index 0000000..1ac1337
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/utils/Utilities.java
@@ -0,0 +1,35 @@
+package cx.ring.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * This class provides a variety of basic utility methods that are not
+ * dependent on any other classes within the org.jamwiki package structure.
+ */
+public class Utilities {
+    private static final String ipv4Pattern = "(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])";
+    private static final String ipv6Pattern = "([0-9a-f]{1,4}:){7}([0-9a-f]){1,4}";
+    private static final Pattern VALID_IPV4_PATTERN = Pattern.compile(ipv4Pattern, Pattern.CASE_INSENSITIVE);
+    private static final Pattern VALID_IPV6_PATTERN = Pattern.compile(ipv6Pattern, Pattern.CASE_INSENSITIVE);
+
+    /**
+     * Determine if the given string is a valid IPv4 or IPv6 address.  This method
+     * uses pattern matching to see if the given string could be a valid IP address.
+     *
+     * @param ipAddress A string that is to be examined to verify whether or not
+     *                  it could be a valid IP address.
+     * @return <code>true</code> if the string is a value that is a valid IP address,
+     * <code>false</code> otherwise.
+     */
+    public static boolean isIpAddress(String ipAddress) {
+
+        Matcher m1 = VALID_IPV4_PATTERN.matcher(ipAddress);
+        if (m1.matches()) {
+            return true;
+        }
+        Matcher m2 = VALID_IPV6_PATTERN.matcher(ipAddress);
+        return m2.matches();
+    }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/views/CallPaneLayout.java b/ring-android/app/src/main/java/cx/ring/views/CallPaneLayout.java
index c9bd686..cd2afcf 100644
--- a/ring-android/app/src/main/java/cx/ring/views/CallPaneLayout.java
+++ b/ring-android/app/src/main/java/cx/ring/views/CallPaneLayout.java
@@ -60,6 +60,7 @@
 		super(context, attrs, defStyle);
 	}
 
+	/*
 	@Override
 	public boolean onInterceptTouchEvent(MotionEvent event)
 	{
@@ -68,6 +69,6 @@
 		}
 
 		return super.onInterceptTouchEvent(event);
-	}
+	}*/
 
 }
diff --git a/ring-android/app/src/main/java/cx/ring/views/HalfCircleImageView.java b/ring-android/app/src/main/java/cx/ring/views/HalfCircleImageView.java
index e9b0d6a..46ed0d6 100644
--- a/ring-android/app/src/main/java/cx/ring/views/HalfCircleImageView.java
+++ b/ring-android/app/src/main/java/cx/ring/views/HalfCircleImageView.java
@@ -76,7 +76,7 @@
     private void setup()
     {
         backgroundPaint = new Paint();
-        backgroundPaint.setColor(getResources().getColor(R.color.sfl_dark_blue));
+        backgroundPaint.setColor(getResources().getColor(R.color.color_primary_dark));
         backgroundPaint.setAntiAlias(true);
         // init paint
         paint = new Paint();
diff --git a/ring-android/app/src/main/java/cx/ring/views/NumberPickerPreference.java b/ring-android/app/src/main/java/cx/ring/views/NumberPickerPreference.java
index bbf7342..cc6b156 100644
--- a/ring-android/app/src/main/java/cx/ring/views/NumberPickerPreference.java
+++ b/ring-android/app/src/main/java/cx/ring/views/NumberPickerPreference.java
@@ -92,7 +92,7 @@
             throw new RuntimeException("mNumberPicker is null!");
         }
 
-        // Initialize state
+        // Initialize State
         mNumberPicker.setWrapSelectorWheel(false);
         mNumberPicker.setMaxValue(max);
         mNumberPicker.setMinValue(min);
diff --git a/ring-android/app/src/main/java/cx/ring/views/QuadNumberPickerPreference.java b/ring-android/app/src/main/java/cx/ring/views/QuadNumberPickerPreference.java
index 49bf9d3..3604fd2 100644
--- a/ring-android/app/src/main/java/cx/ring/views/QuadNumberPickerPreference.java
+++ b/ring-android/app/src/main/java/cx/ring/views/QuadNumberPickerPreference.java
@@ -127,7 +127,7 @@
             throw new RuntimeException("mNumberPicker1 or mNumberPicker2 is null!");
         }
 
-        // Initialize state
+        // Initialize State
         mNumberPicker1.setWrapSelectorWheel(false);
         mNumberPicker1.setMaxValue(mMax1);
         mNumberPicker1.setMinValue(mMin1);
diff --git a/ring-android/app/src/main/java/cx/ring/views/SwipeListViewTouchListener.java b/ring-android/app/src/main/java/cx/ring/views/SwipeListViewTouchListener.java
deleted file mode 100644
index 8e05466..0000000
--- a/ring-android/app/src/main/java/cx/ring/views/SwipeListViewTouchListener.java
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
- *
- *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
- *
- *  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, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Additional permission under GNU GPL version 3 section 7:
- *
- *  If you modify this program, or any covered work, by linking or
- *  combining it with the OpenSSL project's OpenSSL library (or a
- *  modified version of that library), containing parts covered by the
- *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
- *  grants you additional permission to convey the resulting work.
- *  Corresponding Source for a non-source form of such a combination
- *  shall include the source code for the parts of OpenSSL used as well
- *  as that of the covered work.
- */
-
-package cx.ring.views;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import cx.ring.R;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.graphics.Rect;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.ListView;
-
-public class SwipeListViewTouchListener implements View.OnTouchListener {
-    // Cached ViewConfiguration and system-wide constant values
-    private int mSlop;
-    private int mMinFlingVelocity;
-    private int mMaxFlingVelocity;
-    private long mAnimationTime;
-
-    private static final String TAG = SwipeListViewTouchListener.class.getSimpleName();
-
-    // Fixed properties
-    private ListView mListView;
-    private OnSwipeCallback mCallback;
-    private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
-    private boolean dismissLeft = true;
-    private boolean dismissRight = true;
-
-    // Transient properties
-    private List<PendingSwipeData> mPendingSwipes = new ArrayList<PendingSwipeData>();
-    private int mDismissAnimationRefCount = 0;
-    private float mDownX;
-    private float mDownY;
-    private boolean mSwiping;
-    private VelocityTracker mVelocityTracker;
-    private int mDownPosition;
-    private View mDownView, mUnderDownView;
-    private boolean mPaused;
-
-    /**
-     * The callback interface used by {@link SwipeListViewTouchListener} to inform its client about a successful swipe of one or more list item
-     * positions.
-     */
-    public interface OnSwipeCallback {
-        /**
-         * Called when the user has swiped the list item to the left.
-         * 
-         * @param listView
-         *            The originating {@link ListView}.
-         * @param reverseSortedPositions
-         *            An array of positions to dismiss, sorted in descending order for convenience.
-         */
-        void onSwipeLeft(ListView listView, int[] reverseSortedPositions);
-
-        void onSwipeRight(ListView listView, View downView);
-    }
-
-    /**
-     * Constructs a new swipe-to-action touch listener for the given list view.
-     * 
-     * @param listView
-     *            The list view whose items should be dismissable.
-     * @param callback
-     *            The callback to trigger when the user has indicated that she would like to dismiss one or more list items.
-     */
-    public SwipeListViewTouchListener(ListView listView, OnSwipeCallback callback) {
-        ViewConfiguration vc = ViewConfiguration.get(listView.getContext());
-        mSlop = vc.getScaledTouchSlop();
-        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
-        mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
-        mAnimationTime = listView.getContext().getResources().getInteger(android.R.integer.config_shortAnimTime);
-        mListView = listView;
-        mCallback = callback;
-    }
-
-    /**
-     * Constructs a new swipe-to-action touch listener for the given list view.
-     * 
-     * @param listView
-     *            The list view whose items should be dismissable.
-     * @param callback
-     *            The callback to trigger when the user has indicated that she would like to dismiss one or more list items.
-     * @param dismissLeft
-     *            set if the dismiss animation is up when the user swipe to the left
-     * @param dismissRight
-     *            set if the dismiss animation is up when the user swipe to the right
-     * @see #SwipeListViewTouchListener(ListView, OnSwipeCallback, boolean, boolean)
-     */
-    public SwipeListViewTouchListener(ListView listView, OnSwipeCallback callback, boolean dismissLeft, boolean dismissRight) {
-        this(listView, callback);
-        this.dismissLeft = dismissLeft;
-        this.dismissRight = dismissRight;
-    }
-
-    /**
-     * Enables or disables (pauses or resumes) watching for swipe-to-dismiss gestures.
-     * 
-     * @param enabled
-     *            Whether or not to watch for gestures.
-     */
-    public void setEnabled(boolean enabled) {
-        mPaused = !enabled;
-    }
-
-    /**
-     * Returns an {@link android.widget.AbsListView.OnScrollListener} to be added to the {@link ListView} using
-     * {@link ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener)}. If a scroll listener is already assigned, the caller should
-     * still pass scroll changes through to this listener. This will ensure that this {@link SwipeListViewTouchListener} is paused during list view
-     * scrolling.</p>
-     * 
-     * @see {@link SwipeListViewTouchListener}
-     */
-    public AbsListView.OnScrollListener makeScrollListener() {
-        return new AbsListView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(AbsListView absListView, int scrollState) {
-                setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
-            }
-
-            @Override
-            public void onScroll(AbsListView absListView, int i, int i1, int i2) {
-            }
-        };
-    }
-
-    @Override
-    public boolean onTouch(View item, MotionEvent motionEvent) {
-        if (mViewWidth < 2) {
-            mViewWidth = mListView.getWidth();
-        }
-
-        switch (motionEvent.getActionMasked()) {
-        case MotionEvent.ACTION_DOWN: {
-            if (mPaused) {
-                return false;
-            }
-
-            // TODO: ensure this is a finger, and set a flag
-
-            // Find the child view that was touched (perform a hit test)
-            Rect rect = new Rect();
-            int childCount = mListView.getChildCount();
-            int[] listViewCoords = new int[2];
-            mListView.getLocationOnScreen(listViewCoords);
-            int x = (int) motionEvent.getRawX() - listViewCoords[0];
-            int y = (int) motionEvent.getRawY() - listViewCoords[1];
-            View child;
-            for (int i = 0; i < childCount; i++) {
-                child = mListView.getChildAt(i);
-                child.getHitRect(rect);
-                if (rect.contains(x, y)) {
-                    mDownView = child.findViewById(R.id.contactview);
-                    mUnderDownView = child.findViewById(R.id.contact_underview);
-                    break;
-                }
-            }
-
-            if (mDownView != null) {
-
-                mDownX = motionEvent.getRawX() - mDownView.getTranslationX();
-                mDownY = motionEvent.getRawY();
-                mDownPosition = mListView.getPositionForView(mDownView);
-
-                mVelocityTracker = VelocityTracker.obtain();
-                mVelocityTracker.addMovement(motionEvent);
-            }
-            item.onTouchEvent(motionEvent);
-            return true;
-        }
-
-        case MotionEvent.ACTION_UP: {
-            if (mVelocityTracker == null) {
-                break;
-            }
-
-            float deltaX = motionEvent.getRawX() - mDownX;
-
-            mVelocityTracker.addMovement(motionEvent);
-            mVelocityTracker.computeCurrentVelocity(500); // 1000 by defaut but it was too much
-            float velocityX = Math.abs(mVelocityTracker.getXVelocity());
-            float velocityY = Math.abs(mVelocityTracker.getYVelocity());
-            boolean swipe = false;
-            boolean swipeRight = false;
-
-            if (mDownView.getTranslationX() > mViewWidth / 2) {
-                swipe = true;
-                swipeRight = deltaX > 0;
-            } else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity && velocityY < velocityX) {
-                swipe = true;
-                swipeRight = mVelocityTracker.getXVelocity() > 0;
-            }
-            if (swipe) {
-                // sufficent swipe value
-                final View downView = mDownView; // mDownView gets null'd before animation ends
-                final int downPosition = mDownPosition;
-                final boolean toTheRight = swipeRight;
-                ++mDismissAnimationRefCount;
-
-                if (toTheRight) {
-                    mDownView.animate().translationX(mViewWidth / 2).alpha(1).setDuration(mAnimationTime).setListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mListView.requestDisallowInterceptTouchEvent(false);
-                            // mCallback.onSwipeRight(mListView, mUnderDownView);
-                            toggleUnderLayerState(true);
-                            // performSwipeAction(downView, downPosition, toTheRight,dismissRight);
-                        }
-                    });
-                } else {
-                    mDownView.animate().translationX(0).alpha(1).setDuration(mAnimationTime);
-                }
-
-            } else {
-                // cancel
-                mDownView.animate().translationX(0).alpha(1).setDuration(mAnimationTime).setListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        toggleUnderLayerState(false);
-                        mUnderDownView = null;
-                    }
-                });
-            }
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-            mDownX = 0;
-            mDownView = null;
-            mDownPosition = ListView.INVALID_POSITION;
-            mSwiping = false;
-            break;
-        }
-
-        case MotionEvent.ACTION_MOVE: {
-            if (mVelocityTracker == null || mPaused) {
-                break;
-            }
-
-            mVelocityTracker.addMovement(motionEvent);
-            mVelocityTracker.computeCurrentVelocity(500);
-            float deltaX = motionEvent.getRawX() - mDownX;
-            float deltaY = motionEvent.getRawY() - mDownY;
-
-            if (Math.abs(deltaX) < Math.abs(deltaY)) {
-                mListView.requestDisallowInterceptTouchEvent(false);
-                return false;
-            }
-
-            if (Math.abs(deltaX) > mSlop) {
-                mSwiping = true;
-                mListView.requestDisallowInterceptTouchEvent(true);
-
-                // Cancel ListView's touch (un-highlighting the item)
-                MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
-                cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
-                mListView.onTouchEvent(cancelEvent);
-                cancelEvent.recycle();
-            }
-            if (deltaX < 0)
-                return true;
-
-            if (mSwiping) {
-                mDownView.setTranslationX(deltaX);
-                // mDownView.setAlpha(Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth)));
-                return true;
-            }
-            break;
-        }
-        }
-        return false;
-    }
-
-    private void toggleUnderLayerState(boolean b) {
-        if (mUnderDownView == null)
-            return;
-        mUnderDownView.findViewById(R.id.quick_edit).setClickable(b);
-        mUnderDownView.findViewById(R.id.quick_discard).setClickable(b);
-        mUnderDownView.findViewById(R.id.quick_starred).setClickable(b);
-    }
-
-    class PendingSwipeData implements Comparable<PendingSwipeData> {
-        public int position;
-        public View view;
-
-        public PendingSwipeData(int position, View view) {
-            this.position = position;
-            this.view = view;
-        }
-
-        @Override
-        public int compareTo(PendingSwipeData other) {
-            // Sort by descending position
-            return other.position - position;
-        }
-    }
-
-    private void performSwipeAction(final View swipeView, final int swipePosition, boolean toTheRight, boolean dismiss) {
-        // Animate the dismissed list item to zero-height and fire the dismiss callback when
-        // all dismissed list item animations have completed. This triggers layout on each animation
-        // frame; in the future we may want to do something smarter and more performant.
-
-        final ViewGroup.LayoutParams lp = swipeView.getLayoutParams();
-        final int originalHeight = swipeView.getHeight();
-        final boolean swipeRight = toTheRight;
-
-        ValueAnimator animator;
-        if (dismiss)
-            animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
-        else
-            animator = ValueAnimator.ofInt(originalHeight, originalHeight - 1).setDuration(mAnimationTime);
-
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                --mDismissAnimationRefCount;
-                if (mDismissAnimationRefCount == 0) {
-                    // No active animations, process all pending dismisses.
-                    // Sort by descending position
-                    Collections.sort(mPendingSwipes);
-
-                    int[] swipePositions = new int[mPendingSwipes.size()];
-                    for (int i = mPendingSwipes.size() - 1; i >= 0; i--) {
-                        swipePositions[i] = mPendingSwipes.get(i).position;
-                    }
-                    // if (swipeRight)
-                    // mCallback.onSwipeRight(mListView, swipePositions);
-                    // else
-                    // mCallback.onSwipeLeft(mListView, swipePositions);
-
-                    ViewGroup.LayoutParams lp;
-                    for (PendingSwipeData pendingDismiss : mPendingSwipes) {
-                        // Reset view presentation
-                        pendingDismiss.view.setAlpha(1f);
-                        pendingDismiss.view.setTranslationX(0);
-                        lp = pendingDismiss.view.getLayoutParams();
-                        lp.height = originalHeight;
-                        pendingDismiss.view.setLayoutParams(lp);
-                    }
-
-                    mPendingSwipes.clear();
-                }
-            }
-        });
-
-        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator valueAnimator) {
-                lp.height = (Integer) valueAnimator.getAnimatedValue();
-                swipeView.setLayoutParams(lp);
-            }
-        });
-
-        mPendingSwipes.add(new PendingSwipeData(swipePosition, swipeView));
-        animator.start();
-    }
-
-    public void openItem(View child, int pos, long id) {
-
-        mDownView = child.findViewById(R.id.contactview);
-        mUnderDownView = child.findViewById(R.id.contact_underview);
-        if (mDownView.getTranslationX() > 0)
-            return;
-        mDownView.animate().translationX(mViewWidth / 2).setDuration(mAnimationTime).setListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mListView.requestDisallowInterceptTouchEvent(false);
-                toggleUnderLayerState(true);
-                // performSwipeAction(downView, downPosition, toTheRight,dismissRight);
-            }
-        });
-    }
-}
diff --git a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/AdapterWrapper.java b/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/AdapterWrapper.java
deleted file mode 100644
index 22b02a8..0000000
--- a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/AdapterWrapper.java
+++ /dev/null
@@ -1,225 +0,0 @@
-package cx.ring.views.stickylistheaders;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import android.content.Context;
-import android.database.DataSetObserver;
-import android.graphics.drawable.Drawable;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.Checkable;
-import android.widget.ListAdapter;
-
-/**
- * A {@link ListAdapter} which wraps a {@link StickyListHeadersAdapter} and
- * automatically handles wrapping the result of
- * {@link StickyListHeadersAdapter#getView(int, android.view.View, android.view.ViewGroup)}
- * and
- * {@link StickyListHeadersAdapter#getHeaderView(int, android.view.View, android.view.ViewGroup)}
- * appropriately.
- *
- * @author Jake Wharton (jakewharton@gmail.com)
- */
-class AdapterWrapper extends BaseAdapter implements StickyListHeadersAdapter {
-
-	interface OnHeaderClickListener {
-		public void onHeaderClick(View header, int itemPosition, long headerId);
-	}
-
-	final StickyListHeadersAdapter mDelegate;
-	private final List<View> mHeaderCache = new LinkedList<View>();
-	private final Context mContext;
-	private Drawable mDivider;
-	private int mDividerHeight;
-	private OnHeaderClickListener mOnHeaderClickListener;
-	private DataSetObserver mDataSetObserver = new DataSetObserver() {
-
-		@Override
-		public void onInvalidated() {
-			mHeaderCache.clear();
-			AdapterWrapper.super.notifyDataSetInvalidated();
-		}
-		
-		@Override
-		public void onChanged() {
-			AdapterWrapper.super.notifyDataSetChanged();
-		}
-	};
-
-	AdapterWrapper(Context context,
-			StickyListHeadersAdapter delegate) {
-		this.mContext = context;
-		this.mDelegate = delegate;
-		delegate.registerDataSetObserver(mDataSetObserver);
-	}
-
-	void setDivider(Drawable divider, int dividerHeight) {
-		this.mDivider = divider;
-		this.mDividerHeight = dividerHeight;
-		notifyDataSetChanged();
-	}
-
-	@Override
-	public boolean areAllItemsEnabled() {
-		return mDelegate.areAllItemsEnabled();
-	}
-
-	@Override
-	public boolean isEnabled(int position) {
-		return mDelegate.isEnabled(position);
-	}
-
-	@Override
-	public int getCount() {
-		return mDelegate.getCount();
-	}
-
-	@Override
-	public Object getItem(int position) {
-		return mDelegate.getItem(position);
-	}
-
-	@Override
-	public long getItemId(int position) {
-		return mDelegate.getItemId(position);
-	}
-
-	@Override
-	public boolean hasStableIds() {
-		return mDelegate.hasStableIds();
-	}
-
-	@Override
-	public int getItemViewType(int position) {
-		return mDelegate.getItemViewType(position);
-	}
-
-	@Override
-	public int getViewTypeCount() {
-		return mDelegate.getViewTypeCount();
-	}
-
-	@Override
-	public boolean isEmpty() {
-		return mDelegate.isEmpty();
-	}
-
-	/**
-	 * Will recycle header from {@link WrapperView} if it exists
-	 */
-	private void recycleHeaderIfExists(WrapperView wv) {
-		View header = wv.mHeader;
-		if (header != null) {
-			// reset the headers visibility when adding it to the cache
-			header.setVisibility(View.VISIBLE);
-			mHeaderCache.add(header);
-		}
-	}
-
-	/**
-	 * Get a header view. This optionally pulls a header from the supplied
-	 * {@link WrapperView} and will also recycle the divider if it exists.
-	 */
-	private View configureHeader(WrapperView wv, final int position) {
-		View header = wv.mHeader == null ? popHeader() : wv.mHeader;
-		header = mDelegate.getHeaderView(position, header, wv);
-		if (header == null) {
-			throw new NullPointerException("Header view must not be null.");
-		}
-		//if the header isn't clickable, the listselector will be drawn on top of the header
-		header.setClickable(true);
-		header.setOnClickListener(new OnClickListener() {
-
-			@Override
-			public void onClick(View v) {
-				if(mOnHeaderClickListener != null){
-					long headerId = mDelegate.getHeaderId(position);
-					mOnHeaderClickListener.onHeaderClick(v, position, headerId);
-				}
-			}
-		});
-		return header;
-	}
-
-	private View popHeader() {
-		if(mHeaderCache.size() > 0) {
-			return mHeaderCache.remove(0);
-		}
-		return null;
-	}
-
-	/** Returns {@code true} if the previous position has the same header ID. */
-	private boolean previousPositionHasSameHeader(int position) {
-		return position != 0
-				&& mDelegate.getHeaderId(position) == mDelegate
-						.getHeaderId(position - 1);
-	}
-
-	@Override
-	public WrapperView getView(int position, View convertView, ViewGroup parent) {
-		WrapperView wv = (convertView == null) ? new WrapperView(mContext) : (WrapperView) convertView;
-		View item = mDelegate.getView(position, wv.mItem, parent);
-		View header = null;
-		if (previousPositionHasSameHeader(position)) {
-			recycleHeaderIfExists(wv);
-		} else {
-			header = configureHeader(wv, position);
-		}
-		if((item instanceof Checkable) && !(wv instanceof CheckableWrapperView)) {
-			// Need to create Checkable subclass of WrapperView for ListView to work correctly
-			wv = new CheckableWrapperView(mContext);
-		} else if(!(item instanceof Checkable) && (wv instanceof CheckableWrapperView)) {
-			wv = new WrapperView(mContext);
-		}
-		wv.update(item, header, mDivider, mDividerHeight);
-		return wv;
-	}
-
-	public void setOnHeaderClickListener(OnHeaderClickListener onHeaderClickListener){
-		this.mOnHeaderClickListener = onHeaderClickListener;
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		return mDelegate.equals(o); 
-	}
-
-	@Override
-	public View getDropDownView(int position, View convertView, ViewGroup parent) {
-		return ((BaseAdapter) mDelegate).getDropDownView(position, convertView, parent);
-	}
-
-	@Override
-	public int hashCode() {
-		return mDelegate.hashCode();
-	}
-
-	@Override
-	public void notifyDataSetChanged() {
-		((BaseAdapter) mDelegate).notifyDataSetChanged();
-	}
-
-	@Override
-	public void notifyDataSetInvalidated() {
-		((BaseAdapter) mDelegate).notifyDataSetInvalidated();
-	}
-
-	@Override
-	public String toString() {
-		return mDelegate.toString();
-	}
-
-	@Override
-	public View getHeaderView(int position, View convertView, ViewGroup parent) {
-		return mDelegate.getHeaderView(position, convertView, parent);
-	}
-
-	@Override
-	public long getHeaderId(int position) {
-		return mDelegate.getHeaderId(position);
-	}
-
-}
diff --git a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/ApiLevelTooLowException.java b/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/ApiLevelTooLowException.java
deleted file mode 100644
index 075dfb4..0000000
--- a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/ApiLevelTooLowException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package cx.ring.views.stickylistheaders;
-
-public class ApiLevelTooLowException extends RuntimeException {
-
-    private static final long serialVersionUID = -5480068364264456757L;
-
-    public ApiLevelTooLowException(int versionCode) {
-        super("Requires API level " + versionCode);
-    }
-
-}
diff --git a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/CheckableWrapperView.java b/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/CheckableWrapperView.java
deleted file mode 100644
index e22204f..0000000
--- a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/CheckableWrapperView.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package cx.ring.views.stickylistheaders;
-
-import android.content.Context;
-import android.widget.Checkable;
-
-/**
- * A WrapperView that implements the checkable interface
- * 
- * @author Emil Sjölander
- */
-class CheckableWrapperView extends WrapperView implements Checkable {
-
-	public CheckableWrapperView(final Context context) {
-		super(context);
-	}
-
-	@Override
-	public boolean isChecked() {
-		return ((Checkable) mItem).isChecked();
-	}
-
-	@Override
-	public void setChecked(final boolean checked) {
-		((Checkable) mItem).setChecked(checked);
-	}
-
-	@Override
-	public void toggle() {
-		setChecked(!isChecked());
-	}
-}
diff --git a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/SectionIndexerAdapterWrapper.java b/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/SectionIndexerAdapterWrapper.java
deleted file mode 100644
index dd823ff..0000000
--- a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/SectionIndexerAdapterWrapper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package cx.ring.views.stickylistheaders;
-
-import android.content.Context;
-import android.widget.SectionIndexer;
-
-class SectionIndexerAdapterWrapper extends
-		AdapterWrapper implements SectionIndexer {
-	
-	final SectionIndexer mSectionIndexerDelegate;
-
-	SectionIndexerAdapterWrapper(Context context,
-			StickyListHeadersAdapter delegate) {
-		super(context, delegate);
-		mSectionIndexerDelegate = (SectionIndexer) delegate;
-	}
-
-	@Override
-	public int getPositionForSection(int section) {
-		return mSectionIndexerDelegate.getPositionForSection(section);
-	}
-
-	@Override
-	public int getSectionForPosition(int position) {
-		return mSectionIndexerDelegate.getSectionForPosition(position);
-	}
-
-	@Override
-	public Object[] getSections() {
-		return mSectionIndexerDelegate.getSections();
-	}
-
-}
diff --git a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/StickyListHeadersAdapter.java b/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/StickyListHeadersAdapter.java
deleted file mode 100644
index 236338d..0000000
--- a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/StickyListHeadersAdapter.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package cx.ring.views.stickylistheaders;
-
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListAdapter;
-
-public interface StickyListHeadersAdapter extends ListAdapter {
-	/**
-	 * Get a View that displays the header data at the specified position in the
-	 * set. You can either create a View manually or inflate it from an XML layout
-	 * file.
-	 *
-	 * @param position
-	 * The position of the item within the adapter's data set of the item whose
-	 * header view we want.
-	 * @param convertView
-	 * The old view to reuse, if possible. Note: You should check that this view is
-	 * non-null and of an appropriate type before using. If it is not possible to
-	 * convert this view to display the correct data, this method can create a new
-	 * view.
-	 * @param parent
-	 * The parent that this view will eventually be attached to.
-	 * @return
-	 * A View corresponding to the data at the specified position.
-	 */
-	View getHeaderView(int position, View convertView, ViewGroup parent);
-
-	/**
-	 * Get the header id associated with the specified position in the list.
-	 *
-	 * @param position
-	 * The position of the item within the adapter's data set whose header id we
-	 * want.
-	 * @return
-	 * The id of the header at the specified position.
-	 */
-	long getHeaderId(int position);
-}
diff --git a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/StickyListHeadersListView.java b/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/StickyListHeadersListView.java
deleted file mode 100644
index 72780e9..0000000
--- a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/StickyListHeadersListView.java
+++ /dev/null
@@ -1,993 +0,0 @@
-package cx.ring.views.stickylistheaders;
-
-import cx.ring.R;
-import cx.ring.adapters.ContactsAdapter;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.database.DataSetObserver;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.util.AttributeSet;
-import android.util.SparseBooleanArray;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView.OnItemLongClickListener;
-import android.widget.FrameLayout;
-import android.widget.ListView;
-import android.widget.SectionIndexer;
-
-/**
- * Even though this is a FrameLayout subclass we it is called a ListView. This
- * is because of 2 reasons. 1. It acts like as ListView 2. It used to be a
- * ListView subclass and i did not was to change to name causing compatibility
- * errors.
- * 
- * @author Emil Sjölander
- */
-public class StickyListHeadersListView extends FrameLayout {
-
-	public interface OnHeaderClickListener {
-		public void onHeaderClick(StickyListHeadersListView l, View header,
-				int itemPosition, long headerId, boolean currentlySticky);
-	}
-
-	/* --- Children --- */
-	private WrapperViewList mList;
-	private View mHeader;
-
-	/* --- Header state --- */
-	private Long mHeaderId;
-	// used to not have to call getHeaderId() all the time
-	private Integer mHeaderPosition;
-	private Integer mHeaderOffset;
-
-	/* --- Delegates --- */
-	private OnScrollListener mOnScrollListenerDelegate;
-
-	/* --- Settings --- */
-	private boolean mAreHeadersSticky = true;
-	private boolean mClippingToPadding = true;
-	private boolean mIsDrawingListUnderStickyHeader = true;
-	private int mPaddingLeft = 0;
-	private int mPaddingTop = 0;
-	private int mPaddingRight = 0;
-	private int mPaddingBottom = 0;
-
-	/* --- Other --- */
-	private AdapterWrapper mAdapter;
-	private OnHeaderClickListener mOnHeaderClickListener;
-	private Drawable mDivider;
-	private int mDividerHeight;
-	private AdapterWrapperDataSetObserver mDataSetObserver;
-
-	public StickyListHeadersListView(Context context) {
-		this(context, null);
-	}
-
-	public StickyListHeadersListView(Context context, AttributeSet attrs) {
-		this(context, attrs, 0);
-	}
-
-	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
-	public StickyListHeadersListView(Context context, AttributeSet attrs,
-			int defStyle) {
-		super(context, attrs, defStyle);
-
-		// Initialize the list
-		mList = new WrapperViewList(context, attrs);
-		mDivider = mList.getDivider();
-		mDividerHeight = mList.getDividerHeight();
-
-		// null out divider, dividers are handled by adapter so they look good
-		// with headers
-		mList.setDivider(null);
-		mList.setDividerHeight(0);
-
-		mList.setLifeCycleListener(new WrapperViewListLifeCycleListener());
-		mList.setOnScrollListener(new WrapperListScrollListener());
-		addView(mList);
-
-		if (attrs != null) {
-			TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
-					R.styleable.StickyListHeadersListView, 0, 0);
-
-			try {
-				// Android attributes
-				if (a.hasValue(R.styleable.StickyListHeadersListView_android_padding)) {
-					int padding = a
-							.getDimensionPixelSize(
-									R.styleable.StickyListHeadersListView_android_padding,
-									0);
-					mPaddingLeft = padding;
-					mPaddingTop = padding;
-					mPaddingRight = padding;
-					mPaddingBottom = padding;
-				} else {
-					mPaddingLeft = a
-							.getDimensionPixelSize(
-									R.styleable.StickyListHeadersListView_android_paddingLeft,
-									0);
-					mPaddingTop = a
-							.getDimensionPixelSize(
-									R.styleable.StickyListHeadersListView_android_paddingTop,
-									0);
-					mPaddingRight = a
-							.getDimensionPixelSize(
-									R.styleable.StickyListHeadersListView_android_paddingRight,
-									0);
-					mPaddingBottom = a
-							.getDimensionPixelSize(
-									R.styleable.StickyListHeadersListView_android_paddingBottom,
-									0);
-				}
-				setPadding(mPaddingLeft, mPaddingTop, mPaddingRight,
-						mPaddingBottom);
-
-				// Set clip to padding on the list and reset value to default on
-				// wrapper
-				mClippingToPadding = a
-						.getBoolean(
-								R.styleable.StickyListHeadersListView_android_clipToPadding,
-								true);
-				super.setClipToPadding(true);
-				mList.setClipToPadding(mClippingToPadding);
-
-				// ListView attributes
-				mList.setFadingEdgeLength(a
-						.getDimensionPixelSize(
-								R.styleable.StickyListHeadersListView_android_fadingEdgeLength,
-								mList.getVerticalFadingEdgeLength()));
-				final int fadingEdge = a
-						.getInt(R.styleable.StickyListHeadersListView_android_requiresFadingEdge,
-								0);
-				if (fadingEdge == 0x00001000) {
-					mList.setVerticalFadingEdgeEnabled(false);
-					mList.setHorizontalFadingEdgeEnabled(true);
-				} else if (fadingEdge == 0x00002000) {
-					mList.setVerticalFadingEdgeEnabled(true);
-					mList.setHorizontalFadingEdgeEnabled(false);
-				} else {
-					mList.setVerticalFadingEdgeEnabled(false);
-					mList.setHorizontalFadingEdgeEnabled(false);
-				}
-				mList.setCacheColorHint(a
-						.getColor(
-								R.styleable.StickyListHeadersListView_android_cacheColorHint,
-								mList.getCacheColorHint()));
-				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-					mList.setChoiceMode(a
-							.getInt(R.styleable.StickyListHeadersListView_android_choiceMode,
-									mList.getChoiceMode()));
-				}
-				mList.setDrawSelectorOnTop(a
-						.getBoolean(
-								R.styleable.StickyListHeadersListView_android_drawSelectorOnTop,
-								false));
-				mList.setFastScrollEnabled(a
-						.getBoolean(
-								R.styleable.StickyListHeadersListView_android_fastScrollEnabled,
-								mList.isFastScrollEnabled()));
-				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-					mList.setFastScrollAlwaysVisible(a
-							.getBoolean(
-									R.styleable.StickyListHeadersListView_android_fastScrollAlwaysVisible,
-									mList.isFastScrollAlwaysVisible()));
-				}
-				mList.setScrollBarStyle(a
-						.getInt(R.styleable.StickyListHeadersListView_android_scrollbarStyle,
-								0));
-				final Drawable selector = a
-						.getDrawable(R.styleable.StickyListHeadersListView_android_listSelector);
-				if (selector != null) {
-					mList.setSelector(selector);
-				}
-				mList.setScrollingCacheEnabled(a
-						.getBoolean(
-								R.styleable.StickyListHeadersListView_android_scrollingCache,
-								mList.isScrollingCacheEnabled()));
-				final Drawable divider = a
-						.getDrawable(R.styleable.StickyListHeadersListView_android_divider);
-				if (divider != null) {
-					mDivider = divider;
-				}
-				mDividerHeight = a
-						.getDimensionPixelSize(
-								R.styleable.StickyListHeadersListView_android_dividerHeight,
-								mDividerHeight);
-
-				// StickyListHeaders attributes
-				mAreHeadersSticky = a.getBoolean(
-						R.styleable.StickyListHeadersListView_hasStickyHeaders,
-						true);
-				mIsDrawingListUnderStickyHeader = a
-						.getBoolean(
-								R.styleable.StickyListHeadersListView_isDrawingListUnderStickyHeader,
-								true);
-            } finally {
-				a.recycle();
-			}
-		}
-
-        mList.setVerticalScrollBarEnabled(isVerticalScrollBarEnabled());
-        mList.setHorizontalScrollBarEnabled(isHorizontalScrollBarEnabled());
-    }
-
-	@Override
-	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-		measureHeader(mHeader);
-	}
-
-	private void ensureHeaderHasCorrectLayoutParams(View header) {
-		ViewGroup.LayoutParams lp = header.getLayoutParams();
-		if (lp == null) {
-			lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
-		} else if (lp.height == LayoutParams.MATCH_PARENT) {
-			lp.height = LayoutParams.WRAP_CONTENT;
-		}
-		header.setLayoutParams(lp);
-	}
-
-	private void measureHeader(View header) {
-		if (header != null) {
-			final int width = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
-			final int parentWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
-					width, MeasureSpec.EXACTLY);
-			final int parentHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0,
-					MeasureSpec.UNSPECIFIED);
-			measureChild(header, parentWidthMeasureSpec,
-					parentHeightMeasureSpec);
-		}
-	}
-
-	@Override
-	protected void onLayout(boolean changed, int left, int top, int right,
-			int bottom) {
-		mList.layout(0, 0, mList.getMeasuredWidth(), getHeight());
-		if (mHeader != null) {
-			MarginLayoutParams lp = (MarginLayoutParams) mHeader
-					.getLayoutParams();
-			int headerTop = lp.topMargin
-					+ (mClippingToPadding ? mPaddingTop : 0);
-			// The left parameter must for some reason be set to 0.
-			// I think it should be set to mPaddingLeft but apparently not
-			mHeader.layout(mPaddingLeft, headerTop, mHeader.getMeasuredWidth()
-					+ mPaddingLeft, headerTop + mHeader.getMeasuredHeight());
-		}
-	}
-
-	@Override
-	protected void dispatchDraw(Canvas canvas) {
-		// Only draw the list here.
-		// The header should be drawn right after the lists children are drawn.
-		// This is done so that the header is above the list items
-		// but below the list decorators (scroll bars etc).
-		drawChild(canvas, mList, 0);
-	}
-
-	// Reset values tied the header. also remove header form layout
-	// This is called in response to the data set or the adapter changing
-	private void clearHeader() {
-		if (mHeader != null) {
-			removeView(mHeader);
-			mHeader = null;
-			mHeaderId = null;
-			mHeaderPosition = null;
-			mHeaderOffset = null;
-
-			// reset the top clipping length
-			mList.setTopClippingLength(0);
-			updateHeaderVisibilities();
-		}
-	}
-
-	private void updateOrClearHeader(int firstVisiblePosition) {
-		final int adapterCount = mAdapter == null ? 0 : mAdapter.getCount();
-		if (adapterCount == 0 || !mAreHeadersSticky) {
-			return;
-		}
-
-		final int headerViewCount = mList.getHeaderViewsCount();
-		final int realFirstVisibleItem = firstVisiblePosition - headerViewCount;
-
-		// It is not a mistake to call getFirstVisiblePosition() here.
-		// Most of the time getFixedFirstVisibleItem() should be called
-		// but that does not work great together with getChildAt()
-		final boolean doesListHaveChildren = mList.getChildCount() != 0;
-		final boolean isFirstViewBelowTop = doesListHaveChildren && mList.getFirstVisiblePosition() == 0
-				&& mList.getChildAt(0).getTop() > 0;
-		final boolean isFirstVisibleItemOutsideAdapterRange = realFirstVisibleItem > adapterCount - 1
-				|| realFirstVisibleItem < 0;
-		if (!doesListHaveChildren || isFirstVisibleItemOutsideAdapterRange
-				|| isFirstViewBelowTop) {
-			clearHeader();
-			return;
-		}
-
-		updateHeader(realFirstVisibleItem);
-	}
-
-	private void updateHeader(int firstVisiblePosition) {
-
-		// check if there is a new header should be sticky
-		if (mHeaderPosition == null || mHeaderPosition != firstVisiblePosition) {
-			mHeaderPosition = firstVisiblePosition;
-			final long headerId = mAdapter.getHeaderId(firstVisiblePosition);
-			if (mHeaderId == null || mHeaderId != headerId) {
-				mHeaderId = headerId;
-				final View header = mAdapter.getHeaderView(mHeaderPosition,
-						mHeader, this);
-				if (mHeader != header) {
-					if (header == null) {
-						throw new NullPointerException("header may not be null");
-					}
-					swapHeader(header);
-				}
-				
-				ensureHeaderHasCorrectLayoutParams(mHeader);
-				measureHeader(mHeader);
-
-				// Reset mHeaderOffset to null ensuring
-				// that it will be set on the header and
-				// not skipped for performance reasons.
-				mHeaderOffset = null;
-			}
-		}
-
-		int headerOffset = 0;
-
-		// Calculate new header offset
-		// Skip looking at the first view. it never matters because it always
-		// results in a headerOffset = 0
-		int headerBottom = mHeader.getMeasuredHeight()
-				+ (mClippingToPadding ? mPaddingTop : 0);
-		for (int i = 0; i < mList.getChildCount(); i++) {
-			final View child = mList.getChildAt(i);
-			final boolean doesChildHaveHeader = child instanceof WrapperView
-					&& ((WrapperView) child).hasHeader();
-			final boolean isChildFooter = mList.containsFooterView(child);
-			if (child.getTop() >= (mClippingToPadding ? mPaddingTop : 0)
-					&& (doesChildHaveHeader || isChildFooter)) {
-				headerOffset = Math.min(child.getTop() - headerBottom, 0);
-				break;
-			}
-		}
-
-		setHeaderOffet(headerOffset);
-
-		if (!mIsDrawingListUnderStickyHeader) {
-			mList.setTopClippingLength(mHeader.getMeasuredHeight()
-					+ mHeaderOffset);
-		}
-
-		updateHeaderVisibilities();
-	}
-
-	private void swapHeader(View newHeader) {
-		if (mHeader != null) {
-			removeView(mHeader);
-		}
-		mHeader = newHeader;
-		addView(mHeader);
-		mHeader.setOnClickListener(new OnClickListener() {
-
-			@Override
-			public void onClick(View v) {
-				if (mOnHeaderClickListener != null) {
-					mOnHeaderClickListener.onHeaderClick(
-							StickyListHeadersListView.this, mHeader,
-							mHeaderPosition, mHeaderId, true);
-				}
-			}
-
-		});
-	}
-
-	// hides the headers in the list under the sticky header.
-	// Makes sure the other ones are showing
-	private void updateHeaderVisibilities() {
-		int top;
-		if (mHeader != null) {
-			top = mHeader.getMeasuredHeight()
-					+ (mHeaderOffset != null ? mHeaderOffset : 0);
-		} else {
-			top = mClippingToPadding ? mPaddingTop : 0;
-		}
-		int childCount = mList.getChildCount();
-		for (int i = 0; i < childCount; i++) {
-			View child = mList.getChildAt(i);
-			if (child instanceof WrapperView) {
-				WrapperView wrapperViewChild = (WrapperView) child;
-				if (wrapperViewChild.hasHeader()) {
-					View childHeader = wrapperViewChild.mHeader;
-					if (wrapperViewChild.getTop() < top) {
-						if (childHeader.getVisibility() != View.INVISIBLE) {
-							childHeader.setVisibility(View.INVISIBLE);
-						}
-					} else {
-						if (childHeader.getVisibility() != View.VISIBLE) {
-							childHeader.setVisibility(View.VISIBLE);
-						}
-					}
-				}
-			}
-		}
-	}
-
-	// Wrapper around setting the header offset in different ways depending on
-	// the API version
-	@SuppressLint("NewApi")
-	private void setHeaderOffet(int offset) {
-		if (mHeaderOffset == null || mHeaderOffset != offset) {
-			mHeaderOffset = offset;
-			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-				mHeader.setTranslationY(mHeaderOffset);
-			} else {
-				MarginLayoutParams params = (MarginLayoutParams) mHeader
-						.getLayoutParams();
-				params.topMargin = mHeaderOffset;
-				mHeader.setLayoutParams(params);
-			}
-		}
-	}
-
-	private class AdapterWrapperDataSetObserver extends DataSetObserver {
-
-		@Override
-		public void onChanged() {
-			clearHeader();
-		}
-
-		@Override
-		public void onInvalidated() {
-			clearHeader();
-		}
-
-	}
-
-	private class WrapperListScrollListener implements OnScrollListener {
-
-		@Override
-		public void onScroll(AbsListView view, int firstVisibleItem,
-				int visibleItemCount, int totalItemCount) {
-			if (mOnScrollListenerDelegate != null) {
-				mOnScrollListenerDelegate.onScroll(view, firstVisibleItem,
-						visibleItemCount, totalItemCount);
-			}
-			updateOrClearHeader(mList.getFixedFirstVisibleItem());
-		}
-
-		@Override
-		public void onScrollStateChanged(AbsListView view, int scrollState) {
-			if (mOnScrollListenerDelegate != null) {
-				mOnScrollListenerDelegate.onScrollStateChanged(view,
-						scrollState);
-			}
-		}
-
-	}
-
-	private class WrapperViewListLifeCycleListener implements WrapperViewList.LifeCycleListener {
-
-		@Override
-		public void onDispatchDrawOccurred(Canvas canvas) {
-			// onScroll is not called often at all before froyo
-			// therefor we need to update the header here as well.
-			if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
-				updateOrClearHeader(mList.getFixedFirstVisibleItem());
-			}
-			if (mHeader != null) {
-				if (mClippingToPadding) {
-					canvas.save();
-					canvas.clipRect(0, mPaddingTop, getRight(), getBottom());
-					drawChild(canvas, mHeader, 0);
-					canvas.restore();
-				} else {
-					drawChild(canvas, mHeader, 0);
-				}
-			}
-		}
-
-	}
-
-	private class AdapterWrapperHeaderClickHandler implements
-			AdapterWrapper.OnHeaderClickListener {
-
-		@Override
-		public void onHeaderClick(View header, int itemPosition, long headerId) {
-			mOnHeaderClickListener.onHeaderClick(
-					StickyListHeadersListView.this, header, itemPosition,
-					headerId, false);
-		}
-
-	}
-
-	private boolean isStartOfSection(int position) {
-		return position == 0
-				|| mAdapter.getHeaderId(position) != mAdapter
-						.getHeaderId(position - 1);
-	}
-
-	private int getHeaderOverlap(int position) {
-		boolean isStartOfSection = isStartOfSection(position);
-		if (!isStartOfSection) {
-			View header = mAdapter.getHeaderView(position, null, mList);
-			if (header == null) {
-				throw new NullPointerException("header may not be null");
-			}
-			ensureHeaderHasCorrectLayoutParams(header);
-			measureHeader(header);
-			return header.getMeasuredHeight();
-		}
-		return 0;
-	}
-
-	/* ---------- StickyListHeaders specific API ---------- */
-
-	public void setAreHeadersSticky(boolean areHeadersSticky) {
-		mAreHeadersSticky = areHeadersSticky;
-		if (!areHeadersSticky) {
-			clearHeader();
-		} else {
-			updateOrClearHeader(mList.getFixedFirstVisibleItem());
-		}
-		// invalidating the list will trigger dispatchDraw()
-		mList.invalidate();
-	}
-
-	public boolean areHeadersSticky() {
-		return mAreHeadersSticky;
-	}
-
-	/**
-	 * Use areHeadersSticky() method instead
-	 */
-	@Deprecated
-	public boolean getAreHeadersSticky() {
-		return areHeadersSticky();
-	}
-
-	public void setDrawingListUnderStickyHeader(
-			boolean drawingListUnderStickyHeader) {
-		mIsDrawingListUnderStickyHeader = drawingListUnderStickyHeader;
-		// reset the top clipping length
-		mList.setTopClippingLength(0);
-	}
-
-	public boolean isDrawingListUnderStickyHeader() {
-		return mIsDrawingListUnderStickyHeader;
-	}
-
-	public void setOnHeaderClickListener(
-			OnHeaderClickListener onHeaderClickListener) {
-		mOnHeaderClickListener = onHeaderClickListener;
-		if (mAdapter != null) {
-			if (mOnHeaderClickListener != null) {
-				mAdapter.setOnHeaderClickListener(new AdapterWrapperHeaderClickHandler());
-			} else {
-				mAdapter.setOnHeaderClickListener(null);
-			}
-		}
-	}
-
-	public View getListChildAt(int index) {
-		return mList.getChildAt(index);
-	}
-
-	public int getListChildCount() {
-		return mList.getChildCount();
-	}
-
-	/**
-	 * Use the method with extreme caution!! Changing any values on the
-	 * underlying ListView might break everything.
-	 * 
-	 * @return the ListView backing this view.
-	 */
-	public ListView getWrappedList() {
-		return mList;
-	}
-
-	/* ---------- ListView delegate methods ---------- */
-
-	public void setAdapter(StickyListHeadersAdapter adapter) {
-		if (adapter == null) {
-			mList.setAdapter(null);
-			clearHeader();
-			return;
-		}
-		if (mAdapter != null) {
-			mAdapter.unregisterDataSetObserver(mDataSetObserver);
-		}
-
-		if (adapter instanceof SectionIndexer) {
-			mAdapter = new SectionIndexerAdapterWrapper(getContext(), adapter);
-		} else {
-			mAdapter = new AdapterWrapper(getContext(), adapter);
-		}
-		mDataSetObserver = new AdapterWrapperDataSetObserver();
-		mAdapter.registerDataSetObserver(mDataSetObserver);
-
-		if (mOnHeaderClickListener != null) {
-			mAdapter.setOnHeaderClickListener(new AdapterWrapperHeaderClickHandler());
-		} else {
-			mAdapter.setOnHeaderClickListener(null);
-		}
-
-		mAdapter.setDivider(mDivider, mDividerHeight);
-
-		mList.setAdapter(mAdapter);
-		clearHeader();
-	}
-
-	public StickyListHeadersAdapter getAdapter() {
-		return mAdapter == null ? null : mAdapter.mDelegate;
-	}
-
-	public void setDivider(Drawable divider) {
-		mDivider = divider;
-		if (mAdapter != null) {
-			mAdapter.setDivider(mDivider, mDividerHeight);
-		}
-	}
-
-	public void setDividerHeight(int dividerHeight) {
-		mDividerHeight = dividerHeight;
-		if (mAdapter != null) {
-			mAdapter.setDivider(mDivider, mDividerHeight);
-		}
-	}
-
-	public Drawable getDivider() {
-		return mDivider;
-	}
-
-	public int getDividerHeight() {
-		return mDividerHeight;
-	}
-
-	public void setOnScrollListener(OnScrollListener onScrollListener) {
-		mOnScrollListenerDelegate = onScrollListener;
-	}
-
-	public void setOnItemClickListener(OnItemClickListener listener) {
-		mList.setOnItemClickListener(listener);
-	}
-
-	public void setOnItemLongClickListener(OnItemLongClickListener listener) {
-		mList.setOnItemLongClickListener(listener);
-	}
-
-    public void addHeaderView(View v, Object data, boolean isSelectable) {
-        mList.addHeaderView(v, data, isSelectable);
-    }
-
-	public void addHeaderView(View v) {
-		mList.addHeaderView(v);
-	}
-
-	public void removeHeaderView(View v) {
-		mList.removeHeaderView(v);
-	}
-
-	public int getHeaderViewsCount() {
-		return mList.getHeaderViewsCount();
-	}
-
-	public void addFooterView(View v) {
-		mList.addFooterView(v);
-	}
-
-	public void removeFooterView(View v) {
-		mList.removeFooterView(v);
-	}
-
-	public int getFooterViewsCount() {
-		return mList.getFooterViewsCount();
-	}
-
-	public void setEmptyView(View v) {
-		mList.setEmptyView(v);
-	}
-
-	public View getEmptyView() {
-		return mList.getEmptyView();
-	}
-
-    @Override
-    public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) {
-        mList.setVerticalScrollBarEnabled(verticalScrollBarEnabled);
-    }
-
-    @Override
-    public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) {
-        mList.setHorizontalScrollBarEnabled(horizontalScrollBarEnabled);
-    }
-
-	@TargetApi(Build.VERSION_CODES.FROYO)
-	public void smoothScrollBy(int distance, int duration) {
-		requireSdkVersion(Build.VERSION_CODES.FROYO);
-		mList.smoothScrollBy(distance, duration);
-	}
-
-	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
-	public void smoothScrollByOffset(int offset) {
-		requireSdkVersion(Build.VERSION_CODES.HONEYCOMB);
-		mList.smoothScrollByOffset(offset);
-	}
-
-	@SuppressLint("NewApi")
-	@TargetApi(Build.VERSION_CODES.FROYO)
-	public void smoothScrollToPosition(int position) {
-		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
-			mList.smoothScrollToPosition(position);
-		} else {
-			int offset = mAdapter == null ? 0 : getHeaderOverlap(position);
-			offset -= mClippingToPadding ? 0 : mPaddingTop;
-			mList.smoothScrollToPositionFromTop(position, offset);
-		}
-	}
-
-	@TargetApi(Build.VERSION_CODES.FROYO)
-	public void smoothScrollToPosition(int position, int boundPosition) {
-		requireSdkVersion(Build.VERSION_CODES.FROYO);
-		mList.smoothScrollToPosition(position, boundPosition);
-	}
-
-	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
-	public void smoothScrollToPositionFromTop(int position, int offset) {
-		requireSdkVersion(Build.VERSION_CODES.HONEYCOMB);
-		offset += mAdapter == null ? 0 : getHeaderOverlap(position);
-		offset -= mClippingToPadding ? 0 : mPaddingTop;
-		mList.smoothScrollToPositionFromTop(position, offset);
-	}
-
-	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
-	public void smoothScrollToPositionFromTop(int position, int offset,
-			int duration) {
-		requireSdkVersion(Build.VERSION_CODES.HONEYCOMB);
-		offset += mAdapter == null ? 0 : getHeaderOverlap(position);
-		offset -= mClippingToPadding ? 0 : mPaddingTop;
-		mList.smoothScrollToPositionFromTop(position, offset, duration);
-	}
-
-	public void setSelection(int position) {
-		setSelectionFromTop(position, 0);
-	}
-
-	public void setSelectionAfterHeaderView() {
-		mList.setSelectionAfterHeaderView();
-	}
-
-	public void setSelectionFromTop(int position, int y) {
-		y += mAdapter == null ? 0 : getHeaderOverlap(position);
-		y -= mClippingToPadding ? 0 : mPaddingTop;
-		mList.setSelectionFromTop(position, y);
-	}
-
-	public void setSelector(Drawable sel) {
-		mList.setSelector(sel);
-	}
-
-	public void setSelector(int resID) {
-		mList.setSelector(resID);
-	}
-
-	public int getFirstVisiblePosition() {
-		return mList.getFirstVisiblePosition();
-	}
-
-	public int getLastVisiblePosition() {
-		return mList.getLastVisiblePosition();
-	}
-
-	public void setChoiceMode(int choiceMode) {
-		mList.setChoiceMode(choiceMode);
-	}
-
-	public void setItemChecked(int position, boolean value) {
-		mList.setItemChecked(position, value);
-	}
-
-	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
-	public int getCheckedItemCount() {
-		requireSdkVersion(Build.VERSION_CODES.HONEYCOMB);
-		return mList.getCheckedItemCount();
-	}
-
-	@TargetApi(Build.VERSION_CODES.FROYO)
-	public long[] getCheckedItemIds() {
-		requireSdkVersion(Build.VERSION_CODES.FROYO);
-		return mList.getCheckedItemIds();
-	}
-
-	public int getCheckedItemPosition() {
-		return mList.getCheckedItemPosition();
-	}
-
-	public SparseBooleanArray getCheckedItemPositions() {
-		return mList.getCheckedItemPositions();
-	}
-
-	public int getCount() {
-		return mList.getCount();
-	}
-
-	public Object getItemAtPosition(int position) {
-		return mList.getItemAtPosition(position);
-	}
-
-	public long getItemIdAtPosition(int position) {
-		return mList.getItemIdAtPosition(position);
-	}
-
-	public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) {
-		mList.setOnCreateContextMenuListener(l);
-	}
-
-	public boolean showContextMenu() {
-		return mList.showContextMenu();
-	}
-
-	public void invalidateViews() {
-		mList.invalidateViews();
-	}
-
-	@Override
-	public void setClipToPadding(boolean clipToPadding) {
-		if (mList != null) {
-			mList.setClipToPadding(clipToPadding);
-		}
-		mClippingToPadding = clipToPadding;
-	}
-
-	@Override
-	public void setPadding(int left, int top, int right, int bottom) {
-		mPaddingLeft = left;
-		mPaddingTop = top;
-		mPaddingRight = right;
-		mPaddingBottom = bottom;
-
-		if (mList != null) {
-			mList.setPadding(left, top, right, bottom);
-		}
-		super.setPadding(0, 0, 0, 0);
-		requestLayout();
-	}
-
-	@Override
-	public int getPaddingLeft() {
-		return mPaddingLeft;
-	}
-
-	@Override
-	public int getPaddingTop() {
-		return mPaddingTop;
-	}
-
-	@Override
-	public int getPaddingRight() {
-		return mPaddingRight;
-	}
-
-	@Override
-	public int getPaddingBottom() {
-		return mPaddingBottom;
-	}
-
-	public void setFastScrollEnabled(boolean fastScrollEnabled) {
-		mList.setFastScrollEnabled(fastScrollEnabled);
-	}
-
-	/**
-	 * @see android.widget.AbsListView#setFastScrollAlwaysVisible(boolean)
-	 * @throws ApiLevelTooLowException on pre-Honeycomb device.
-	 */
-	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
-	public void setFastScrollAlwaysVisible(boolean alwaysVisible) {
-		requireSdkVersion(Build.VERSION_CODES.HONEYCOMB);
-		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-			mList.setFastScrollAlwaysVisible(alwaysVisible);
-		}
-	}
-
-	/**
-	 * @see android.widget.AbsListView#isFastScrollAlwaysVisible()
-	 * @return true if the fast scroller will always show. False on pre-Honeycomb devices.
-	 */
-	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
-	public boolean isFastScrollAlwaysVisible(){
-		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
-			return false;
-		}
-		return mList.isFastScrollAlwaysVisible();
-	}
-
-	private void requireSdkVersion(int versionCode) {
-		if (Build.VERSION.SDK_INT < versionCode) {
-			throw new ApiLevelTooLowException(versionCode);
-		}
-	}
-
-	public int getPositionForView(View view) {
-		return mList.getPositionForView(view);
-	}
-	
-
-	
-	
-	
-    private int mTotalCount;
-    private int mItemOffsetY[];
-    private boolean scrollIsComputed = false;
-    private int mHeight;
-    
-    
-	public int getListHeight() {
-        return mHeight;
-    }
-
-    public void computeScrollY() {
-        mHeight = 0;
-        mTotalCount = getAdapter().getCount();
-
-        int sectionHeight = 0;
-        int itemHeight = 0;
-        int desiredWidth = MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST);
-
-        if (mItemOffsetY == null) {
-            mItemOffsetY = new int[mTotalCount];
-        }
-        for (int i = 0; i < mTotalCount; ++i) {
-
-            if (i == 0) {
-                View view = getAdapter().getView(i, null, this);
-                view.measure(desiredWidth, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-                sectionHeight = view.getMeasuredHeight();
-                mItemOffsetY[i] = mHeight;
-                mHeight += sectionHeight;
-            } else if (i == 1) {
-                View view = getAdapter().getView(i, null, this);
-                view.measure(desiredWidth, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-                itemHeight = view.getMeasuredHeight();
-                mItemOffsetY[i] = mHeight;
-                mHeight += itemHeight;
-            } else {
-                int type = getAdapter().getItemViewType(i);
-                switch (type) {
-                case ContactsAdapter.TYPE_CONTACT:
-                    mHeight += itemHeight;
-                case ContactsAdapter.TYPE_HEADER:
-                    mHeight += sectionHeight;
-                }
-                mItemOffsetY[i] = mHeight;
-                mHeight += sectionHeight;
-            }
-
-            System.out.println(mHeight);
-        }
-        scrollIsComputed = true;
-    }
-
-    public boolean scrollYIsComputed() {
-        return scrollIsComputed;
-    }
-
-    public int getComputedScrollY() {
-        int pos, nScrollY, nItemY;
-        View view = null;
-        pos = getFirstVisiblePosition();
-        view = getChildAt(0);
-        nItemY = view.getTop();
-        nScrollY = mItemOffsetY[pos] - nItemY;
-        return nScrollY;
-    }
-
-}
diff --git a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/WrapperView.java b/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/WrapperView.java
deleted file mode 100644
index 9ee36ad..0000000
--- a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/WrapperView.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package cx.ring.views.stickylistheaders;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-
-/**
- * 
- * the view that wrapps a divider header and a normal list item. The listview sees this as 1 item
- * 
- * @author Emil Sjölander
- */
-public class WrapperView extends ViewGroup {
-
-	View mItem;
-	Drawable mDivider;
-	int mDividerHeight;
-	View mHeader;
-	int mItemTop;
-
-	WrapperView(Context c) {
-		super(c);
-	}
-
-	public boolean hasHeader() {
-		return mHeader != null;
-	}
-	
-	public View getItem() {
-		return mItem;
-	}
-	
-	public View getHeader() {
-		return mHeader;
-	}
-
-	void update(View item, View header, Drawable divider, int dividerHeight) {
-		
-		//every wrapperview must have a list item
-		if (item == null) {
-			throw new NullPointerException("List view item must not be null.");
-		}
-
-		//only remove the current item if it is not the same as the new item. this can happen if wrapping a recycled view
-		if (this.mItem != item) {
-			removeView(this.mItem);
-			this.mItem = item;
-			final ViewParent parent = item.getParent();
-			if(parent != null && parent != this) {
-				if(parent instanceof ViewGroup) {
-					((ViewGroup) parent).removeView(item);
-				}
-			}
-			addView(item);
-		}
-
-		//same logik as above but for the header
-		if (this.mHeader != header) {
-			if (this.mHeader != null) {
-				removeView(this.mHeader);
-			}
-			this.mHeader = header;
-			if (header != null) {
-				addView(header);
-			}
-		}
-
-		if (this.mDivider != divider) {
-			this.mDivider = divider;
-			this.mDividerHeight = dividerHeight;
-			invalidate();
-		}
-	}
-
-	@Override
-	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-		int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
-		int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(measuredWidth,
-				MeasureSpec.EXACTLY);
-		int measuredHeight = 0;
-		
-		//measure header or divider. when there is a header visible it acts as the divider
-		if (mHeader != null) {
-			ViewGroup.LayoutParams params = mHeader.getLayoutParams();
-			if (params != null && params.height > 0) {
-				mHeader.measure(childWidthMeasureSpec,
-						MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY));
-			} else {
-				mHeader.measure(childWidthMeasureSpec,
-						MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-			}
-			measuredHeight += mHeader.getMeasuredHeight();
-		} else if (mDivider != null) {
-			measuredHeight += mDividerHeight;
-		}
-		
-		//measure item
-		ViewGroup.LayoutParams params = mItem.getLayoutParams();
-		if (params != null && params.height > 0) {
-			mItem.measure(childWidthMeasureSpec,
-					MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY));
-		} else {
-			mItem.measure(childWidthMeasureSpec,
-					MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-		}
-		measuredHeight += mItem.getMeasuredHeight();
-
-		setMeasuredDimension(measuredWidth, measuredHeight);
-	}
-
-	@Override
-	protected void onLayout(boolean changed, int l, int t, int r, int b) {
-
-		l = 0;
-		t = 0;
-		r = getWidth();
-		b = getHeight();
-
-		if (mHeader != null) {
-			int headerHeight = mHeader.getMeasuredHeight();
-			mHeader.layout(l, t, r, headerHeight);
-			mItemTop = headerHeight;
-			mItem.layout(l, headerHeight, r, b);
-		} else if (mDivider != null) {
-			mDivider.setBounds(l, t, r, mDividerHeight);
-			mItemTop = mDividerHeight;
-			mItem.layout(l, mDividerHeight, r, b);
-		} else {
-			mItemTop = t;
-			mItem.layout(l, t, r, b);
-		}
-	}
-
-	@Override
-	protected void dispatchDraw(Canvas canvas) {
-		super.dispatchDraw(canvas);
-		if (mHeader == null && mDivider != null) {
-			// Drawable.setBounds() does not seem to work pre-honeycomb. So have
-			// to do this instead
-			if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
-				canvas.clipRect(0, 0, getWidth(), mDividerHeight);
-			}
-			mDivider.draw(canvas);
-		}
-	}
-}
diff --git a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/WrapperViewList.java b/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/WrapperViewList.java
deleted file mode 100644
index c0c95d7..0000000
--- a/ring-android/app/src/main/java/cx/ring/views/stickylistheaders/WrapperViewList.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package cx.ring.views.stickylistheaders;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.os.Build;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.AbsListView;
-import android.widget.ListView;
-
-class WrapperViewList extends ListView {
-
-	interface LifeCycleListener {
-		void onDispatchDrawOccurred(Canvas canvas);
-	}
-
-	private LifeCycleListener mLifeCycleListener;
-	private List<View> mFooterViews;
-	private int mTopClippingLength;
-	private Rect mSelectorRect = new Rect();// for if reflection fails
-	private Field mSelectorPositionField;
-	private boolean mClippingToPadding = true;
-
-	public WrapperViewList(Context context, AttributeSet attrs) {
-		super(context, attrs);
-
-		// Use reflection to be able to change the size/position of the list
-		// selector so it does not come under/over the header
-		try {
-			Field selectorRectField = AbsListView.class.getDeclaredField("mSelectorRect");
-			selectorRectField.setAccessible(true);
-			mSelectorRect = (Rect) selectorRectField.get(this);
-
-			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-				mSelectorPositionField = AbsListView.class.getDeclaredField("mSelectorPosition");
-				mSelectorPositionField.setAccessible(true);
-			}
-		} catch (NoSuchFieldException e) {
-			e.printStackTrace();
-		} catch (IllegalArgumentException e) {
-			e.printStackTrace();
-		} catch (IllegalAccessException e) {
-			e.printStackTrace();
-		}
-	}
-
-	@Override
-	public boolean performItemClick(View view, int position, long id) {
-		if (view instanceof WrapperView) {
-			view = ((WrapperView) view).mItem;
-		}
-		return super.performItemClick(view, position, id);
-	}
-
-	private void positionSelectorRect() {
-		if (!mSelectorRect.isEmpty()) {
-			int selectorPosition = getSelectorPosition();
-			if (selectorPosition >= 0) {
-				int firstVisibleItem = getFixedFirstVisibleItem();
-				View v = getChildAt(selectorPosition - firstVisibleItem);
-				if (v instanceof WrapperView) {
-					WrapperView wrapper = ((WrapperView) v);
-					mSelectorRect.top = wrapper.getTop() + wrapper.mItemTop;
-				}
-			}
-		}
-	}
-
-	private int getSelectorPosition() {
-		if (mSelectorPositionField == null) { // not all supported andorid
-												// version have this variable
-			for (int i = 0; i < getChildCount(); i++) {
-				if (getChildAt(i).getBottom() == mSelectorRect.bottom) {
-					return i + getFixedFirstVisibleItem();
-				}
-			}
-		} else {
-			try {
-				return mSelectorPositionField.getInt(this);
-			} catch (IllegalArgumentException e) {
-				e.printStackTrace();
-			} catch (IllegalAccessException e) {
-				e.printStackTrace();
-			}
-		}
-		return -1;
-	}
-
-	@Override
-	protected void dispatchDraw(Canvas canvas) {
-		positionSelectorRect();
-		if (mTopClippingLength != 0) {
-			canvas.save();
-			Rect clipping = canvas.getClipBounds();
-			clipping.top = mTopClippingLength;
-			canvas.clipRect(clipping);
-			super.dispatchDraw(canvas);
-			canvas.restore();
-		} else {
-			super.dispatchDraw(canvas);
-		}
-		mLifeCycleListener.onDispatchDrawOccurred(canvas);
-	}
-
-	void setLifeCycleListener(LifeCycleListener lifeCycleListener) {
-		mLifeCycleListener = lifeCycleListener;
-	}
-
-	@Override
-	public void addFooterView(View v) {
-		super.addFooterView(v);
-		if (mFooterViews == null) {
-			mFooterViews = new ArrayList<View>();
-		}
-		mFooterViews.add(v);
-	}
-
-	@Override
-	public boolean removeFooterView(View v) {
-		if (super.removeFooterView(v)) {
-			mFooterViews.remove(v);
-			return true;
-		}
-		return false;
-	}
-
-	boolean containsFooterView(View v) {
-		if (mFooterViews == null) {
-			return false;
-		}
-		return mFooterViews.contains(v);
-	}
-
-	void setTopClippingLength(int topClipping) {
-		mTopClippingLength = topClipping;
-	}
-
-	int getFixedFirstVisibleItem() {
-		int firstVisibleItem = getFirstVisiblePosition();
-		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-			return firstVisibleItem;
-		}
-
-		// first getFirstVisiblePosition() reports items
-		// outside the view sometimes on old versions of android
-		for (int i = 0; i < getChildCount(); i++) {
-			if (getChildAt(i).getBottom() >= 0) {
-				firstVisibleItem += i;
-				break;
-			}
-		}
-
-		// work around to fix bug with firstVisibleItem being to high
-		// because list view does not take clipToPadding=false into account
-		// on old versions of android
-		if (!mClippingToPadding && getPaddingTop() > 0 && firstVisibleItem > 0) {
-			if (getChildAt(0).getTop() > 0) {
-				firstVisibleItem -= 1;
-			}
-		}
-
-		return firstVisibleItem;
-	}
-
-	@Override
-	public void setClipToPadding(boolean clipToPadding) {
-		mClippingToPadding = clipToPadding;
-		super.setClipToPadding(clipToPadding);
-	}
-
-}
diff --git a/ring-android/app/src/main/jni/Android.mk b/ring-android/app/src/main/jni/Android.mk
index 37b98fd..7f63ff5 100644
--- a/ring-android/app/src/main/jni/Android.mk
+++ b/ring-android/app/src/main/jni/Android.mk
@@ -43,7 +43,6 @@
 ARCH=$(ANDROID_ABI)
 
 CPP_STATIC= $(ANDROID_NDK)/sources/cxx-stl/gnu-libstdc++$(CXXSTL)/libs/$(ARCH)/libgnustl_static.a \
-			$(RING_CONTRIB)/lib/libexpat.a \
 			$(RING_CONTRIB)/lib/libgnutls.a \
 			$(RING_CONTRIB)/lib/libnettle.a \
 			$(RING_CONTRIB)/lib/libhogweed.a \
@@ -82,12 +81,14 @@
 
 LOCAL_MODULE := libringjni
 
+LOCAL_CFLAGS   +=   -fpic
+
 LOCAL_CPPFLAGS += 	-DCCPP_PREFIX \
 					-DPROGSHAREDIR=\"${MY_DATADIR}/ring\" \
 					-DHAVE_CONFIG_H \
 					-DHAVE_SPEEX_CODEC \
 					-DHAVE_GSM_CODEC \
-					-w -frtti \
+					-w -frtti -fpic \
 					-std=c++11 -fexceptions -fpermissive \
 					-DAPP_NAME=\"Ring\" \
 					-DSWIG_JAVA_ATTACH_CURRENT_THREAD_AS_DAEMON \
@@ -127,7 +128,7 @@
 				-lresample-arm-unknown-linux-androideabi
 endif
 
-LOCAL_LDLIBS	+=	-lexpat -lhogweed \
+LOCAL_LDLIBS	+=	-lhogweed \
 					-lspeexdsp -lvorbisfile -lyaml-cpp \
 					-lFLAC -liax  -lnettle \
 					-logg \
diff --git a/ring-android/app/src/main/jni/Application.mk b/ring-android/app/src/main/jni/Application.mk
index 687227d..fe89ddc 100644
--- a/ring-android/app/src/main/jni/Application.mk
+++ b/ring-android/app/src/main/jni/Application.mk
@@ -30,7 +30,7 @@
 
 
 
-APP_PLATFORM := android-15
+APP_PLATFORM := android-16
 APP_OPTIM := debug
 APP_ABI := ${ANDROID_ABI}
 NDK_TOOLCHAIN_VERSION := 4.9
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_action_end_call.png b/ring-android/app/src/main/res/drawable-hdpi/ic_action_end_call.png
deleted file mode 100644
index c807fe9..0000000
--- a/ring-android/app/src/main/res/drawable-hdpi/ic_action_end_call.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_call_end_black_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_call_end_black_24dp.png
new file mode 100644
index 0000000..3f193b1
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_call_end_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_call_end_black_36dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_call_end_black_36dp.png
new file mode 100644
index 0000000..cac21f2
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_call_end_black_36dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_call_end_white_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_call_end_white_24dp.png
new file mode 100644
index 0000000..625b827
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_call_end_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_call_white_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_call_white_24dp.png
new file mode 100644
index 0000000..4dc5065
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_call_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_chat_white_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_chat_white_24dp.png
new file mode 100644
index 0000000..d2cfdf1
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_chat_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_lock_white_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_lock_white_24dp.png
new file mode 100644
index 0000000..cd4f04a
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..7be098f
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_share_white_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_share_white_24dp.png
new file mode 100644
index 0000000..b09a692
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_share_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_videocam_white_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_videocam_white_24dp.png
new file mode 100644
index 0000000..d83e0d5
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_videocam_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-hdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-hdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..e65515d
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-ldrtl-hdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-mdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-mdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..d65d822
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-ldrtl-mdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-xhdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-xhdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..3a25fbb
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-ldrtl-xhdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-xxhdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-xxhdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..89afc01
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-ldrtl-xxhdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-ldrtl-xxxhdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-ldrtl-xxxhdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..def070f
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-ldrtl-xxxhdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_action_end_call.png b/ring-android/app/src/main/res/drawable-mdpi/ic_action_end_call.png
deleted file mode 100644
index ee026de..0000000
--- a/ring-android/app/src/main/res/drawable-mdpi/ic_action_end_call.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_call_end_black_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_call_end_black_24dp.png
new file mode 100644
index 0000000..3253503
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_call_end_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_call_end_black_36dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_call_end_black_36dp.png
new file mode 100644
index 0000000..3f193b1
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_call_end_black_36dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_call_end_white_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_call_end_white_24dp.png
new file mode 100644
index 0000000..378272f
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_call_end_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_call_white_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_call_white_24dp.png
new file mode 100644
index 0000000..77f9de5
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_call_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_chat_white_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_chat_white_24dp.png
new file mode 100644
index 0000000..dac4cb9
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_chat_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_lock_white_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_lock_white_24dp.png
new file mode 100644
index 0000000..1127f87
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..83156aa
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_share_white_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_share_white_24dp.png
new file mode 100644
index 0000000..e944fd7
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_share_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_videocam_white_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_videocam_white_24dp.png
new file mode 100644
index 0000000..d146209
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_videocam_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_action_end_call.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_action_end_call.png
deleted file mode 100644
index aef6bb0..0000000
--- a/ring-android/app/src/main/res/drawable-xhdpi/ic_action_end_call.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_call_end_black_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_call_end_black_24dp.png
new file mode 100644
index 0000000..d10890e
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_call_end_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_call_end_black_36dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_call_end_black_36dp.png
new file mode 100644
index 0000000..44794a9
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_call_end_black_36dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_call_end_white_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_call_end_white_24dp.png
new file mode 100644
index 0000000..a4fe688
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_call_end_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_call_white_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_call_white_24dp.png
new file mode 100644
index 0000000..ef45e93
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_call_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_chat_white_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_chat_white_24dp.png
new file mode 100644
index 0000000..ace0bef
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_chat_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_lock_white_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_lock_white_24dp.png
new file mode 100644
index 0000000..ad8d91a
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..fd36be8
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_share_white_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_share_white_24dp.png
new file mode 100644
index 0000000..22a8783
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_share_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_videocam_white_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_videocam_white_24dp.png
new file mode 100644
index 0000000..1b2583d
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_videocam_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_action_end_call.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_action_end_call.png
deleted file mode 100644
index c34a804..0000000
--- a/ring-android/app/src/main/res/drawable-xxhdpi/ic_action_end_call.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_end_black_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_end_black_24dp.png
new file mode 100644
index 0000000..44794a9
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_end_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_end_black_36dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_end_black_36dp.png
new file mode 100644
index 0000000..ab57d90
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_end_black_36dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_end_white_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_end_white_24dp.png
new file mode 100644
index 0000000..e1831d7
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_end_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_white_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_white_24dp.png
new file mode 100644
index 0000000..90ead2e
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_call_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_chat_white_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_chat_white_24dp.png
new file mode 100644
index 0000000..4245090
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_chat_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_lock_white_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_lock_white_24dp.png
new file mode 100644
index 0000000..0e52c7c
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..40b74eb
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_share_white_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_share_white_24dp.png
new file mode 100644
index 0000000..a35b3cd
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_share_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_videocam_white_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_videocam_white_24dp.png
new file mode 100644
index 0000000..44c28e2
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_videocam_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_end_black_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_end_black_24dp.png
new file mode 100644
index 0000000..3a0ef39
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_end_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_end_black_36dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_end_black_36dp.png
new file mode 100644
index 0000000..58888d8
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_end_black_36dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_end_white_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_end_white_24dp.png
new file mode 100644
index 0000000..8801d0d
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_end_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_white_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_white_24dp.png
new file mode 100644
index 0000000..b0e0205
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_call_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_chat_white_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_chat_white_24dp.png
new file mode 100644
index 0000000..d708e15
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_chat_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_lock_white_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_lock_white_24dp.png
new file mode 100644
index 0000000..a55147b
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_send_black_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_send_black_24dp.png
new file mode 100644
index 0000000..761929f
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_send_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_share_white_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_share_white_24dp.png
new file mode 100644
index 0000000..e351c7b
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_share_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_videocam_white_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_videocam_white_24dp.png
new file mode 100644
index 0000000..ed20c07
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_videocam_white_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable/call_button.xml b/ring-android/app/src/main/res/drawable/call_button.xml
index 7e07ee4..0a5c971 100644
--- a/ring-android/app/src/main/res/drawable/call_button.xml
+++ b/ring-android/app/src/main/res/drawable/call_button.xml
@@ -1,11 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_enabled="true" android:state_pressed="true"><shape android:shape="oval">
+    <item android:state_enabled="true" android:state_pressed="true">
+        <shape android:shape="oval">
             <solid android:color="@color/sfl_light_blue" />
-        </shape></item>
-    <item><shape android:shape="oval">
-            <solid android:color="@color/sfl_dark_blue" />
-        </shape></item>
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/color_primary_dark" />
+        </shape>
+    </item>
 
 </selector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/drawable/drawer_disc_handle.xml b/ring-android/app/src/main/res/drawable/drawer_disc_handle.xml
index 6d00638..bf5d4b9 100644
--- a/ring-android/app/src/main/res/drawable/drawer_disc_handle.xml
+++ b/ring-android/app/src/main/res/drawable/drawer_disc_handle.xml
@@ -1,14 +1,20 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_enabled="true" android:state_pressed="true"><shape android:shape="oval">
-            <solid android:color="@color/sfl_dark_blue" />
-        </shape></item>
-    <item android:state_enabled="false"><shape android:shape="oval">
-            <solid android:color="@color/sfl_dark_blue" />
-        </shape></item>
-    <item><shape android:shape="oval">
-            <solid android:color="@color/sfl_dark_blue" />
-        </shape></item>
+    <item android:state_enabled="true" android:state_pressed="true">
+        <shape android:shape="oval">
+            <solid android:color="@color/color_primary_dark" />
+        </shape>
+    </item>
+    <item android:state_enabled="false">
+        <shape android:shape="oval">
+            <solid android:color="@color/color_primary_dark" />
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/color_primary_dark" />
+        </shape>
+    </item>
 
 </selector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/drawable/item_contact_selector.xml b/ring-android/app/src/main/res/drawable/item_contact_selector.xml
index 222289e..432c3fa 100644
--- a/ring-android/app/src/main/res/drawable/item_contact_selector.xml
+++ b/ring-android/app/src/main/res/drawable/item_contact_selector.xml
@@ -1,20 +1,23 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_pressed="true"><shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape>
             <solid android:color="@color/sfl_pantone631_blue" />
-
-            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
-        </shape></item>
-    <item android:state_focused="true"><shape xmlns:android="http://schemas.android.com/apk/res/android">
+            <padding android:bottom="@dimen/padding_large" android:left="@dimen/padding_large" android:right="@dimen/padding_large" android:top="@dimen/padding_large" />
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape>
             <solid android:color="@color/sfl_pantone631_blue" />
-
-            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
-        </shape></item>
-    <item><shape xmlns:android="http://schemas.android.com/apk/res/android">
+            <padding android:bottom="@dimen/padding_large" android:left="@dimen/padding_large" android:right="@dimen/padding_large" android:top="@dimen/padding_large" />
+        </shape>
+    </item>
+    <item>
+        <shape>
             <solid android:color="@color/sfl_blue_0" />
-
-            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
-        </shape></item>
+            <padding android:bottom="@dimen/padding_large" android:left="@dimen/padding_large" android:right="@dimen/padding_large" android:top="@dimen/padding_large" />
+        </shape>
+    </item>
 
 </selector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/drawable/item_generic_selector.xml b/ring-android/app/src/main/res/drawable/item_generic_selector.xml
index da0ba95..231cdf4 100644
--- a/ring-android/app/src/main/res/drawable/item_generic_selector.xml
+++ b/ring-android/app/src/main/res/drawable/item_generic_selector.xml
@@ -4,17 +4,17 @@
     <item android:state_pressed="true"><shape xmlns:android="http://schemas.android.com/apk/res/android">
             <solid android:color="@color/darker_gray" />
 
-            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
+            <padding android:bottom="@dimen/padding_large" android:left="@dimen/padding_large" android:right="@dimen/padding_large" android:top="@dimen/padding_large" />
         </shape></item>
     <item android:state_focused="true"><shape xmlns:android="http://schemas.android.com/apk/res/android">
             <solid android:color="@color/light" />
 
-            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
+            <padding android:bottom="@dimen/padding_large" android:left="@dimen/padding_large" android:right="@dimen/padding_large" android:top="@dimen/padding_large" />
         </shape></item>
     <item><shape xmlns:android="http://schemas.android.com/apk/res/android">
             <solid android:color="@color/light" />
 
-            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
+            <padding android:bottom="@dimen/padding_large" android:left="@dimen/padding_large" android:right="@dimen/padding_large" android:top="@dimen/padding_large" />
         </shape></item>
 
 </selector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/drawable/item_history_selector.xml b/ring-android/app/src/main/res/drawable/item_history_selector.xml
index 77f7649..ee1120e 100644
--- a/ring-android/app/src/main/res/drawable/item_history_selector.xml
+++ b/ring-android/app/src/main/res/drawable/item_history_selector.xml
@@ -1,20 +1,23 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_pressed="true"><shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape xmlns:android="http://schemas.android.com/apk/res/android">
             <solid android:color="@color/transparent_grey" />
-
-            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
-        </shape></item>
-    <item android:state_focused="true"><shape xmlns:android="http://schemas.android.com/apk/res/android">
+            <padding android:bottom="@dimen/padding_large" android:left="@dimen/padding_large" android:right="@dimen/padding_large" android:top="@dimen/padding_large" />
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape xmlns:android="http://schemas.android.com/apk/res/android">
             <solid android:color="@color/transparent_grey" />
-
-            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
-        </shape></item>
-    <item><shape xmlns:android="http://schemas.android.com/apk/res/android">
-            <solid android:color="@color/transparent_light" />
-
-            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
-        </shape></item>
+            <padding android:bottom="@dimen/padding_large" android:left="@dimen/padding_large" android:right="@dimen/padding_large" android:top="@dimen/padding_large" />
+        </shape>
+    </item>
+    <item>
+        <shape xmlns:android="http://schemas.android.com/apk/res/android">
+            <solid android:color="@android:color/transparent" />
+            <padding android:bottom="@dimen/padding_large" android:left="@dimen/padding_large" android:right="@dimen/padding_large" android:top="@dimen/padding_large" />
+        </shape>
+    </item>
 
 </selector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/drawable/toggle_speaker_selector.xml b/ring-android/app/src/main/res/drawable/toggle_speaker_selector.xml
index 7fed3f3..8160c5d 100644
--- a/ring-android/app/src/main/res/drawable/toggle_speaker_selector.xml
+++ b/ring-android/app/src/main/res/drawable/toggle_speaker_selector.xml
@@ -16,7 +16,7 @@
         </layer-list></item>
     <item android:state_checked="true"><layer-list>
             <item><shape android:shape="rectangle">
-                    <solid android:color="@color/sfl_action_blue" />
+                    <solid android:color="@color/color_primary_light" />
 
                     <stroke android:width="1dp" android:color="@color/sfl_blue_lines" />
 
diff --git a/ring-android/app/src/main/res/layout/activity_account_settings.xml b/ring-android/app/src/main/res/layout/activity_account_settings.xml
index 13d726a..f9473ad 100644
--- a/ring-android/app/src/main/res/layout/activity_account_settings.xml
+++ b/ring-android/app/src/main/res/layout/activity_account_settings.xml
@@ -1,20 +1,22 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical" >
+    android:orientation="vertical"
+    tools:context=".client.AccountEditionActivity">
 
     <com.astuetz.PagerSlidingTabStrip
         android:id="@+id/pager_sliding_strip"
         android:layout_width="match_parent"
         android:layout_height="?android:attr/actionBarSize"
         android:layout_alignParentTop="true"
-        android:background="@color/sfl_blue_0"
         android:textColor="@color/white"
-        app:pstsIndicatorColor="@color/sfl_light_blue"
-        app:pstsUnderlineColor="@color/sfl_light_blue"
+        android:background="@color/color_primary_light_shadow"
+        app:pstsIndicatorColor="@color/color_primary_light"
+        app:pstsShouldExpand="true"
+        app:pstsUnderlineColor="@color/color_primary_light"
         />
-        <!---->
 
     <android.support.v4.view.ViewPager
         android:id="@+id/pager"
diff --git a/ring-android/app/src/main/res/layout/activity_call_layout.xml b/ring-android/app/src/main/res/layout/activity_call_layout.xml
index 8f1878a..6649ef3 100644
--- a/ring-android/app/src/main/res/layout/activity_call_layout.xml
+++ b/ring-android/app/src/main/res/layout/activity_call_layout.xml
@@ -30,11 +30,14 @@
 as that of the covered work.
 -->
 
-<cx.ring.views.CallPaneLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/slidingpanelayout"
     android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+    android:layout_height="match_parent"
+    tools:context=".client.CallActivity">
 
+    <!--
     <FrameLayout
         android:id="@+id/message_list_frame"
         android:layout_width="300dp"
@@ -43,6 +46,14 @@
     <FrameLayout
         android:id="@+id/ongoingcall_pane"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
+        android:layout_height="match_parent"
+        android:layout_gravity="right|center_vertical" />
+-->
+    <fragment
+        android:id="@+id/ongoingcall_pane"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:name="cx.ring.fragments.CallFragment"
+        tools:layout="@layout/frag_call" />
 
-</cx.ring.views.CallPaneLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/activity_home.xml b/ring-android/app/src/main/res/layout/activity_home.xml
index 5bbadcc..8efc6e3 100644
--- a/ring-android/app/src/main/res/layout/activity_home.xml
+++ b/ring-android/app/src/main/res/layout/activity_home.xml
@@ -32,20 +32,22 @@
 
 <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/drawer_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <cx.ring.views.SlidingUpPanelLayout
-        android:id="@+id/contact_panel"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
+    android:fitsSystemWindows="true"
+    tools:context=".client.HomeActivity">
 
         <RelativeLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent">
 
+            <ViewStub
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/viewStub" />
+
             <android.support.v7.widget.Toolbar
                 android:id="@+id/main_toolbar"
                 android:layout_width="match_parent"
@@ -53,18 +55,36 @@
                 android:layout_alignParentLeft="true"
                 android:layout_alignParentStart="true"
                 android:layout_alignParentTop="true"
+                android:background="@color/actionbar"
 
-                android:background="@color/sfl_dark_blue"
                 android:elevation="4dp"
                 android:gravity="bottom"
                 android:longClickable="true"
-                android:minHeight="?android:attr/actionBarSize"
+                android:minHeight="?attr/actionBarSize"
                 android:popupTheme="@style/Theme.AppCompat.Light.NoActionBar"
-                android:theme="@style/MyActionBar"
+                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                 app:contentInsetStart="72dp"
                 app:elevation="4dp"
                 app:popupTheme="@style/Theme.AppCompat.Light.NoActionBar"
-                app:titleMarginBottom="16dp" />
+                app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
+                app:titleMarginBottom="@dimen/action_bar_title_margin_bottom" />
+
+            <android.support.design.widget.FloatingActionButton
+                android:id="@+id/action_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignBottom="@+id/main_toolbar"
+                android:layout_alignParentLeft="true"
+                android:layout_alignParentStart="true"
+                android:layout_marginBottom="@dimen/action_button_bpadding"
+                android:layout_marginLeft="16dp"
+                android:layout_marginStart="16dp"
+                android:adjustViewBounds="false"
+                android:baselineAlignBottom="false"
+                android:elevation="4dp"
+                android:visibility="gone"
+                app:elevation="4dp"
+                app:fabSize="mini" />
 
             <FrameLayout
                 android:id="@+id/main_frame"
@@ -75,32 +95,8 @@
                 android:layout_below="@id/main_toolbar"
                 android:orientation="vertical" />
 
-            <android.support.design.widget.FloatingActionButton
-                android:id="@+id/action_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignBottom="@id/main_toolbar"
-                android:layout_alignParentLeft="true"
-                android:layout_alignParentStart="true"
-                android:layout_centerVertical="true"
-                android:layout_marginBottom="-20dp"
-                android:layout_marginLeft="16dp"
-                android:layout_marginStart="20dp"
-                android:elevation="4dp"
-                android:visibility="gone"
-                app:elevation="4dp"
-                app:fabSize="mini" />
         </RelativeLayout>
 
-        <FrameLayout
-            android:id="@+id/contacts_frame"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:clickable="true"
-            android:focusable="true"
-            android:focusableInTouchMode="true" />
-    </cx.ring.views.SlidingUpPanelLayout>
-
     <android.support.design.widget.NavigationView
         android:id="@+id/left_drawer"
         android:layout_width="wrap_content"
diff --git a/ring-android/app/src/main/res/layout/activity_new_conversation.xml b/ring-android/app/src/main/res/layout/activity_new_conversation.xml
new file mode 100644
index 0000000..89be1ee
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/activity_new_conversation.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="cx.ring.client.NewConversationActivity">
+
+    <fragment
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:name="cx.ring.fragments.ContactListFragment"
+        android:id="@+id/fragment"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentStart="true"
+        tools:layout="@layout/frag_contact_list" />
+</RelativeLayout>
diff --git a/ring-android/app/src/main/res/layout/frag_accounts_list.xml b/ring-android/app/src/main/res/layout/frag_accounts_list.xml
index 22d71dc..ead1b96 100644
--- a/ring-android/app/src/main/res/layout/frag_accounts_list.xml
+++ b/ring-android/app/src/main/res/layout/frag_accounts_list.xml
@@ -3,9 +3,7 @@
     xmlns:dslv="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:background="@color/white"
-    >
+    android:orientation="vertical">
 
         <TextView
             android:layout_width="match_parent"
@@ -33,7 +31,7 @@
                dslv:drag_scroll_start="0.33"
                dslv:drag_start_mode="onDown"
                dslv:float_alpha="0.6"
-               dslv:float_background_color="@color/sfl_action_blue"
+               dslv:float_background_color="@color/action_blue"
                dslv:remove_enabled="false"
                dslv:slide_shuffle_speed="0.3" />
 
diff --git a/ring-android/app/src/main/res/layout/frag_audio_mgmt.xml b/ring-android/app/src/main/res/layout/frag_audio_mgmt.xml
index 672492b..b89a291 100644
--- a/ring-android/app/src/main/res/layout/frag_audio_mgmt.xml
+++ b/ring-android/app/src/main/res/layout/frag_audio_mgmt.xml
@@ -60,7 +60,7 @@
                 dslv:drag_scroll_start="0.33"
                 dslv:drag_start_mode="onDown"
                 dslv:float_alpha="0.6"
-                dslv:float_background_color="@color/sfl_action_blue"
+                dslv:float_background_color="@color/action_blue"
                 dslv:remove_enabled="false"
                 dslv:slide_shuffle_speed="0.3" />
         </LinearLayout>
diff --git a/ring-android/app/src/main/res/layout/frag_call.xml b/ring-android/app/src/main/res/layout/frag_call.xml
index ce4d2b0..fae787b 100644
--- a/ring-android/app/src/main/res/layout/frag_call.xml
+++ b/ring-android/app/src/main/res/layout/frag_call.xml
@@ -1,84 +1,195 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:background="@drawable/bg_72"
-                android:divider="@drawable/divider">
-
-    <cx.ring.model.BubblesView
-            android:id="@+id/main_view"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_above="@+id/speaker_toggle"/>
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    tools:context=".client.CallActivity">
 
     <RelativeLayout
-            android:id="@+id/call_status_bar"
-            android:layout_width="match_parent"
-            android:layout_height="?android:attr/actionBarSize"
-            android:layout_alignParentTop="true">
+        android:id="@+id/main_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentStart="true">
 
-        <ImageView
-                android:id="@+id/image_call"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerVertical="true"
-                android:layout_gravity="left"
-                android:layout_marginLeft="15dp"
-                android:layout_marginRight="10dp"
-                android:src="@drawable/ic_action_call"/>
+        <!--
+        <Button
+            android:id="@+id/call_accept_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_toLeftOf="@+id/call_refuse_btn"
+            android:layout_toStartOf="@+id/call_refuse_btn"
+            android:backgroundTint="#447542"
+            android:text="Accept" />
 
-        <TextView
-                android:id="@+id/call_status_txt"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerVertical="true"
-                android:layout_toRightOf="@+id/image_call"
-                android:textSize="12sp"
-                android:textColor="@color/white"/>
-
-        <ViewSwitcher
-                android:id="@+id/security_switcher"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerVertical="true"
-                android:visibility="gone"
-                android:layout_toLeftOf="@+id/dialpad_btn">
-
-            <Button
-                    android:id="@+id/confirm_sas"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:textSize="12sp"
-                    android:textColor="@color/white"/>
+        <Button
+            android:id="@+id/call_refuse_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignTop="@+id/call_accept_btn"
+            android:layout_marginEnd="58dp"
+            android:layout_marginRight="58dp"
+            android:backgroundTint="#ff6e6e"
+            android:text="Refuse" />
+-->
+        <RelativeLayout
+            android:id="@+id/contact_bubble_layout"
+            android:layout_width="fill_parent"
+            android:layout_height="200dp"
+            android:layout_centerHorizontal="true"
+            android:layout_centerVertical="true"
+            android:layout_marginBottom="16dp">
 
             <ImageView
-                    android:id="@+id/lock_image"
-                    android:layout_gravity="end|center_vertical"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"/>
+                android:id="@+id/contact_bubble"
+                android:layout_width="200dp"
+                android:layout_height="fill_parent"
+                android:layout_above="@+id/contact_bubble_txt"
+                android:layout_centerHorizontal="true" />
+
+            <TextView
+                android:id="@+id/contact_bubble_txt"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_alignParentBottom="true"
+                android:layout_centerHorizontal="true"
+                android:gravity="center_horizontal"
+                android:text="Adrien Béraud"
+                android:textAlignment="gravity"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+                android:textIsSelectable="true"
+                android:textColor="@color/text_color_primary" />
+
+        </RelativeLayout>
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="false"
+            android:layout_centerHorizontal="true"
+            android:layout_below="@+id/contact_bubble_layout">
+
+            <android.support.design.widget.FloatingActionButton
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/call_refuse_btn"
+                android:src="@drawable/ic_call_end_white_24dp"
+                app:backgroundTint="@color/error_red"
+                app:rippleColor="@android:color/white"
+                app:elevation="6dp"
+                app:pressedTranslationZ="12dp"
+                android:layout_below="@+id/contact_bubble_layout"
+                android:layout_centerHorizontal="true"
+                android:layout_margin="8dp" />
+
+            <android.support.design.widget.FloatingActionButton
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/call_accept_btn"
+                android:src="@drawable/ic_call_white_24dp"
+                app:backgroundTint="#4caf50"
+                app:rippleColor="@android:color/white"
+                app:elevation="6dp"
+                app:pressedTranslationZ="12dp"
+                android:layout_below="@+id/contact_bubble_layout"
+                android:layout_toLeftOf="@+id/call_refuse_btn"
+                android:layout_toStartOf="@+id/call_refuse_btn"
+                android:layout_margin="8dp" />
+        </LinearLayout>
+
+        <android.support.design.widget.FloatingActionButton
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/call_hangup_btn"
+            android:src="@drawable/ic_call_end_white_24dp"
+            app:backgroundTint="@color/error_red"
+            app:rippleColor="@android:color/white"
+            app:elevation="6dp"
+            app:pressedTranslationZ="12dp"
+            android:layout_below="@+id/contact_bubble_layout"
+            android:layout_centerHorizontal="true"
+            android:layout_margin="8dp"
+            android:visibility="gone" />
+
+    </RelativeLayout>
+
+    <RelativeLayout
+        android:id="@+id/call_status_bar"
+        android:layout_width="match_parent"
+        android:layout_height="?android:attr/actionBarSize"
+        android:layout_alignParentTop="true"
+        android:visibility="visible">
+
+        <ImageView
+            android:id="@+id/image_call"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_gravity="left"
+            android:layout_marginLeft="15dp"
+            android:layout_marginRight="10dp"
+            android:src="@drawable/ic_action_call" />
+
+        <TextView
+            android:id="@+id/call_status_txt"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_toRightOf="@+id/image_call"
+            android:textColor="@color/text_color_primary"
+            android:textSize="12sp" />
+
+        <ViewSwitcher
+            android:id="@+id/security_switcher"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:visibility="gone">
+
+            <Button
+                android:id="@+id/confirm_sas"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:textColor="@color/white"
+                android:textSize="12sp" />
+
+            <ImageView
+                android:id="@+id/lock_image"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="end|center_vertical" />
         </ViewSwitcher>
 
 
-        <ImageButton
-                android:id="@+id/dialpad_btn"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignParentRight="true"
-                android:layout_centerVertical="true"
-                android:layout_marginRight="10dp"
-                android:background="@null"
-                android:src="@drawable/ic_action_dial_pad_light"/>
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/security_indicator"
+            android:src="@drawable/ic_lock_white_24dp"
+            android:tint="#4caf50"
+            android:layout_centerVertical="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentEnd="true"
+            android:layout_margin="16dp"
+            android:visibility="gone" />
 
     </RelativeLayout>
 
     <ToggleButton
-            android:id="@+id/speaker_toggle"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textOn=""
-            android:textOff=""
-            android:background="@drawable/toggle_speaker_selector"
-            android:layout_alignParentBottom="true"/>
+        android:id="@+id/speaker_toggle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:background="@drawable/toggle_speaker_selector"
+        android:textOff=""
+        android:textOn=""
+        android:visibility="gone" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/frag_call_list.xml b/ring-android/app/src/main/res/layout/frag_call_list.xml
index 3be66f9..91d8686 100644
--- a/ring-android/app/src/main/res/layout/frag_call_list.xml
+++ b/ring-android/app/src/main/res/layout/frag_call_list.xml
@@ -31,30 +31,34 @@
 -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent">
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="@dimen/padding_small"
+    android:background="@android:color/white">
 
-    <RelativeLayout
-            android:id="@+id/confs_layouts"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_margin="10dp"
-            android:background="@drawable/item_generic_selector">
+    <ListView
+        android:id="@+id/confs_list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:divider="@null"
+        tools:listitem="@layout/item_calllist">
+    </ListView>
 
-        <TextView
-                android:id="@+id/confs_counter"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:gravity="center"
-                android:layout_alignParentTop="true"
-                android:textSize="30sp"/>
-
-        <ListView
-                android:id="@+id/confs_list"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@+id/confs_counter">
-        </ListView>
-    </RelativeLayout>
+    <android.support.design.widget.FloatingActionButton
+        android:id="@+id/newconv_fab"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentRight="true"
+        android:layout_gravity="bottom|end"
+        android:layout_margin="@dimen/fab_compat_margin"
+        android:src="@drawable/ic_add_white_24dp"
+        app:backgroundTint="@color/error_red"
+        app:rippleColor="@android:color/white"
+        app:elevation="6dp"
+        app:pressedTranslationZ="12dp" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/frag_contact_list.xml b/ring-android/app/src/main/res/layout/frag_contact_list.xml
index 740e72f..f056e77 100644
--- a/ring-android/app/src/main/res/layout/frag_contact_list.xml
+++ b/ring-android/app/src/main/res/layout/frag_contact_list.xml
@@ -32,65 +32,21 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:swipe="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/drag_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical" >
+    android:orientation="vertical"
+    tools:context=".client.DetailHistoryActivity">
 
-    <RelativeLayout
-        android:id="@+id/slider_button"
-        android:layout_width="match_parent"
-        android:layout_height="68dp" >
-
-        <RelativeLayout
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/contact_drawer_handle_height"
-            android:layout_alignParentBottom="true"
-            android:background="@color/sfl_dark_blue" >
-
-            <TextView
-                android:id="@+id/handle_title"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_alignParentBottom="true"
-                android:layout_centerInParent="true"
-                android:gravity="center"
-                android:text="Contacts"
-                android:textColor="@color/white"
-                android:textStyle="bold" />
-
-            <ImageButton
-                android:id="@+id/contact_search_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignParentBottom="true"
-                android:layout_alignParentRight="true"
-                android:background="@color/sfl_dark_blue"
-                android:gravity="center"
-                android:src="@drawable/ic_btn_search" >
-            </ImageButton>
-        </RelativeLayout>
-
-        <!-- Declared after for implicit z order -->
-
-        <cx.ring.views.HalfCircleImageView
-            android:id="@+id/hello"
-            android:layout_width="112dp"
-            android:layout_height="68dp"
-            android:layout_alignParentBottom="true"
-            android:layout_centerHorizontal="true"
-            android:src="@drawable/ic_action_group" />
-    </RelativeLayout>
-
-    <cx.ring.views.stickylistheaders.StickyListHeadersListView
+    <se.emilsjolander.stickylistheaders.StickyListHeadersListView
         android:id="@+id/contacts_stickylv"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="@color/sfl_dark_blue"
         android:drawSelectorOnTop="true"
         android:fastScrollEnabled="true"
-        android:scrollbarStyle="outsideOverlay" />
+        android:scrollbarStyle="outsideOverlay"
+        android:divider="@null" />
 
     <TextView
         android:id="@android:id/empty"
diff --git a/ring-android/app/src/main/res/layout/frag_contact_list_header.xml b/ring-android/app/src/main/res/layout/frag_contact_list_header.xml
index 873e92c..d2ee4d8 100644
--- a/ring-android/app/src/main/res/layout/frag_contact_list_header.xml
+++ b/ring-android/app/src/main/res/layout/frag_contact_list_header.xml
@@ -1,42 +1,53 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/container"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:background="@color/sfl_dark_blue"
-              android:orientation="vertical">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
 
-    <SearchView
-            android:id="@+id/contact_search"
-            android:layout_width="match_parent"
-            android:queryHint="@string/searchbar_hint"
-            android:layout_height="?android:attr/actionBarSize"
-            android:background="@color/lighter_gray"/>
+    <include
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        layout="@layout/item_contact"
+        android:layout_gravity="center_horizontal"
+        android:id="@+id/newcontact_element" />
 
     <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:drawableLeft="@drawable/ic_action_important"
-            android:gravity="center_vertical"
-            android:text="@string/starred_contacts_title"
-            android:textColor="@color/white"
-            android:textStyle="bold"/>
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:background="@android:color/white"
+        android:gravity="center_vertical"
+        android:text="@string/starred_contacts_title"
+        android:textColor="@color/text_color_secondary"
+        android:id="@+id/fav_head_label"
+        android:textStyle="bold"
+        android:textSize="16sp"
+        android:paddingLeft="16dp" />
+
+    <ImageView
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:id="@+id/imageView3"
+        android:layout_gravity="bottom"
+        android:background="#e0e0e0" />
 
     <LinearLayout
-            android:id="@+id/llMain"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:background="@color/sfl_blue_0"
-            android:padding="10dp">
+        android:id="@+id/llMain"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="8dp"
+        android:background="@android:color/white">
 
         <GridView
-                android:id="@+id/favorites_grid"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:columnWidth="80dp"
-                android:numColumns="auto_fit"
-                android:stretchMode="spacingWidth"
-                android:verticalSpacing="@dimen/contact_vertical_spacing"/>
+            android:id="@+id/favorites_grid"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:columnWidth="80dp"
+            android:numColumns="auto_fit"
+            android:stretchMode="spacingWidth"
+            android:verticalSpacing="@dimen/contact_vertical_spacing"
+            tools:listitem="@layout/item_contact_starred" />
     </LinearLayout>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/frag_conversation.xml b/ring-android/app/src/main/res/layout/frag_conversation.xml
new file mode 100644
index 0000000..b2f8ee6
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/frag_conversation.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:orientation="vertical" android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".client.ConversationActivity">
+
+    <ListView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/hist_list"
+        android:layout_weight="1"
+        android:transcriptMode="alwaysScroll"
+        android:stackFromBottom="true"
+        android:divider="@null"
+        android:background="#ebeff0"
+        android:listSelector="@android:color/transparent"
+        tools:listitem="@layout/item_textmsg" />
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:background="#e3c1c1"
+        android:id="@+id/ongoingcall_pane">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:text="Ongoing call"
+            android:id="@+id/textView2"
+            android:layout_centerVertical="true"
+            android:layout_centerHorizontal="true"
+            android:layout_margin="10dp" />
+    </RelativeLayout>
+
+    <ImageView
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:id="@+id/divider"
+        android:layout_gravity="center_horizontal"
+        android:background="#bdbdbd" />
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@android:color/white"
+        android:elevation="6dp">
+
+        <EditText
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:id="@+id/msg_input_txt"
+            android:layout_weight="1" />
+
+        <ImageButton
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:id="@+id/msg_send"
+            android:src="@drawable/ic_send_black_24dp"
+            android:tint="@android:color/darker_gray"
+            android:background="@android:color/transparent"
+            android:padding="8dp" />
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/frag_home.xml b/ring-android/app/src/main/res/layout/frag_home.xml
index c3ddd10..fc63c43 100644
--- a/ring-android/app/src/main/res/layout/frag_home.xml
+++ b/ring-android/app/src/main/res/layout/frag_home.xml
@@ -3,23 +3,22 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical" >
-
+<!--
     <ImageView
         android:layout_width="match_parent"
         android:layout_height="?android:attr/actionBarSize"
         android:layout_alignParentTop="true"
         android:background="@color/sfl_dark_blue" />
-
+-->
     <com.astuetz.PagerSlidingTabStrip
         android:id="@+id/pts_main"
         android:layout_width="match_parent"
         android:layout_height="?android:attr/actionBarSize"
         android:layout_alignParentTop="true"
-        android:background="@color/sfl_blue_0"
-        app:pstsIndicatorColor="@color/sfl_light_blue"
+        android:background="@color/color_primary_light_shadow"
+        app:pstsIndicatorColor="@color/color_primary_light"
         app:pstsShouldExpand="true"
-        app:pstsUnderlineColor="@color/sfl_light_blue"
-         />
+        app:pstsUnderlineColor="@color/color_primary_light" />
 
     <android.support.v4.view.ViewPager
         android:id="@+id/pager"
diff --git a/ring-android/app/src/main/res/layout/frag_imessaging.xml b/ring-android/app/src/main/res/layout/frag_imessaging.xml
index e975a75..cc569d0 100644
--- a/ring-android/app/src/main/res/layout/frag_imessaging.xml
+++ b/ring-android/app/src/main/res/layout/frag_imessaging.xml
@@ -10,7 +10,7 @@
         android:layout_above="@+id/form"
         android:stackFromBottom="true"
         android:transcriptMode="alwaysScroll"
-        android:background="@color/sfl_dark_blue"
+        android:background="@color/color_primary_dark"
         android:layout_alignParentTop="true" >
     </ListView>
 
diff --git a/ring-android/app/src/main/res/layout/frag_menu_header.xml b/ring-android/app/src/main/res/layout/frag_menu_header.xml
index 43686ad..6a6f118 100644
--- a/ring-android/app/src/main/res/layout/frag_menu_header.xml
+++ b/ring-android/app/src/main/res/layout/frag_menu_header.xml
@@ -2,7 +2,7 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@color/sfl_blue_0"
+    android:background="@color/color_primary_dark"
     android:paddingBottom="8dp"
     android:paddingRight="5dp"
     android:paddingTop="40dp"
diff --git a/ring-android/app/src/main/res/layout/header.xml b/ring-android/app/src/main/res/layout/header.xml
index d9c5b47..36fc52c 100644
--- a/ring-android/app/src/main/res/layout/header.xml
+++ b/ring-android/app/src/main/res/layout/header.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@null"
+    android:layout_height="48dp"
+    android:background="@android:color/white"
     android:clickable="false"
     android:focusable="false"
     android:orientation="vertical" >
@@ -13,10 +13,21 @@
         android:layout_height="wrap_content"
         android:clickable="false"
         android:focusable="false"
-        android:textColor="@color/white"
-        android:background="@color/sfl_dark_blue"
+        android:textColor="@color/text_color_secondary"
         android:paddingLeft="5dp"
-        android:textSize="14sp"
-        android:textStyle="bold" />
+        android:textSize="16sp"
+        android:textStyle="bold"
+        android:layout_marginLeft="16dp"
+        android:text="A"
+        android:layout_gravity="center_vertical" />
 
-</LinearLayout>
\ No newline at end of file
+    <ImageView
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:id="@+id/imageView2"
+        android:layout_gravity="bottom"
+        android:background="#e0e0e0"
+        android:layout_marginLeft="16dp"
+        android:layout_marginRight="16dp" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/item_account.xml b/ring-android/app/src/main/res/layout/item_account.xml
index 9629be8..d6a9020 100644
--- a/ring-android/app/src/main/res/layout/item_account.xml
+++ b/ring-android/app/src/main/res/layout/item_account.xml
@@ -20,7 +20,11 @@
         android:layout_alignParentLeft="true"
         android:layout_below="@+id/account_alias"
         android:textAppearance="@style/ListSecondary"
-        android:text="hostname" />
+        android:text="hostnamehostnamehostnamehostnamehostnamehostnamehostnamehostname"
+        android:ellipsize="middle"
+        android:singleLine="true"
+        android:layout_toLeftOf="@+id/error_indicator"
+        android:layout_toStartOf="@+id/error_indicator" />
 
     <ImageView
         android:id="@+id/error_indicator"
@@ -31,6 +35,8 @@
         android:clickable="false"
         android:focusable="false"
         android:src="@drawable/ic_error_white_24dp"
-        android:focusableInTouchMode="false" />
+        android:focusableInTouchMode="false"
+        android:tint="@android:color/holo_red_light"
+        android:layout_marginLeft="16dp" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/item_account_pref.xml b/ring-android/app/src/main/res/layout/item_account_pref.xml
index 92f0ae1..ee774ce 100644
--- a/ring-android/app/src/main/res/layout/item_account_pref.xml
+++ b/ring-android/app/src/main/res/layout/item_account_pref.xml
@@ -27,13 +27,16 @@
 
     <TextView
         android:id="@+id/account_host"
-        android:layout_width="wrap_content"
+        android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:layout_below="@+id/account_alias"
         android:layout_marginLeft="72dp"
         android:textAppearance="@style/ListSecondary"
-        android:text="hostname"
-        android:layout_alignParentLeft="true" />
+        android:text="hostnamehostnamehostnamehostnamehostname"
+        android:layout_alignParentLeft="true"
+        android:ellipsize="middle"
+        android:singleLine="true"
+        android:layout_marginRight="56dp" />
 
     <CheckBox
         android:id="@+id/account_checked"
@@ -64,6 +67,7 @@
         android:layout_marginRight="16dp"
         android:layout_centerVertical="true"
         android:layout_toStartOf="@+id/account_checked"
-        android:layout_toLeftOf="@+id/loading_indicator" />
+        android:layout_toLeftOf="@+id/loading_indicator"
+        android:tint="@color/error_red" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/item_account_selected.xml b/ring-android/app/src/main/res/layout/item_account_selected.xml
index 3c2a198..6abbe19 100644
--- a/ring-android/app/src/main/res/layout/item_account_selected.xml
+++ b/ring-android/app/src/main/res/layout/item_account_selected.xml
@@ -24,8 +24,12 @@
         android:layout_alignParentLeft="true"
         android:layout_below="@+id/account_alias"
         android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textColor="@color/white"
-        android:text="hostname" />
+        android:textColor="@color/secondary_text_default_material_dark"
+        android:text="hostnamehostnamehostnamehostnamehostnamehostnamehostname"
+        android:singleLine="true"
+        android:ellipsize="middle"
+        android:layout_toLeftOf="@+id/error_indicator"
+        android:layout_toStartOf="@+id/error_indicator" />
 
     <ImageView
         android:id="@+id/error_indicator"
@@ -35,6 +39,7 @@
         android:layout_centerVertical="true"
         android:clickable="false"
         android:focusable="false"
-        android:src="@drawable/ic_error_white_24dp" />
+        android:src="@drawable/ic_error_white_24dp"
+        android:layout_marginLeft="16dp" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/item_calllist.xml b/ring-android/app/src/main/res/layout/item_calllist.xml
index aa426e4..7cfe3e5 100644
--- a/ring-android/app/src/main/res/layout/item_calllist.xml
+++ b/ring-android/app/src/main/res/layout/item_calllist.xml
@@ -1,42 +1,66 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
+
+Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+
+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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-->
+
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/call_entry"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_alignParentLeft="true"
-    android:layout_centerVertical="true"
-    android:background="@drawable/item_generic_selector" >
+    android:layout_width="match_parent"
+    android:layout_height="72dp"
+    android:background="@drawable/item_history_selector"
+    android:descendantFocusability="blocksDescendants">
+
+    <ImageView
+        android:id="@+id/photo"
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:background="@null"
+        android:scaleType="centerCrop"
+        android:layout_centerVertical="true"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentStart="true"
+        android:layout_marginRight="16dp" />
 
     <TextView
-        android:id="@+id/call_title"
+        android:id="@+id/msg_txt"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
+        android:layout_alignParentLeft="false"
         android:layout_alignParentTop="true"
         android:ellipsize="marquee"
         android:marqueeRepeatLimit="marquee_forever"
         android:scrollHorizontally="true"
         android:singleLine="true"
-        android:text=""
-        android:textSize="20sp" />
+        android:textSize="16sp"
+        android:layout_toRightOf="@+id/photo"
+        android:textColor="@color/text_color_primary"
+        android:layout_marginTop="2dp" />
 
     <TextView
         android:id="@+id/call_status"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_below="@+id/call_title"
-        android:text=""
-        android:textSize="12sp" />
-
-    <TextView
-        android:id="@+id/call_time"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_below="@+id/call_title"
-        android:layout_toRightOf="@+id/call_status"
-        android:paddingLeft="10dp"
-        android:text=""
-        android:textSize="12sp" />
+        android:layout_alignParentLeft="false"
+        android:layout_below="@+id/msg_txt"
+        android:textSize="14sp"
+        android:layout_toRightOf="@+id/photo"
+        android:textColor="@color/text_color_secondary" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/item_codec.xml b/ring-android/app/src/main/res/layout/item_codec.xml
index a604aa1..cd0bd51 100644
--- a/ring-android/app/src/main/res/layout/item_codec.xml
+++ b/ring-android/app/src/main/res/layout/item_codec.xml
@@ -1,8 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/codec_container"
     android:layout_width="match_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight" >
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    tools:context=".client.AccountEditionActivity">
 
     <ImageView
             android:id="@+id/drag_handle"
@@ -11,7 +13,7 @@
             android:layout_centerVertical="true"
             android:layout_alignParentLeft="true"
             android:layout_marginLeft="10dp"
-            android:src="@drawable/handle"/>
+            android:src="@drawable/ic_reorder_black_24dp"/>
 
     <TextView
         android:id="@+id/codec_name"
diff --git a/ring-android/app/src/main/res/layout/item_contact.xml b/ring-android/app/src/main/res/layout/item_contact.xml
index 8b961b0..4d2647e 100644
--- a/ring-android/app/src/main/res/layout/item_contact.xml
+++ b/ring-android/app/src/main/res/layout/item_contact.xml
@@ -33,110 +33,63 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+    android:layout_height="wrap_content" >
 
     <RelativeLayout
+        android:id="@+id/contactview"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@color/sfl_action_blue"
+        android:layout_height="wrap_content"
+        android:padding="16dp"
+        android:background="@android:color/white"
         android:descendantFocusability="blocksDescendants" >
 
-        <LinearLayout
-            android:id="@+id/contact_underview"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_alignParentBottom="true"
-            android:layout_alignParentTop="true"
+        <ImageView
+            android:id="@+id/photo"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
+            android:contentDescription="@string/contact_picture_description"
+            android:scaleType="centerCrop" />
+
+        <TextView
+            android:id="@+id/display_name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:textColor="@color/text_color_primary"
+            android:textIsSelectable="false"
             android:layout_centerVertical="true"
-            android:orientation="horizontal"
-            android:weightSum="6" >
+            android:layout_toRightOf="@+id/photo"
+            android:layout_toEndOf="@+id/photo"
+            android:textSize="16sp"
+            android:layout_marginLeft="16dp" />
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:divider="@drawable/divider"
+            android:showDividers="middle"
+            android:visibility="gone">
 
             <ImageButton
-                android:id="@+id/quick_starred"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
+                android:id="@+id/quick_call"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="5dp"
                 android:background="@null"
-                android:contentDescription="@string/contact_quick_starred_description"
-                android:src="@drawable/ic_action_not_important" />
+                android:contentDescription="@string/contact_quick_call_description"
+                android:src="@drawable/ic_action_call" />
 
             <ImageButton
-                android:id="@+id/quick_edit"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
+                android:id="@+id/quick_message"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="5dp"
                 android:background="@null"
-                android:contentDescription="@string/contact_quick_edit_description"
-                android:src="@drawable/ic_action_edit" />
-
-            <ImageButton
-                android:id="@+id/quick_discard"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:background="@null"
-                android:contentDescription="@string/contact_quick_discard_description"
-                android:src="@drawable/ic_action_discard" />
-
-            <Space
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="3" />
+                android:contentDescription="@string/contact_quick_msg_description"
+                android:src="@drawable/ic_action_chat" />
         </LinearLayout>
-
-        <RelativeLayout
-            android:id="@+id/contactview"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="@drawable/item_contact_selector" >
-
-            <ImageView
-                android:id="@+id/photo"
-                android:layout_width="70dp"
-                android:layout_height="70dp"
-                android:contentDescription="@string/contact_picture_description"
-                android:scaleType="centerCrop" />
-
-            <TextView
-                android:id="@+id/display_name"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignBottom="@+id/photo"
-                android:layout_alignTop="@+id/photo"
-                android:layout_marginLeft="15dp"
-                android:layout_toRightOf="@+id/photo"
-                android:gravity="center_vertical"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textColor="@color/white"
-                android:textSize="14sp" />
-
-            <LinearLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignParentRight="true"
-                android:layout_centerVertical="true"
-                android:divider="@drawable/divider"
-                android:showDividers="middle" >
-
-                <ImageButton
-                    android:id="@+id/quick_call"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_margin="5dp"
-                    android:background="@null"
-                    android:contentDescription="@string/contact_quick_call_description"
-                    android:src="@drawable/ic_action_call" />
-
-                <ImageButton
-                    android:id="@+id/quick_message"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_margin="5dp"
-                    android:background="@null"
-                    android:contentDescription="@string/contact_quick_msg_description"
-                    android:src="@drawable/ic_action_chat" />
-            </LinearLayout>
-        </RelativeLayout>
     </RelativeLayout>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/item_contact_starred.xml b/ring-android/app/src/main/res/layout/item_contact_starred.xml
index d3426a7..6b9e396 100644
--- a/ring-android/app/src/main/res/layout/item_contact_starred.xml
+++ b/ring-android/app/src/main/res/layout/item_contact_starred.xml
@@ -1,32 +1,30 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
-
-    <RelativeLayout
-        android:id="@+id/contactview"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" >
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:id="@+id/contactview"
+    android:orientation="vertical">
 
         <ImageView
             android:id="@+id/photo"
-            android:layout_width="70dp"
-            android:layout_height="70dp"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
             android:layout_centerHorizontal="true"
             android:contentDescription="@string/contact_picture_description"
-            android:scaleType="centerCrop" />
+            android:scaleType="centerCrop"
+            android:layout_gravity="center_horizontal" />
 
         <TextView
             android:id="@+id/display_name"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_alignParentBottom="true"
             android:layout_below="@+id/photo"
             android:layout_centerHorizontal="true"
             android:gravity="center"
             android:singleLine="true"
-            android:textColor="@color/white"
+            android:textColor="@color/text_color_primary"
             android:textSize="12sp" />
-    </RelativeLayout>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/item_history.xml b/ring-android/app/src/main/res/layout/item_history.xml
index d56455a..1297873 100644
--- a/ring-android/app/src/main/res/layout/item_history.xml
+++ b/ring-android/app/src/main/res/layout/item_history.xml
@@ -17,25 +17,15 @@
 You should have received a copy of the GNU General Public License   
 along with this program; if not, write to the Free Software         
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.          
-                                                                    
-Additional permission under GNU GPL version 3 section 7:            
-                                                                    
-If you modify this program, or any covered work, by linking or      
-combining it with the OpenSSL project's OpenSSL library (or a       
-modified version of that library), containing parts covered by the  
-terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.    
-grants you additional permission to convey the resulting work.      
-Corresponding Source for a non-source form of such a combination    
-shall include the source code for the parts of OpenSSL used as well 
-as that of the covered work.
 -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/contactview"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="100dp"
     android:background="@drawable/item_history_selector"
-    android:descendantFocusability="blocksDescendants" >
+    android:descendantFocusability="blocksDescendants">
 
     <ImageButton
         android:id="@+id/photo"
@@ -54,7 +44,8 @@
         android:layout_toRightOf="@+id/photo"
         android:paddingLeft="@dimen/padding_small"
         android:singleLine="true"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:text="Adrien" />
 
     <TextView
         android:id="@+id/date_start"
diff --git a/ring-android/app/src/main/res/layout/item_textmsg.xml b/ring-android/app/src/main/res/layout/item_textmsg.xml
new file mode 100644
index 0000000..ddef7b4
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/item_textmsg.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
+
+Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+
+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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <RelativeLayout
+        android:id="@+id/txt_entry_right"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@android:color/transparent"
+        android:padding="@dimen/padding_large"
+        android:focusable="false"
+        android:layout_gravity="right"
+        android:visibility="gone">
+
+        <TextView
+            android:id="@+id/msg_txt_right"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@android:color/white"
+            android:ellipsize="marquee"
+            android:marqueeRepeatLimit="marquee_forever"
+            android:padding="12dp"
+            android:scrollHorizontally="true"
+            android:singleLine="false"
+            android:text="Ceci est un long message sur plusieurs lignes. Il apparaitera en multilignes"
+            android:textColor="@color/text_color_primary"
+            android:textSize="16sp"
+            android:focusable="true"
+            android:textIsSelectable="true"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentEnd="true"
+            android:layout_marginLeft="48dp" />
+
+        <TextView
+            android:id="@+id/msg_details_txt_right"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Adrien - 12 mars"
+            android:textColor="@color/text_color_secondary"
+            android:textSize="14sp"
+            android:layout_below="@+id/msg_txt_right"
+            android:layout_alignRight="@+id/msg_txt_right"
+            android:layout_alignEnd="@+id/msg_txt_right" />
+    </RelativeLayout>
+
+    <RelativeLayout
+        android:id="@+id/txt_entry"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@android:color/transparent"
+        android:padding="@dimen/padding_large"
+        android:focusable="false">
+
+        <ImageView
+            android:id="@+id/photo"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentStart="true"
+            android:layout_alignParentTop="true"
+            android:layout_marginRight="16dp"
+            android:background="@null"
+            android:scaleType="centerCrop" />
+
+        <TextView
+            android:id="@+id/msg_txt"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_toEndOf="@+id/photo"
+            android:layout_toRightOf="@+id/photo"
+            android:background="@android:color/white"
+            android:ellipsize="marquee"
+            android:marqueeRepeatLimit="marquee_forever"
+            android:padding="12dp"
+            android:scrollHorizontally="true"
+            android:singleLine="false"
+            android:text="Ceci est un long message sur plusieurs lignes. Il apparaitera en multilignes"
+            android:textColor="@color/text_color_primary"
+            android:textSize="16sp"
+            android:focusable="true"
+            android:textIsSelectable="true"
+            android:layout_marginRight="48dp" />
+
+        <TextView
+            android:id="@+id/msg_details_txt"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="false"
+            android:layout_below="@+id/msg_txt"
+            android:layout_toRightOf="@+id/photo"
+            android:text="Adrien - 12 mars"
+            android:textColor="@color/text_color_secondary"
+            android:textSize="14sp" />
+
+    </RelativeLayout>
+
+    <RelativeLayout
+        android:id="@+id/call_entry"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:descendantFocusability="blocksDescendants"
+        android:background="#ced8da"
+        android:padding="12dp"
+        android:layout_marginBottom="16dp"
+        android:layout_gravity="right|bottom"
+        android:visibility="gone">
+
+        <TextView
+            android:id="@+id/call_hist_txt"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="marquee"
+            android:marqueeRepeatLimit="marquee_forever"
+            android:scrollHorizontally="true"
+            android:singleLine="false"
+            android:text="Appel manqué"
+            android:textColor="@color/text_color_primary"
+            android:textSize="14sp"
+            />
+
+        <TextView
+            android:id="@+id/call_details_txt"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="false"
+            android:text="Adrien - 12 mars"
+            android:textColor="@color/text_color_secondary"
+            android:textSize="12sp"
+            android:layout_below="@+id/call_hist_txt" />
+
+    </RelativeLayout>
+</FrameLayout>
diff --git a/ring-android/app/src/main/res/menu/ac_call.xml b/ring-android/app/src/main/res/menu/ac_call.xml
index 7e74699..eff7bf7 100644
--- a/ring-android/app/src/main/res/menu/ac_call.xml
+++ b/ring-android/app/src/main/res/menu/ac_call.xml
@@ -4,7 +4,7 @@
     <item
         android:id="@+id/menuitem_chat"
         android:showAsAction="always"
-        android:icon="@drawable/ic_action_chat"
+        android:icon="@drawable/ic_chat_white_24dp"
         android:title="@string/ab_action_chat"/>
 
 </menu>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/menu/conversation_actions.xml b/ring-android/app/src/main/res/menu/conversation_actions.xml
new file mode 100644
index 0000000..601faf4
--- /dev/null
+++ b/ring-android/app/src/main/res/menu/conversation_actions.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+        <item
+            android:id="@+id/conv_action_videocall"
+            android:icon="@drawable/ic_videocam_white_24dp"
+            android:title="Video call"
+            android:showAsAction="always"
+            />
+        <item
+            android:id="@+id/conv_action_audiocall"
+            android:icon="@drawable/ic_call_white_24dp"
+            android:title="Audio call"
+            android:showAsAction="always"/>
+</menu>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/menu/newconv_option_menu.xml b/ring-android/app/src/main/res/menu/newconv_option_menu.xml
new file mode 100644
index 0000000..9ef8122
--- /dev/null
+++ b/ring-android/app/src/main/res/menu/newconv_option_menu.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/contact_search"
+        android:title="Nom d'un contact ou numéro"
+        android:icon="@drawable/ic_btn_search"
+        android:showAsAction="collapseActionView|ifRoom"
+        android:actionViewClass="android.widget.SearchView" />
+</menu>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/values-land/dimens.xml b/ring-android/app/src/main/res/values-land/dimens.xml
new file mode 100644
index 0000000..b2c3f52
--- /dev/null
+++ b/ring-android/app/src/main/res/values-land/dimens.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2004-2014 Savoir-Faire Linux Inc.                     
+                                                                    
+Author: Adrien Beraud <adrien.beraud@gmail.com>                     
+                                                                    
+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, write to the Free Software         
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.          
+                                                                    
+Additional permission under GNU GPL version 3 section 7:            
+                                                                    
+If you modify this program, or any covered work, by linking or      
+combining it with the OpenSSL project's OpenSSL library (or a       
+modified version of that library), containing parts covered by the  
+terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.    
+grants you additional permission to convey the resulting work.      
+Corresponding Source for a non-source form of such a combination    
+shall include the source code for the parts of OpenSSL used as well 
+as that of the covered work.
+-->
+<resources>
+
+    <dimen name="action_bar_title_margin_bottom">10dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/values-sw600dp/dimens.xml b/ring-android/app/src/main/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..bcb3ccb
--- /dev/null
+++ b/ring-android/app/src/main/res/values-sw600dp/dimens.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2004-2014 Savoir-Faire Linux Inc.                     
+                                                                    
+Author: Adrien Beraud <adrien.beraud@gmail.com>                     
+                                                                    
+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, write to the Free Software         
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.          
+                                                                    
+Additional permission under GNU GPL version 3 section 7:            
+                                                                    
+If you modify this program, or any covered work, by linking or      
+combining it with the OpenSSL project's OpenSSL library (or a       
+modified version of that library), containing parts covered by the  
+terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.    
+grants you additional permission to convey the resulting work.      
+Corresponding Source for a non-source form of such a combination    
+shall include the source code for the parts of OpenSSL used as well 
+as that of the covered work.
+-->
+<resources>
+
+    <dimen name="action_bar_title_margin_bottom">20dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/values-v21/dimens.xml b/ring-android/app/src/main/res/values-v21/dimens.xml
new file mode 100644
index 0000000..f3c4cba
--- /dev/null
+++ b/ring-android/app/src/main/res/values-v21/dimens.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2004-2014 Savoir-Faire Linux Inc.                     
+                                                                    
+Author: Adrien Beraud <adrien.beraud@gmail.com>                     
+                                                                    
+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, write to the Free Software         
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.          
+                                                                    
+Additional permission under GNU GPL version 3 section 7:            
+                                                                    
+If you modify this program, or any covered work, by linking or      
+combining it with the OpenSSL project's OpenSSL library (or a       
+modified version of that library), containing parts covered by the  
+terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.    
+grants you additional permission to convey the resulting work.      
+Corresponding Source for a non-source form of such a combination    
+shall include the source code for the parts of OpenSSL used as well 
+as that of the covered work.
+-->
+<resources>
+
+    <dimen name="action_button_bpadding">-20dp</dimen>
+    <dimen name="fab_compat_margin">16dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/values-v21/styles.xml b/ring-android/app/src/main/res/values-v21/styles.xml
index cbf5228..89b7d60 100644
--- a/ring-android/app/src/main/res/values-v21/styles.xml
+++ b/ring-android/app/src/main/res/values-v21/styles.xml
@@ -1,22 +1,23 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
     <style name="AppThemeWithOverlay" parent="AppThemeBase">
-        <item name="android:actionBarStyle">@style/MyActionBar</item>
-        <item name="android:windowActionBarOverlay">true</item>
-        <item name="windowActionBarOverlay">true</item>
-        <item name="android:windowBackground">@drawable/bg_72</item>
         <item name="android:windowDrawsSystemBarBackgrounds">true</item>
-        <item name="android:statusBarColor">@android:color/transparent</item>
+        <item name="android:statusBarColor">@color/color_primary_light</item>
         <item name="android:windowTranslucentStatus">true</item>
     </style>
 
     <style name="AppThemeWithoutOverlay" parent="@android:style/Theme.Material.Light.DarkActionBar">
         <item name="android:actionBarStyle">@style/NativeActionBar</item>
+        <item name="android:colorAccent">@color/color_primary_light</item>
+        <item name="android:colorPrimary">@color/color_primary_light</item>
+        <item name="android:colorPrimaryDark">@color/color_primary_dark</item>
+
     </style>
 
     <style name="NativeActionBar" parent="@android:style/Widget.ActionBar">
-        <item name="android:background">@color/sfl_dark_blue</item>
+        <item name="android:background">@color/actionbar</item>
         <item name="android:titleTextStyle">@style/NativeActionBar.Text</item>
+        <item name="android:elevation">4dp</item>
     </style>
 
     <style name="NativeActionBar.Text" parent="@android:style/TextAppearance.Material.Widget.ActionBar.Title">
diff --git a/ring-android/app/src/main/res/values/colors.xml b/ring-android/app/src/main/res/values/colors.xml
index b21f6b0..bb377d6 100644
--- a/ring-android/app/src/main/res/values/colors.xml
+++ b/ring-android/app/src/main/res/values/colors.xml
@@ -1,14 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    
-    
-    <!-- SFL colors -->
+
+    <color name="color_primary_light">#3AC0D2</color>
+    <color name="color_primary_light_shadow">#40b5c6</color>
+
+    <color name="color_primary_dark">#004C60</color>
+
+
+    <color name="action_blue">#004C60</color>
+
+    <color name="actionbar">@color/color_primary_light</color>
+
+
+    <!-- SFL colors-->
     <color name="sfl_pantone631_blue">#56B0C9</color>
-    <color name="sfl_dark_blue">#09353c</color>
+    <!-- <color name="sfl_dark_blue">#09353c</color>
     
     <color name="sfl_another_blue">#051d21</color>
     <color name="sfl_action_blue">#AA2eadda</color>
-    
+     -->
     
     <color name="sfl_blue_0">#002930</color>
     
@@ -51,8 +61,12 @@
     <color name="holo_orange_dark">#ffff8800</color>
     <!-- A really bright Holo shade of blue -->
     <color name="holo_blue_bright">#ff00ddff</color>
-    
-    
+
     <color name="transparent_grey">#AACCCCCC</color>
-    
+
+    <color name="text_color_primary">@color/abc_primary_text_material_light</color>
+    <color name="text_color_secondary">@color/abc_secondary_text_material_light</color>
+    <color name="text_color_primary_dark">@color/abc_primary_text_material_dark</color>
+    <color name="text_color_secondary_dark">@color/abc_secondary_text_material_dark</color>
+
 </resources>
diff --git a/ring-android/app/src/main/res/values/dimens.xml b/ring-android/app/src/main/res/values/dimens.xml
index 2d3ac13..31e5c92 100644
--- a/ring-android/app/src/main/res/values/dimens.xml
+++ b/ring-android/app/src/main/res/values/dimens.xml
@@ -47,8 +47,14 @@
     <dimen name="contact_drawer_handle_height">36dp</dimen>
     <dimen name="contact_drawer_handle_height_with_shadow">40dp</dimen>
 
-    <dimen name="contact_vertical_spacing">10dp</dimen>
+    <dimen name="contact_vertical_spacing">16dp</dimen>
     
     
     <dimen name="header_history_detail">200dp</dimen>
+
+    <dimen name="action_button_bpadding">-35dp</dimen>
+    <dimen name="fab_compat_margin">0dp</dimen>
+
+    <dimen name="action_bar_title_margin_bottom">12dp</dimen>
+
 </resources>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/values/strings.xml b/ring-android/app/src/main/res/values/strings.xml
index b2584e7..5978919 100644
--- a/ring-android/app/src/main/res/values/strings.xml
+++ b/ring-android/app/src/main/res/values/strings.xml
@@ -63,8 +63,8 @@
 
     <!-- Dialing Fragment -->
     <string name="dial_action_call">Call</string>
-    <string name="dial_error_no_number_dialed">Dial a number</string>
-    <string name="dial_hint">Type phone number</string>
+    <string name="dial_error_no_number_dialed">Dial a mNumber</string>
+    <string name="dial_hint">Type phone mNumber</string>
 
     <!-- History Fragment -->
     <string name="hist_replay_button">Replay</string>
@@ -89,7 +89,7 @@
     <!-- ContactList Fragment -->
     <string name="no_contact_found">No contact found</string>
     <string name="starred_contacts_title">Favorites</string>
-    <string name="searchbar_hint">Enter name or phone number&#8230;</string>
+    <string name="searchbar_hint">Enter name or phone mNumber&#8230;</string>
 
     <!-- FileExplorerDFragement -->
     <string name="file_explorer_title">Select a file</string>
@@ -97,7 +97,7 @@
     <!-- TransferDFragment -->
     <string name="transfer_to_another_call">Transfer to another current call:</string>
     <string name="transfer_no_other_call">No other calls pending</string>
-    <string name="transfer_type_number">Type number to transfer to:</string>
+    <string name="transfer_type_number">Type mNumber to transfer to:</string>
 
     <!-- Notifications -->
     <string name="notif_missed_call_title">Missed call</string>
diff --git a/ring-android/app/src/main/res/values/styles.xml b/ring-android/app/src/main/res/values/styles.xml
index 89379e3..0e1b43b 100644
--- a/ring-android/app/src/main/res/values/styles.xml
+++ b/ring-android/app/src/main/res/values/styles.xml
@@ -1,16 +1,15 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="AppThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
-
+    <style name="AppThemeBase" parent="@style/Theme.AppCompat.Light.NoActionBar">
+        <item name="actionBarStyle">@style/MyActionBar</item>
+        <item name="colorAccent">@color/color_primary_dark</item>
+        <item name="colorPrimary">@color/color_primary_light</item>
+        <item name="colorPrimaryDark">@color/color_primary_dark</item>
+        <item name="android:windowActionBarOverlay">true</item>
+        <item name="windowActionBarOverlay">true</item>
     </style>
 
     <style name="AppThemeWithOverlay" parent="AppThemeBase">
-
-        <item name="android:actionBarStyle">@style/MyActionBar</item>
-
-        <item name="android:windowActionBarOverlay">true</item>
-        <item name="windowActionBarOverlay">true</item>
-        <item name="android:windowBackground">@drawable/bg_72</item>
         <item name="android:activatedBackgroundIndicator">@drawable/navigation_selector</item>
     </style>
 
@@ -24,22 +23,26 @@
         <item name="android:actionBarStyle">@style/NativeActionBar</item>
     </style>
 
-    <style name="NativeActionBar" parent="@android:style/Widget.ActionBar">
-        <item name="android:background">@color/sfl_dark_blue</item>
-        <item name="titleTextStyle">@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse</item>
-
+    <style name="NativeActionBar" parent="@android:style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse">
+        <item name="android:background">@color/color_primary_light</item>
+        <item name="elevation">4dp</item>
     </style>
 
-    <style name="NativeActionBar.Text" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title">
-    </style>
-
-    <style name="MyActionBar" parent="@style/Widget.AppCompat.Light.ActionBar.Solid">
+    <style name="MyActionBar" parent="@style/Widget.AppCompat.ActionBar.Solid">
         <item name="android:textColorPrimary">@android:color/primary_text_dark</item>
+        <item name="android:textColorHighlight">@android:color/primary_text_dark</item>
         <item name="android:textColorSecondary">@android:color/secondary_text_dark</item>
+        <item name="colorControlNormal">@color/white</item>
         <item name="selectableItemBackground">?android:selectableItemBackground</item>
         <item name="selectableItemBackgroundBorderless">?android:selectableItemBackground</item>
-        <item name="actionMenuTextColor">@color/abc_primary_text_material_light</item>
+        <item name="titleTextStyle">@style/MyTitleTextStyle</item>
+        <item name="elevation">4dp</item>
     </style>
+
+    <style name="MyTitleTextStyle" parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Title">
+        <item name="android:textColor">@color/error_red</item>
+    </style>
+
     <style name="MenuHeader" parent="Theme.AppCompat.Light.NoActionBar">
         <item name="android:textColorPrimary">@android:color/primary_text_dark</item>
         <item name="android:textColorSecondary">@android:color/secondary_text_dark</item>