Bubbles: Honor screen density when drawing bubbles and attractors.
diff --git a/src/com/savoirfairelinux/sflphone/client/SFLPhoneHomeActivity.java b/src/com/savoirfairelinux/sflphone/client/SFLPhoneHomeActivity.java
index 5b3b187..0e1c822 100644
--- a/src/com/savoirfairelinux/sflphone/client/SFLPhoneHomeActivity.java
+++ b/src/com/savoirfairelinux/sflphone/client/SFLPhoneHomeActivity.java
@@ -31,8 +31,6 @@
  */
 package com.savoirfairelinux.sflphone.client;
 
-import java.util.Random;
-
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.Fragment;
@@ -65,7 +63,6 @@
 import com.savoirfairelinux.sflphone.fragments.MenuFragment;
 import com.savoirfairelinux.sflphone.interfaces.CallInterface;
 import com.savoirfairelinux.sflphone.model.CallContact;
-import com.savoirfairelinux.sflphone.model.CallContact.ContactBuilder;
 import com.savoirfairelinux.sflphone.model.SipCall;
 import com.savoirfairelinux.sflphone.service.CallManagerCallBack;
 import com.savoirfairelinux.sflphone.service.ISipService;
@@ -73,385 +70,387 @@
 import com.savoirfairelinux.sflphone.views.CustomSlidingDrawer;
 
 public class SFLPhoneHomeActivity extends Activity implements ActionBar.TabListener, DialingFragment.Callbacks, ContactListFragment.Callbacks,
-        CallElementListFragment.Callbacks, HistoryFragment.Callbacks, CallInterface {
+CallElementListFragment.Callbacks, HistoryFragment.Callbacks, CallInterface {
 
-    SectionsPagerAdapter mSectionsPagerAdapter = null;
-    static final String TAG = "SFLPhoneHomeActivity";
+	SectionsPagerAdapter mSectionsPagerAdapter = null;
+	static final String TAG = "SFLPhoneHomeActivity";
 
-    private ContactListFragment mContactsFragment = null;
-    private DialingFragment mDialingFragment = null;
-    private CallElementListFragment mCallElementList = null;
-    private HistoryFragment mHistorySectionFragment = null;
+	private ContactListFragment mContactsFragment = null;
+	private DialingFragment mDialingFragment = null;
+	private CallElementListFragment mCallElementList = null;
+	private HistoryFragment mHistorySectionFragment = null;
 
-    Fragment fMenu;
+	Fragment fMenu;
 
-    private boolean mBound = false;
-    private ISipService service;
+	private boolean mBound = false;
+	private ISipService service;
 
-    private CharSequence mDrawerTitle;
-    private CharSequence mTitle;
+	private CharSequence mDrawerTitle;
+	private CharSequence mTitle;
 
-    private static final int REQUEST_CODE_PREFERENCES = 1;
-    private static final int REQUEST_CODE_CALL = 2;
+	private static final int REQUEST_CODE_PREFERENCES = 1;
+	private static final int REQUEST_CODE_CALL = 2;
 
-    private static final int ACTION_BAR_TAB_DIALING = 0;
-    private static final int ACTION_BAR_TAB_CALL = 1;
-    private static final int ACTION_BAR_TAB_HISTORY = 2;
+	private static final int ACTION_BAR_TAB_DIALING = 0;
+	private static final int ACTION_BAR_TAB_CALL = 1;
+	private static final int ACTION_BAR_TAB_HISTORY = 2;
 
-    RelativeLayout mSliderButton;
-    CustomSlidingDrawer mDrawer;
-    private DrawerLayout mDrawerLayout;
-    private ActionBarDrawerToggle mDrawerToggle;
-    /**
-     * The {@link ViewPager} that will host the section contents.
-     */
-    ViewPager mViewPager;
+	RelativeLayout mSliderButton;
+	CustomSlidingDrawer mDrawer;
+	private DrawerLayout mDrawerLayout;
+	private ActionBarDrawerToggle mDrawerToggle;
+	/**
+	 * The {@link ViewPager} that will host the section contents.
+	 */
+	ViewPager mViewPager;
 
-    CallReceiver receiver;
+	CallReceiver receiver;
 
-    final private int[] icon_res_id = { R.drawable.ic_tab_call, R.drawable.ic_tab_call, R.drawable.ic_tab_history };
+	final private int[] icon_res_id = { R.drawable.ic_tab_call, R.drawable.ic_tab_call, R.drawable.ic_tab_history };
 
-    // public SFLPhoneHome extends Activity implements ActionBar.TabListener, OnClickListener
+	// public SFLPhoneHome extends Activity implements ActionBar.TabListener, OnClickListener
 
-    /* called before activity is killed, e.g. rotation */
-    @Override
-    protected void onSaveInstanceState(Bundle bundle) {
-        super.onSaveInstanceState(bundle);
-        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
-            try {
-                getFragmentManager().putFragment(bundle, mSectionsPagerAdapter.getClassName(i), mSectionsPagerAdapter.getItem(i));
-            } catch (IllegalStateException e) {
-                Log.e(TAG, "fragment=" + mSectionsPagerAdapter.getItem(i));
-            }
-        }
+	/* called before activity is killed, e.g. rotation */
+	@Override
+	protected void onSaveInstanceState(Bundle bundle) {
+		super.onSaveInstanceState(bundle);
+		for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
+			try {
+				getFragmentManager().putFragment(bundle, mSectionsPagerAdapter.getClassName(i), mSectionsPagerAdapter.getItem(i));
+			} catch (IllegalStateException e) {
+				Log.e(TAG, "fragment=" + mSectionsPagerAdapter.getItem(i));
+			}
+		}
 
-        getFragmentManager().putFragment(bundle, "ContactsListFragment", mContactsFragment);
-        Log.w(TAG, "onSaveInstanceState()");
-    }
+		getFragmentManager().putFragment(bundle, "ContactsListFragment", mContactsFragment);
+		Log.w(TAG, "onSaveInstanceState()");
+	}
 
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
 
-        receiver = new CallReceiver(this);
+		receiver = new CallReceiver(this);
 
-        String libraryPath = getApplicationInfo().dataDir + "/lib";
-        Log.i(TAG, libraryPath);
+		String libraryPath = getApplicationInfo().dataDir + "/lib";
+		Log.i(TAG, libraryPath);
 
-        // Bind to LocalService
-        if (!mBound) {
-            Log.i(TAG, "onStart: Binding service...");
-            Intent intent = new Intent(this, SipService.class);
-            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-        }
+		// Bind to LocalService
+		if (!mBound) {
+			Log.i(TAG, "onStart: Binding service...");
+			Intent intent = new Intent(this, SipService.class);
+			bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+		}
 
-        setContentView(R.layout.activity_sflphone_home);
+		setContentView(R.layout.activity_sflphone_home);
 
-        if (mSectionsPagerAdapter == null) {
-            mSectionsPagerAdapter = new SectionsPagerAdapter(this, getFragmentManager());
-        }
+		if (mSectionsPagerAdapter == null) {
+			mSectionsPagerAdapter = new SectionsPagerAdapter(this, getFragmentManager());
+		}
 
-        /* getFragment(Bundle, String) */
-        if (savedInstanceState != null) {
-            Log.w(TAG, "Activity restarted, recreating PagerAdapter...");
-            /* getFragment (Bundle bundle, String key) */
-            mDialingFragment = (DialingFragment) getFragmentManager().getFragment(savedInstanceState,
-                    mSectionsPagerAdapter.getClassName(ACTION_BAR_TAB_DIALING));
-            mCallElementList = (CallElementListFragment) getFragmentManager().getFragment(savedInstanceState,
-                    mSectionsPagerAdapter.getClassName(ACTION_BAR_TAB_CALL));
-            mHistorySectionFragment = (HistoryFragment) getFragmentManager().getFragment(savedInstanceState,
-                    mSectionsPagerAdapter.getClassName(ACTION_BAR_TAB_HISTORY));
-        }
+		/* getFragment(Bundle, String) */
+		if (savedInstanceState != null) {
+			Log.w(TAG, "Activity restarted, recreating PagerAdapter...");
+			/* getFragment (Bundle bundle, String key) */
+			mDialingFragment = (DialingFragment) getFragmentManager().getFragment(savedInstanceState,
+					mSectionsPagerAdapter.getClassName(ACTION_BAR_TAB_DIALING));
+			mCallElementList = (CallElementListFragment) getFragmentManager().getFragment(savedInstanceState,
+					mSectionsPagerAdapter.getClassName(ACTION_BAR_TAB_CALL));
+			mHistorySectionFragment = (HistoryFragment) getFragmentManager().getFragment(savedInstanceState,
+					mSectionsPagerAdapter.getClassName(ACTION_BAR_TAB_HISTORY));
+		}
 
-        if (mDialingFragment == null) {
-            mDialingFragment = new DialingFragment();
-            Log.w(TAG, "Recreated mDialingFragment=" + mDialingFragment);
-        }
+		if (mDialingFragment == null) {
+			mDialingFragment = new DialingFragment();
+			Log.w(TAG, "Recreated mDialingFragment=" + mDialingFragment);
+		}
 
-        if (mContactsFragment == null) {
-            mContactsFragment = new ContactListFragment();
-            Log.w(TAG, "Recreated mContactListFragment=" + mContactsFragment);
-            getFragmentManager().beginTransaction().replace(R.id.contacts_frame, mContactsFragment).commit();
-        }
-        if (mCallElementList == null) {
-            mCallElementList = new CallElementListFragment();
-            Log.w(TAG, "Recreated mCallElementList=" + mCallElementList);
-        }
-        if (mHistorySectionFragment == null) {
-            mHistorySectionFragment = new HistoryFragment();
-            Log.w(TAG, "Recreated mHistorySectionFragment=" + mHistorySectionFragment);
-        }
+		if (mContactsFragment == null) {
+			mContactsFragment = new ContactListFragment();
+			Log.w(TAG, "Recreated mContactListFragment=" + mContactsFragment);
+			getFragmentManager().beginTransaction().replace(R.id.contacts_frame, mContactsFragment).commit();
+		}
+		if (mCallElementList == null) {
+			mCallElementList = new CallElementListFragment();
+			Log.w(TAG, "Recreated mCallElementList=" + mCallElementList);
+		}
+		if (mHistorySectionFragment == null) {
+			mHistorySectionFragment = new HistoryFragment();
+			Log.w(TAG, "Recreated mHistorySectionFragment=" + mHistorySectionFragment);
+		}
 
-        mDrawer = (CustomSlidingDrawer) findViewById(R.id.custom_sliding_drawer);
+		mDrawer = (CustomSlidingDrawer) findViewById(R.id.custom_sliding_drawer);
 
-        mContactsFragment.setHandleView((RelativeLayout) findViewById(R.id.slider_button));
+		mContactsFragment.setHandleView((RelativeLayout) findViewById(R.id.slider_button));
 
-        mDrawer.setmTrackHandle(findViewById(R.id.handle_title));
+		mDrawer.setmTrackHandle(findViewById(R.id.handle_title));
 
-        final ActionBar actionBar = getActionBar();
-        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+		final ActionBar actionBar = getActionBar();
+		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
 
-        // Set up the ViewPager with the sections adapter.
-        mViewPager = (ViewPager) findViewById(R.id.pager);
-        mViewPager.setAdapter(mSectionsPagerAdapter);
+		// Set up the ViewPager with the sections adapter.
+		mViewPager = (ViewPager) findViewById(R.id.pager);
+		mViewPager.setAdapter(mSectionsPagerAdapter);
 
-        mTitle = mDrawerTitle = getTitle();
-        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
-        // mDrawerList = (ListView) findViewById(R.id.left_drawer);
+		mTitle = mDrawerTitle = getTitle();
+		mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+		// mDrawerList = (ListView) findViewById(R.id.left_drawer);
 
-        // set a custom shadow that overlays the main content when the drawer opens
-        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
-        // set up the drawer's list view with items and click listener
-        // mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mPlanetTitles));
-        // mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
+		// set a custom shadow that overlays the main content when the drawer opens
+		mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
+		// set up the drawer's list view with items and click listener
+		// mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mPlanetTitles));
+		// mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
 
-        getActionBar().setDisplayHomeAsUpEnabled(true);
-        getActionBar().setHomeButtonEnabled(true);
+		getActionBar().setDisplayHomeAsUpEnabled(true);
+		getActionBar().setHomeButtonEnabled(true);
 
-        mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
-        mDrawerLayout, /* DrawerLayout object */
-        R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
-        R.string.drawer_open, /* "open drawer" description for accessibility */
-        R.string.drawer_close /* "close drawer" description for accessibility */
-        ) {
-            public void onDrawerClosed(View view) {
-                getActionBar().setTitle(mTitle);
-                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
-            }
+		mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
+				mDrawerLayout, /* DrawerLayout object */
+				R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
+				R.string.drawer_open, /* "open drawer" description for accessibility */
+				R.string.drawer_close /* "close drawer" description for accessibility */
+				) {
+			@Override
+			public void onDrawerClosed(View view) {
+				getActionBar().setTitle(mTitle);
+				invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
+			}
 
-            public void onDrawerOpened(View drawerView) {
-                getActionBar().setTitle(mDrawerTitle);
-                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
-            }
-        };
+			@Override
+			public void onDrawerOpened(View drawerView) {
+				getActionBar().setTitle(mDrawerTitle);
+				invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
+			}
+		};
 
-        mDrawerLayout.setDrawerListener(mDrawerToggle);
+		mDrawerLayout.setDrawerListener(mDrawerToggle);
 
-        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
-            @Override
-            public void onPageSelected(int position) {
-                actionBar.setSelectedNavigationItem(position);
-            }
-        });
+		mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+			@Override
+			public void onPageSelected(int position) {
+				actionBar.setSelectedNavigationItem(position);
+			}
+		});
 
-        // For each of the sections in the app, add a tab to the action bar.
-        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
+		// For each of the sections in the app, add a tab to the action bar.
+		for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
 
-            actionBar.addTab(actionBar.newTab().setIcon(icon_res_id[i]).setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
-        }
+			actionBar.addTab(actionBar.newTab().setIcon(icon_res_id[i]).setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
+		}
 
-        actionBar.setSelectedNavigationItem(ACTION_BAR_TAB_CALL);
+		actionBar.setSelectedNavigationItem(ACTION_BAR_TAB_CALL);
 
-        fMenu = new MenuFragment();
-        getFragmentManager().beginTransaction().replace(R.id.left_drawer, fMenu).commit();
-    }
+		fMenu = new MenuFragment();
+		getFragmentManager().beginTransaction().replace(R.id.left_drawer, fMenu).commit();
+	}
 
-    @Override
-    protected void onStart() {
-        Log.i(TAG, "onStart");
-        super.onStart();
-    }
+	@Override
+	protected void onStart() {
+		Log.i(TAG, "onStart");
+		super.onStart();
+	}
 
-    /* user gets back to the activity, e.g. through task manager */
-    @Override
-    protected void onRestart() {
-        super.onRestart();
-    }
+	/* user gets back to the activity, e.g. through task manager */
+	@Override
+	protected void onRestart() {
+		super.onRestart();
+	}
 
-    /* activity gets back to the foreground and user input */
-    @Override
-    protected void onResume() {
-        Log.i(TAG, "onResume");
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(CallManagerCallBack.INCOMING_CALL);
-        intentFilter.addAction(CallManagerCallBack.INCOMING_TEXT);
-        intentFilter.addAction(CallManagerCallBack.CALL_STATE_CHANGED);
-        registerReceiver(receiver, intentFilter);
-        super.onResume();
-    }
+	/* activity gets back to the foreground and user input */
+	@Override
+	protected void onResume() {
+		Log.i(TAG, "onResume");
+		IntentFilter intentFilter = new IntentFilter();
+		intentFilter.addAction(CallManagerCallBack.INCOMING_CALL);
+		intentFilter.addAction(CallManagerCallBack.INCOMING_TEXT);
+		intentFilter.addAction(CallManagerCallBack.CALL_STATE_CHANGED);
+		registerReceiver(receiver, intentFilter);
+		super.onResume();
+	}
 
-    /* activity no more in foreground */
-    @Override
-    protected void onPause() {
-        super.onPause();
-        unregisterReceiver(receiver);
-    }
+	/* activity no more in foreground */
+	@Override
+	protected void onPause() {
+		super.onPause();
+		unregisterReceiver(receiver);
+	}
 
-    /* activity is no longer visible */
-    @Override
-    protected void onStop() {
-        super.onStop();
-    }
+	/* activity is no longer visible */
+	@Override
+	protected void onStop() {
+		super.onStop();
+	}
 
-    /* activity finishes itself or is being killed by the system */
-    @Override
-    protected void onDestroy() {
-        /* stop the service, if no other bound user, no need to check if it is running */
-        if (mBound) {
-            Log.i(TAG, "onDestroy: Unbinding service...");
-            unbindService(mConnection);
-            mBound = false;
-        }
+	/* activity finishes itself or is being killed by the system */
+	@Override
+	protected void onDestroy() {
+		/* stop the service, if no other bound user, no need to check if it is running */
+		if (mBound) {
+			Log.i(TAG, "onDestroy: Unbinding service...");
+			unbindService(mConnection);
+			mBound = false;
+		}
 
-        super.onDestroy();
-    }
+		super.onDestroy();
+	}
 
-    public void launchCallActivity(SipCall infos, String action) {
-        Log.i(TAG, "Launch Call Activity");
-        Bundle bundle = new Bundle();
-        bundle.putString("action", action);
-        bundle.putParcelable("CallInfo", infos);
-        Intent intent = new Intent().setClass(this, CallActivity.class);
-        intent.putExtras(bundle);
-        startActivityForResult(intent, REQUEST_CODE_CALL);
-    }
+	public void launchCallActivity(SipCall infos, String action) {
+		Log.i(TAG, "Launch Call Activity");
+		Bundle bundle = new Bundle();
+		bundle.putString("action", action);
+		bundle.putParcelable("CallInfo", infos);
+		Intent intent = new Intent().setClass(this, CallActivity.class);
+		intent.putExtras(bundle);
+		startActivityForResult(intent, REQUEST_CODE_CALL);
+	}
 
-    /** Defines callbacks for service binding, passed to bindService() */
-    private ServiceConnection mConnection = new ServiceConnection() {
+	/** Defines callbacks for service binding, passed to bindService() */
+	private ServiceConnection mConnection = new ServiceConnection() {
 
-        @Override
-        public void onServiceConnected(ComponentName className, IBinder binder) {
-            service = ISipService.Stub.asInterface(binder);
+		@Override
+		public void onServiceConnected(ComponentName className, IBinder binder) {
+			service = ISipService.Stub.asInterface(binder);
 
-            mBound = true;
-            mCallElementList.onServiceSipBinded(service);
-            mHistorySectionFragment.onServiceSipBinded(service);
-            mDialingFragment.onServiceSipBinded(service);
-            Log.d(TAG, "Service connected service=" + service);
+			mBound = true;
+			mCallElementList.onServiceSipBinded(service);
+			mHistorySectionFragment.onServiceSipBinded(service);
+			mDialingFragment.onServiceSipBinded(service);
+			Log.d(TAG, "Service connected service=" + service);
 
-        }
+		}
 
-        @Override
-        public void onServiceDisconnected(ComponentName arg0) {
+		@Override
+		public void onServiceDisconnected(ComponentName arg0) {
 
-            mBound = false;
-            Log.d(TAG, "Service disconnected service=" + service);
-        }
-    };
+			mBound = false;
+			Log.d(TAG, "Service disconnected service=" + service);
+		}
+	};
 
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        Log.i(TAG, "onOptionsItemSelected " + item.getItemId());
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		Log.i(TAG, "onOptionsItemSelected " + item.getItemId());
 
-        if (mDrawerToggle.onOptionsItemSelected(item)) {
-            return true;
-        }
+		if (mDrawerToggle.onOptionsItemSelected(item)) {
+			return true;
+		}
 
-        return super.onOptionsItemSelected(item);
-    }
+		return super.onOptionsItemSelected(item);
+	}
 
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
+	@Override
+	public void onActivityResult(int requestCode, int resultCode, Intent data) {
+		super.onActivityResult(requestCode, resultCode, data);
 
-        switch (requestCode) {
-        case REQUEST_CODE_PREFERENCES:
-            mCallElementList.onServiceSipBinded(service);
-            break;
-        case REQUEST_CODE_CALL:
+		switch (requestCode) {
+		case REQUEST_CODE_PREFERENCES:
+			mCallElementList.onServiceSipBinded(service);
+			break;
+		case REQUEST_CODE_CALL:
 
-            break;
-        }
+			break;
+		}
 
-    }
+	}
 
-    // @Override
-    // public boolean onCreateOptionsMenu(Menu menu) {
-    // getMenuInflater().inflate(R.menu.activity_sflphone_home, menu);
-    // return true;
-    // }
+	// @Override
+	// public boolean onCreateOptionsMenu(Menu menu) {
+	// getMenuInflater().inflate(R.menu.activity_sflphone_home, menu);
+	// return true;
+	// }
 
-    @Override
-    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
-    }
+	@Override
+	public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+	}
 
-    @Override
-    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
-        // When the given tab is selected, switch to the corresponding page in the ViewPager.
-        mViewPager.setCurrentItem(tab.getPosition());
-    }
+	@Override
+	public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+		// When the given tab is selected, switch to the corresponding page in the ViewPager.
+		mViewPager.setCurrentItem(tab.getPosition());
+	}
 
-    @Override
-    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
-        // Log.d(TAG, "onTabReselected");
-    }
+	@Override
+	public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+		// Log.d(TAG, "onTabReselected");
+	}
 
-    @Override
-    public void onCallSelected(SipCall c) {
-        // launchCallActivity(c.mCallInfo);
+	@Override
+	public void onCallSelected(SipCall c) {
+		// launchCallActivity(c.mCallInfo);
 
-    }
+	}
 
-    @Override
-    public ISipService getService() {
-        return service;
-    }
+	@Override
+	public ISipService getService() {
+		return service;
+	}
 
-    /**
-     * Interface implemented to handle incoming events
-     */
-    @Override
-    public void incomingCall(Intent call) {
-        Toast.makeText(this, "New Call incoming", Toast.LENGTH_LONG).show();
-        SipCall infos = call.getParcelableExtra("newcall");
+	/**
+	 * Interface implemented to handle incoming events
+	 */
+	@Override
+	public void incomingCall(Intent call) {
+		Toast.makeText(this, "New Call incoming", Toast.LENGTH_LONG).show();
+		SipCall infos = call.getParcelableExtra("newcall");
 
-        mCallElementList.addCall(infos);
+		mCallElementList.addCall(infos);
 
-        launchCallActivity(infos, CallManagerCallBack.INCOMING_CALL);
+		launchCallActivity(infos, CallManagerCallBack.INCOMING_CALL);
 
-    }
+	}
 
-    @Override
-    public void callStateChanged(Intent callState) {
-        Bundle b = callState.getBundleExtra("com.savoirfairelinux.sflphone.service.newstate");
-        String cID = b.getString("CallID");
-        String state = b.getString("State");
-        Log.i(TAG, "callStateChanged" + cID + "    " + state);
-        mCallElementList.updateCall(cID, state);
+	@Override
+	public void callStateChanged(Intent callState) {
+		Bundle b = callState.getBundleExtra("com.savoirfairelinux.sflphone.service.newstate");
+		String cID = b.getString("CallID");
+		String state = b.getString("State");
+		Log.i(TAG, "callStateChanged" + cID + "    " + state);
+		mCallElementList.updateCall(cID, state);
 
-    }
+	}
 
-    @Override
-    public void incomingText(Intent msg) {
-        Bundle b = msg.getBundleExtra("com.savoirfairelinux.sflphone.service.newtext");
-        b.getString("CallID");
-        String from = b.getString("From");
-        String mess = b.getString("Msg");
-        Toast.makeText(getApplicationContext(), "text from " + from + " : " + mess, Toast.LENGTH_LONG).show();
-    }
+	@Override
+	public void incomingText(Intent msg) {
+		Bundle b = msg.getBundleExtra("com.savoirfairelinux.sflphone.service.newtext");
+		b.getString("CallID");
+		String from = b.getString("From");
+		String mess = b.getString("Msg");
+		Toast.makeText(getApplicationContext(), "text from " + from + " : " + mess, Toast.LENGTH_LONG).show();
+	}
 
-    @Override
-    public void onContactSelected(CallContact c) {
+	@Override
+	public void onContactSelected(CallContact c) {
 
-        SipCall.SipCallBuilder callBuilder = SipCall.SipCallBuilder.getInstance();
-        try {
-            callBuilder.startCallCreation().setAccountID(service.getAccountList().get(1).toString()).setCallType(SipCall.state.CALL_TYPE_OUTGOING);
-        } catch (RemoteException e1) {
-            Log.e(TAG,e1.toString());
-        }
-        callBuilder.addContact(c);
+		SipCall.SipCallBuilder callBuilder = SipCall.SipCallBuilder.getInstance();
+		try {
+			callBuilder.startCallCreation().setAccountID(service.getAccountList().get(0).toString()).setCallType(SipCall.state.CALL_TYPE_OUTGOING);
+		} catch (RemoteException e1) {
+			Log.e(TAG,e1.toString());
+		}
+		callBuilder.addContact(c);
 
-        try {
-            launchCallActivity(callBuilder.build(), "call");
-        } catch (Exception e) {
-            Log.e(TAG, e.toString());
-        }
+		try {
+			launchCallActivity(callBuilder.build(), "call");
+		} catch (Exception e) {
+			Log.e(TAG, e.toString());
+		}
 
-    }
+	}
 
-    @Override
-    public void onCallDialed(String accountID, String to) {
+	@Override
+	public void onCallDialed(String accountID, String to) {
 
-        SipCall.SipCallBuilder callBuilder = SipCall.SipCallBuilder.getInstance();
-        callBuilder.startCallCreation().setAccountID(accountID).setCallType(SipCall.state.CALL_TYPE_OUTGOING);
-        callBuilder.addContact(CallContact.ContactBuilder.buildUnknownContact(to));
+		SipCall.SipCallBuilder callBuilder = SipCall.SipCallBuilder.getInstance();
+		callBuilder.startCallCreation().setAccountID(accountID).setCallType(SipCall.state.CALL_TYPE_OUTGOING);
+		callBuilder.addContact(CallContact.ContactBuilder.buildUnknownContact(to));
 
-        try {
-            launchCallActivity(callBuilder.build(), "call");
-        } catch (Exception e) {
-            Log.e(TAG, e.toString());
-        }
+		try {
+			launchCallActivity(callBuilder.build(), "call");
+		} catch (Exception e) {
+			Log.e(TAG, e.toString());
+		}
 
-    }
+	}
 
 }
diff --git a/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java b/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
index b9ee971..35f0b11 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
@@ -36,6 +36,7 @@
 import android.app.Activity;
 import android.app.Fragment;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.PointF;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -54,264 +55,289 @@
 import com.savoirfairelinux.sflphone.model.BubblesView;
 import com.savoirfairelinux.sflphone.model.CallContact;
 import com.savoirfairelinux.sflphone.model.SipCall;
-import com.savoirfairelinux.sflphone.service.CallManagerCallBack;
 import com.savoirfairelinux.sflphone.service.ISipService;
 
 public class CallFragment extends Fragment {
-    static final String TAG = "CallFragment";
 
-    private SipCall mCall;
+	static final String TAG = "CallFragment";
 
-    private BubblesView view;
-    private BubbleModel model;
-    private PointF screenCenter;
-    private DisplayMetrics metrics;
+	static final float BUBBLE_SIZE = 100;
 
-    private Callbacks mCallbacks = sDummyCallbacks;
+	private SipCall mCall;
 
-    private HashMap<CallContact, Bubble> contacts = new HashMap<CallContact, Bubble>();
+	private BubblesView view;
+	private BubbleModel model;
+	private PointF screenCenter;
+	private DisplayMetrics metrics;
 
-    private TextView contact_name_txt;
+	private Callbacks mCallbacks = sDummyCallbacks;
 
-    CallContact myself = CallContact.ContactBuilder.buildUserContact("Me");
+	private HashMap<CallContact, Bubble> contacts = new HashMap<CallContact, Bubble>();
 
-    @Override
-    public void onCreate(Bundle savedBundle) {
-        super.onCreate(savedBundle);
-        model = new BubbleModel(getResources().getDisplayMetrics().density);
-        metrics = getResources().getDisplayMetrics();
-        screenCenter = new PointF(metrics.widthPixels / 2, metrics.heightPixels / 3);
+	private TextView contact_name_txt;
 
-        Bundle b = getArguments();
+	private CallContact myself = CallContact.ContactBuilder.buildUserContact("Me");
 
-        mCall = b.getParcelable("CallInfo");
-    }
+	private Bitmap hangup_icon;
+	private Bitmap call_icon;
 
-    /**
-     * 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 void onCreate(Bundle savedBundle) {
+		super.onCreate(savedBundle);
+		model = new BubbleModel(getResources().getDisplayMetrics().density);
+		metrics = getResources().getDisplayMetrics();
+		screenCenter = new PointF(metrics.widthPixels / 2, metrics.heightPixels / 3);
 
-        @Override
-        public void onSendMessage(SipCall call, String msg) {
+		Bundle b = getArguments();
 
-        }
+		mCall = b.getParcelable("CallInfo");
+		//mCall.
+	}
 
-        @Override
-        public void callContact(SipCall call) {
-        }
+	/**
+	 * 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 void onSendMessage(SipCall call, String msg) {
+		}
 
-        @Override
-        public void onCallAccepted(SipCall call) {
-            // TODO Auto-generated method stub
+		@Override
+		public void callContact(SipCall call) {
+		}
 
-        }
+		@Override
+		public void onCallAccepted(SipCall call) {
+		}
 
-        @Override
-        public void onCallRejected(SipCall call) {
-            // TODO Auto-generated method stub
+		@Override
+		public void onCallRejected(SipCall call) {
+		}
 
-        }
+		@Override
+		public void onCallEnded(SipCall call) {
+		}
 
-        @Override
-        public void onCallEnded(SipCall call) {
-            // TODO Auto-generated method stub
+		@Override
+		public void onCallSuspended(SipCall call) {
+		}
 
-        }
+		@Override
+		public void onCallResumed(SipCall call) {
+		}
 
-        @Override
-        public void onCallSuspended(SipCall call) {
-            // TODO Auto-generated method stub
+		@Override
+		public void onCalltransfered(SipCall call, String to) {
+		}
 
-        }
+		@Override
+		public void onRecordCall(SipCall call) {
+		}
 
-        @Override
-        public void onCallResumed(SipCall call) {
-            // TODO Auto-generated method stub
+		@Override
+		public ISipService getService() {
+			return null;
+		}
+	};
 
-        }
+	/**
+	 * The Activity calling this fragment has to implement this interface
+	 * 
+	 */
+	public interface Callbacks {
 
-        @Override
-        public void onCalltransfered(SipCall call, String to) {
-            // TODO Auto-generated method stub
+		public ISipService getService();
 
-        }
+		public void callContact(SipCall call);
 
-        @Override
-        public void onRecordCall(SipCall call) {
-            // TODO Auto-generated method stub
+		public void onCallAccepted(SipCall call);
 
-        }
+		public void onCallRejected(SipCall call);
 
-        @Override
-        public ISipService getService() {
-            // TODO Auto-generated method stub
-            return null;
-        }
-    };
+		public void onCallEnded(SipCall call);
 
-    /**
-     * The Activity calling this fragment has to implement this interface
-     * 
-     */
-    public interface Callbacks {
+		public void onCallSuspended(SipCall call);
 
-        public ISipService getService();
+		public void onCallResumed(SipCall call);
 
-        public void callContact(SipCall call);
+		public void onCalltransfered(SipCall call, String to);
 
-        public void onCallAccepted(SipCall call);
+		public void onRecordCall(SipCall call);
 
-        public void onCallRejected(SipCall call);
+		public void onSendMessage(SipCall call, String msg);
+	}
 
-        public void onCallEnded(SipCall call);
+	@Override
+	public void onAttach(Activity activity) {
+		super.onAttach(activity);
 
-        public void onCallSuspended(SipCall call);
+		if (!(activity instanceof Callbacks)) {
+			throw new IllegalStateException("Activity must implement fragment's callbacks.");
+		}
 
-        public void onCallResumed(SipCall call);
+		mCallbacks = (Callbacks) activity;
+	}
 
-        public void onCalltransfered(SipCall call, String to);
+	@Override
+	public void onDetach() {
+		super.onDetach();
+		mCallbacks = sDummyCallbacks;
+	}
 
-        public void onRecordCall(SipCall call);
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.frag_call, container, false);
 
-        public void onSendMessage(SipCall call, String msg);
-    }
+		view = (BubblesView) rootView.findViewById(R.id.main_view);
+		view.setModel(model);
 
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
+		hangup_icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_hangup);
+		call_icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_call);
 
-        if (!(activity instanceof Callbacks)) {
-            throw new IllegalStateException("Activity must implement fragment's callbacks.");
-        }
+		Log.i(TAG, "Starting fragment for call " + mCall.getCallId());
 
-        mCallbacks = (Callbacks) activity;
-    }
+		mCall.printCallInfo();
 
-    @Override
-    public void onDetach() {
-        super.onDetach();
-        mCallbacks = sDummyCallbacks;
-    }
+		if (mCall.isIncoming() && mCall.isRinging()) {
+			initIncomingCallDisplay();
+		} else {
+			if (mCall.isRinging()) {
+				initOutGoingCallDisplay();
+			}
+			try {
+				if (mCall.isOutGoing() && mCallbacks.getService().getCall(mCall.getCallId()) == null) {
+					mCallbacks.getService().placeCall(mCall);
+					initOutGoingCallDisplay();
+				} else if(mCall.isOutGoing() && mCall.isRinging()){
+					initOutGoingCallDisplay();
+				}
+			} catch (RemoteException e) {
+				Log.e(TAG, e.toString());
+			}
+		}
 
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.frag_call, container, false);
+		if(mCall.isOngoing()){
+			initNormalStateDisplay();
+		}
 
-        view = (BubblesView) rootView.findViewById(R.id.main_view);
-        view.setModel(model);
+		return rootView;
+	}
 
-        Log.i(TAG, "Starting fragment for call " + mCall.getCallId());
+	private void initNormalStateDisplay() {
+		Log.i(TAG, "Start normal display");
+		// TODO off-thread image loading
+		Bubble contact_bubble = getBubbleFor(mCall.getContacts().get(0), screenCenter.x, screenCenter.y);
+		Bubble me = getBubbleFor(myself, screenCenter.x, screenCenter.y * 3 / 2);
 
-        mCall.printCallInfo();
-        if (mCall.isRinging()) {
-            initOutGoingCallDisplay();
-        }
-        if (mCall.isIncoming() && mCall.isRinging()) {
-            initIncomingCallDisplay();
-        }
-        try {
-            if (mCall.isOutGoing() && mCallbacks.getService().getCall(mCall.getCallId()) == null) {
-                mCallbacks.getService().placeCall(mCall);
-                initOutGoingCallDisplay();
-            } else if(mCall.isOutGoing() && mCall.isRinging()){
-                initOutGoingCallDisplay();
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, e.toString());
-        }
+		/*	contact_bubble.setPos(screenCenter.x, screenCenter.y);
+		me.setPos(screenCenter.x, screenCenter.y * 3 / 2);*/
+		/*if (mCall.getContacts().get(0).getPhoto_id() > 0) {
+			Bitmap photo = ContactPictureLoader.loadContactPhoto(getActivity().getContentResolver(), mCall.getContacts().get(0).getId());
+			contact_bubble = new Bubble(screenCenter.x, screenCenter.y, 150, photo);
+		} else {
+			contact_bubble = new Bubble(getActivity(), screenCenter.x, screenCenter.y / 2 , 150, R.drawable.ic_contact_picture);
+		}
 
-        if(mCall.isOngoing()){
-            initNormalStateDisplay();
-        }
+		me = new Bubble(getActivity(), screenCenter.x, screenCenter.y * 3 / 2, 150, R.drawable.ic_contact_picture);
+		 */
+		model.clearAttractors();
+		model.addAttractor(new Attractor(new PointF(metrics.widthPixels / 2, metrics.heightPixels * .8f), 20, new Attractor.Callback() {
+			@Override
+			public void onBubbleSucked(Bubble b) {
+				Log.w(TAG, "Bubble sucked ! ");
+				mCallbacks.onCallEnded(mCall);
+			}
+		}, hangup_icon));
 
-        return rootView;
-    }
+		/*	contact_bubble.contact = mCall.getContacts().get(0);
+		me.contact = myself;
+		model.addBubble(contact_bubble);
+		model.addBubble(me);
+		contacts.put(mCall.getContacts().get(0), contact_bubble);
+		contacts.put(myself, me);*/
+	}
 
-    private void initNormalStateDisplay() {
-        Log.i(TAG, "Start normal display");
-        // TODO off-thread image loading
-        Bubble contact_bubble, me;
-        if (mCall.getContacts().get(0).getPhoto_id() > 0) {
-            Bitmap photo = ContactPictureLoader.loadContactPhoto(getActivity().getContentResolver(), mCall.getContacts().get(0).getId());
-            contact_bubble = new Bubble(getActivity(), screenCenter.x, screenCenter.y, 150, photo);
-        } else {
-            contact_bubble = new Bubble(getActivity(), screenCenter.x, screenCenter.y / 2 , 150, R.drawable.ic_contact_picture);
-        }
+	private void initIncomingCallDisplay() {
+		Log.i(TAG, "Start incoming display");
 
-        me = new Bubble(getActivity(), screenCenter.x, screenCenter.y * 3 / 2, 150, R.drawable.ic_contact_picture);
+		Bubble contact_bubble = getBubbleFor(mCall.getContacts().get(0), screenCenter.x, screenCenter.y);
+		contacts.put(mCall.getContacts().get(0), contact_bubble);
 
-        model.attractors.clear();
-        model.attractors.add(new Attractor(new PointF(metrics.widthPixels / 2, metrics.heightPixels * .8f), new Attractor.Callback() {
-            @Override
-            public void onBubbleSucked(Bubble b) {
-                Log.w(TAG, "Bubble sucked ! ");
-                mCallbacks.onCallEnded(mCall);
-            }
-        }));
+		model.clearAttractors();
+		model.addAttractor(new Attractor(new PointF(3 * metrics.widthPixels / 4, metrics.heightPixels / 4), 20, new Attractor.Callback() {
+			@Override
+			public void onBubbleSucked(Bubble b) {
+				mCallbacks.onCallAccepted(mCall);
+			}
+		}, call_icon));
+		model.addAttractor(new Attractor(new PointF(metrics.widthPixels / 4, metrics.heightPixels / 4), 20, new Attractor.Callback() {
+			@Override
+			public void onBubbleSucked(Bubble b) {
+				mCallbacks.onCallRejected(mCall);
+			}
+		}, hangup_icon));
+	}
 
-        contact_bubble.contact = mCall.getContacts().get(0);
-        me.contact = myself;
-        model.listBubbles.add(contact_bubble);
-        model.listBubbles.add(me);
-        contacts.put(mCall.getContacts().get(0), contact_bubble);
-        contacts.put(myself, me);
+	private void initOutGoingCallDisplay() {
+		Log.i(TAG, "Start outgoing display");
+		// TODO off-thread image loading
+		Bubble contact_bubble = getBubbleFor(mCall.getContacts().get(0), screenCenter.x, screenCenter.y);
 
-    }
+		model.clearAttractors();
+		model.addAttractor(new Attractor(new PointF(metrics.widthPixels / 2, metrics.heightPixels * .8f), 20, new Attractor.Callback() {
+			@Override
+			public void onBubbleSucked(Bubble b) {
+				Log.w(TAG, "Bubble sucked ! ");
+				mCallbacks.onCallEnded(mCall);
+			}
+		}, hangup_icon));
 
-    private void initIncomingCallDisplay() {
-        Log.i(TAG, "Start incoming display");
-        model.attractors.clear();
-        model.attractors.add(new Attractor(new PointF(3 * metrics.widthPixels / 4, metrics.heightPixels / 4), new Attractor.Callback() {
-            @Override
-            public void onBubbleSucked(Bubble b) {
-                mCallbacks.onCallAccepted(mCall);
-            }
-        }));
-        model.attractors.add(new Attractor(new PointF(metrics.widthPixels / 4, metrics.heightPixels / 4), new Attractor.Callback() {
-            @Override
-            public void onBubbleSucked(Bubble b) {
-                mCallbacks.onCallRejected(mCall);
-            }
-        }));
-    }
+		/*contact_bubble.contact = mCall.getContacts().get(0);
+		model.addBubble(contact_bubble);
+		contacts.put(mCall.getContacts().get(0), contact_bubble);*/
+	}
 
-    private void initOutGoingCallDisplay() {
-        Log.i(TAG, "Start outgoing display");
-        // TODO off-thread image loading
-        Bubble contact_bubble;
-        if (mCall.getContacts().get(0).getPhoto_id() > 0) {
-            Bitmap photo = ContactPictureLoader.loadContactPhoto(getActivity().getContentResolver(), mCall.getContacts().get(0).getId());
-            contact_bubble = new Bubble(getActivity(), screenCenter.x, screenCenter.y, 150, photo);
-        } else {
-            contact_bubble = new Bubble(getActivity(), screenCenter.x, screenCenter.y, 150, R.drawable.ic_contact_picture);
-        }
+	/**
+	 * Retrieves or create a bubble for a given contact.
+	 * If the bubble exists, it is moved to the new location.
+	 * 
+	 * @param contact The contact
+	 * @param x Initial or new x position.
+	 * @param y Initial or new y position.
+	 * @return Bubble corresponding to the contact.
+	 */
+	private Bubble getBubbleFor(CallContact contact, float x, float y) {
+		Bubble contact_bubble = contacts.get(contact);
+		if(contact_bubble != null) {
+			contact_bubble.attractor.set(x, y);
+			return contact_bubble;
+		}
 
-        model.attractors.clear();
-        model.attractors.add(new Attractor(new PointF(metrics.widthPixels / 2, metrics.heightPixels * .8f), new Attractor.Callback() {
-            @Override
-            public void onBubbleSucked(Bubble b) {
-                Log.w(TAG, "Bubble sucked ! ");
-                mCallbacks.onCallEnded(mCall);
-            }
-        }));
+		if (contact.getPhoto_id() > 0) {
+			Bitmap photo = ContactPictureLoader.loadContactPhoto(getActivity().getContentResolver(), mCall.getContacts().get(0).getId());
+			contact_bubble = new Bubble(x, y, BUBBLE_SIZE, photo);
+		} else {
+			contact_bubble = new Bubble(x, y, BUBBLE_SIZE, getActivity(), R.drawable.ic_contact_picture);
+		}
+		contact_bubble.contact = contact;
 
-        contact_bubble.contact = mCall.getContacts().get(0);
-        model.listBubbles.add(contact_bubble);
-        contacts.put(mCall.getContacts().get(0), contact_bubble);
-    }
+		model.addBubble(contact_bubble);
+		contacts.put(contact, contact_bubble);
 
-    public void changeCallState(String callID, String newState) {
-        
-        Log.w(TAG, "Changing call state of "+callID);
-        mCall.printCallInfo();
-        if(callID != mCall.getCallId())
-            return;
-        
-        mCall.setCallState(newState);
-        if(mCall.isOngoing()){
-            initNormalStateDisplay();
-        }
-    }
+		return contact_bubble;
+	}
+
+	public void changeCallState(String callID, String newState) {
+
+		Log.w(TAG, "Changing call state of "+callID);
+		mCall.printCallInfo();
+		if(!callID.equals(mCall.getCallId()))
+			return;
+
+		mCall.setCallState(newState);
+		if(mCall.isOngoing()){
+			initNormalStateDisplay();
+		}
+	}
 
 }
diff --git a/src/com/savoirfairelinux/sflphone/model/Attractor.java b/src/com/savoirfairelinux/sflphone/model/Attractor.java
index 5547dc8..51b1850 100644
--- a/src/com/savoirfairelinux/sflphone/model/Attractor.java
+++ b/src/com/savoirfairelinux/sflphone/model/Attractor.java
@@ -1,6 +1,10 @@
 package com.savoirfairelinux.sflphone.model;
 
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.PointF;
+import android.graphics.RectF;
 
 public class Attractor {
 
@@ -8,10 +12,36 @@
 		public void onBubbleSucked(Bubble b);
 	}
 
-	PointF pos;
-	Callback callback;
-	public Attractor(PointF pos, Callback callback) {
+	final PointF pos;
+	final float radius;
+
+	final Callback callback;
+	private final Bitmap img;
+
+	private final RectF bounds = new RectF();
+
+	public Attractor(PointF pos, float radius, Callback callback, Bitmap img) {
 		this.pos = pos;
+		this.radius = radius;
 		this.callback = callback;
+		this.img = img;
 	}
-}
\ No newline at end of file
+
+	public Attractor(PointF pos, float radius, Callback callback, Context c, int resId) {
+		this(pos, radius, callback, BitmapFactory.decodeResource(c.getResources(), resId));
+	}
+
+	public void setDensity(float density)
+	{
+		bounds.set(pos.x - radius*density, pos.y - radius*density, pos.x + radius*density, pos.y + radius*density);
+	}
+
+	public RectF getBounds() {
+		return bounds;
+	}
+
+	public Bitmap getBitmap() {
+		return img;
+	}
+
+}
diff --git a/src/com/savoirfairelinux/sflphone/model/Bubble.java b/src/com/savoirfairelinux/sflphone/model/Bubble.java
index 0dbd013..546bb3c 100644
--- a/src/com/savoirfairelinux/sflphone/model/Bubble.java
+++ b/src/com/savoirfairelinux/sflphone/model/Bubble.java
@@ -24,6 +24,7 @@
 	public float target_scale = 1.f;
 	private final float radius;
 	private float scale = 1.f;
+	private float density = 1.f;
 	public PointF speed = new PointF(0, 0);
 	public PointF last_speed = new PointF();
 	public PointF attractor = null;
@@ -36,7 +37,7 @@
 		this.attractor = attractor;
 	}
 
-	public Bubble(Context c, float x, float y, float rad, Bitmap photo) {
+	public Bubble(float x, float y, float rad, Bitmap photo) {
 		internalBMP = photo;
 		pos.set(x, y);
 
@@ -68,18 +69,11 @@
 		internalCanvas.drawBitmap(circle, 0, 0, mPaintPath);
 	}
 
-	public Bubble(Context c, float x, float y, float rad, int resID) {
+	public Bubble(float x, float y, float rad, Context c, int resID) {
 		// Initialize the bitmap object by loading an image from the resources folder
-		/*if (resID != -1)
-			internalBMP = BitmapFactory.decodeResource(c.getResources(), resID);
-		else
-			internalBMP = BitmapFactory.decodeResource(c.getResources(), R.drawable.ic_contact_picture);
-		 */
-		this(c, x, y, rad, BitmapFactory.decodeResource(c.getResources(), resID==-1 ? resID : R.drawable.ic_contact_picture));
+		this(x, y, rad, BitmapFactory.decodeResource(c.getResources(), resID==-1 ? resID : R.drawable.ic_contact_picture));
 	}
 
-
-
 	public Bitmap getBitmap() {
 		return externalBMP;
 	}
@@ -92,7 +86,7 @@
 		scale = s;
 		pos.x = x;
 		pos.y = y;
-		float rad = scale*radius;
+		float rad = scale*radius*density;
 		bounds.left = pos.x - rad;
 		bounds.right = pos.x + rad;
 		bounds.top = pos.y - rad;
@@ -144,4 +138,9 @@
 		float tot_radius = this.radius + radius;
 		return dx*dx + dy*dy < tot_radius*tot_radius;
 	}
+
+	public void setDensity(float density)
+	{
+		this.density = density;
+	}
 }
diff --git a/src/com/savoirfairelinux/sflphone/model/BubbleModel.java b/src/com/savoirfairelinux/sflphone/model/BubbleModel.java
index 460d9e9..87d3718 100644
--- a/src/com/savoirfairelinux/sflphone/model/BubbleModel.java
+++ b/src/com/savoirfairelinux/sflphone/model/BubbleModel.java
@@ -1,6 +1,7 @@
 package com.savoirfairelinux.sflphone.model;
 
 import java.util.ArrayList;
+import java.util.List;
 
 import android.graphics.PointF;
 
@@ -8,10 +9,10 @@
 {
 	private static final String TAG = BubbleModel.class.getSimpleName();
 
-	public long lastUpdate = 0;
+	private long lastUpdate = 0;
 	public int width, height;
-	public ArrayList<Bubble> listBubbles = new ArrayList<Bubble>();
-	public ArrayList<Attractor> attractors = new ArrayList<Attractor>();
+	private ArrayList<Bubble> bubbles = new ArrayList<Bubble>();
+	private ArrayList<Attractor> attractors = new ArrayList<Attractor>();
 
 	private static final double BUBBLE_RETURN_TIME_HALF_LIFE = .3;
 	private static final double BUBBLE_RETURN_TIME_LAMBDA = Math.log(2)/BUBBLE_RETURN_TIME_HALF_LIFE;
@@ -42,6 +43,35 @@
 		border_repulsion = BORDER_REPULSION*density;
 	}
 
+	public void addBubble(Bubble b) {
+		b.setDensity(density);
+		bubbles.add(b);
+	}
+
+	public List<Bubble> getBubbles()
+	{
+		return bubbles;
+	}
+
+	public void addAttractor(Attractor a) {
+		a.setDensity(density);
+		attractors.add(a);
+	}
+
+	public List<Attractor> getAttractors()
+	{
+		return attractors;
+	}
+
+	public void clearAttractors() {
+		attractors.clear();
+	}
+
+	public void clear() {
+		clearAttractors();
+		bubbles.clear();
+	}
+
 	public void update()
 	{
 		long now = System.nanoTime();
@@ -60,8 +90,8 @@
 
 		// Iterators should not be used in frequently called methods
 		// to avoid garbage collection glitches caused by iterator objects.
-		for(int i=0, n=listBubbles.size(); i<n; i++) {
-			Bubble b = listBubbles.get(i);
+		for(int i=0, n=bubbles.size(); i<n; i++) {
+			Bubble b = bubbles.get(i);
 			//Log.w(TAG, "update b");
 
 			if(!b.dragged) {
@@ -134,7 +164,7 @@
 
 				if(attractor != null && attractor_dist < attractor_dist_suck*attractor_dist_suck) {
 					attractor.callback.onBubbleSucked(b);
-					listBubbles.remove(b);
+					bubbles.remove(b);
 					n--;
 				}
 			}
@@ -143,4 +173,6 @@
 
 		}
 	}
+
+
 }
diff --git a/src/com/savoirfairelinux/sflphone/model/BubblesView.java b/src/com/savoirfairelinux/sflphone/model/BubblesView.java
index 1243275..8ca439a 100644
--- a/src/com/savoirfairelinux/sflphone/model/BubblesView.java
+++ b/src/com/savoirfairelinux/sflphone/model/BubblesView.java
@@ -1,11 +1,12 @@
 package com.savoirfairelinux.sflphone.model;

 

+import java.util.List;

+

 import android.content.Context;

 import android.graphics.Canvas;

 import android.graphics.Color;

 import android.graphics.Paint;

 import android.graphics.Paint.Align;

-import android.graphics.RectF;

 import android.os.Handler;

 import android.os.Message;

 import android.util.AttributeSet;

@@ -47,7 +48,7 @@
 

 		attractor_paint.setColor(Color.RED);

 		//attractor_paint.set

-		name_paint.setTextSize(20*textDensity);

+		name_paint.setTextSize(18*textDensity);

 		name_paint.setColor(0xFF303030);

 		name_paint.setTextAlign(Align.CENTER);

 	}

@@ -134,46 +135,55 @@
 

 		int action = event.getActionMasked();

 

-		if (action == MotionEvent.ACTION_DOWN) {

-			for (Bubble b : model.listBubbles) {

-				if (b.intersects(event.getX(), event.getY())) {

-					b.dragged = true;

-					b.last_drag = System.nanoTime();

-					b.setPos(event.getX(), event.getY());

-					b.target_scale = .8f;

-				}

-			}

-		} else if (action == MotionEvent.ACTION_MOVE) {

-			long now = System.nanoTime();

-			for (Bubble b : model.listBubbles) {

-				if (b.dragged) {

-					float x = event.getX(), y = event.getY();

-					float dt = (float) ((now-b.last_drag)/1000000000.);

-					float dx = x - b.getPosX(), dy = y - b.getPosY();

-					b.last_drag = now;

+		synchronized (model) {

+			List<Bubble> bubbles = model.getBubbles();

+			final int n_bubbles = bubbles.size();

 

-					b.setPos(event.getX(), event.getY());

-					/*int hn = event.getHistorySize() - 2;

+			if (action == MotionEvent.ACTION_DOWN) {

+				for(int i=0; i<n_bubbles; i++) {

+					Bubble b = bubbles.get(i);

+					if (b.intersects(event.getX(), event.getY())) {

+						b.dragged = true;

+						b.last_drag = System.nanoTime();

+						b.setPos(event.getX(), event.getY());

+						b.target_scale = .8f;

+					}

+				}

+			} else if (action == MotionEvent.ACTION_MOVE) {

+				long now = System.nanoTime();

+				for(int i=0; i<n_bubbles; i++) {

+					Bubble b = bubbles.get(i);

+					if (b.dragged) {

+						float x = event.getX(), y = event.getY();

+						float dt = (float) ((now-b.last_drag)/1000000000.);

+						float dx = x - b.getPosX(), dy = y - b.getPosY();

+						b.last_drag = now;

+

+						b.setPos(event.getX(), event.getY());

+						/*int hn = event.getHistorySize() - 2;

 					Log.w(TAG, "event.getHistorySize() : " + event.getHistorySize());

 					if(hn > 0) {

 						float dx = x-event.getHistoricalX(hn);

 						float dy = y-event.getHistoricalY(hn);

 						float dt = event.getHistoricalEventTime(hn)/1000.f;*/

-					b.speed.x = dx/dt;

-					b.speed.y = dy/dt;

-					//Log.w(TAG, "onTouch dx:" + b.speed.x + " dy:" + b.speed.y);

-					//}

-					return true;

+						b.speed.x = dx/dt;

+						b.speed.y = dy/dt;

+						//Log.w(TAG, "onTouch dx:" + b.speed.x + " dy:" + b.speed.y);

+						//}

+						return true;

+					}

 				}

-			}

-		} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {

-			for (Bubble b : model.listBubbles) {

-				if (b.dragged) {

-					b.dragged = false;

-					b.target_scale = 1.f;

+			} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {

+				for(int i=0; i<n_bubbles; i++) {

+					Bubble b = bubbles.get(i);

+					if (b.dragged) {

+						b.dragged = false;

+						b.target_scale = 1.f;

+					}

 				}

 			}

 		}

+

 		return true;

 	}

 

@@ -212,9 +222,6 @@
 						doDraw(c);

 					}

 				} finally {

-					// do this in a finally so that if an exception is thrown

-					// during the above, we don't leave the Surface in an

-					// inconsistent state

 					if (c != null)

 						surfaceHolder.unlockCanvasAndPost(c);

 				}

@@ -233,9 +240,6 @@
 					model.width = width;

 					model.height = height;

 				}

-

-				// don't forget to resize the background image

-				//  mBackgroundImage = Bitmap.createScaledBitmap(mBackgroundImage, width, height, true);

 			}

 		}

 

@@ -244,23 +248,19 @@
 			canvas.drawColor(Color.WHITE);

 

 			synchronized (model) {

-				for (int i = 0; i < model.attractors.size(); i++) {

-					Attractor a = model.attractors.get(i);

-					canvas.drawCircle(a.pos.x, a.pos.y, 10, attractor_paint);

+				List<Bubble> bubbles = model.getBubbles();

+				List<Attractor> attractors = model.getAttractors();

+

+				for (int i=0, n=attractors.size(); i < n; i++) {

+					Attractor a = attractors.get(i);

+					//canvas.drawCircle(a.pos.x, a.pos.y, 10, attractor_paint);

+					canvas.drawBitmap(a.getBitmap(), null, a.getBounds(), null);

 				}

 

-				for (int i = 0; i < model.listBubbles.size(); i++) {

-					Bubble b = model.listBubbles.get(i);

-					RectF bounds = new RectF(b.getBounds());

-					/*if(b.dragged) {

-						float width = bounds.left - bounds.right;

-						float red = width/4;

-						bounds.left += red;

-						bounds.right -= red;

-						bounds.top += red;

-						bounds.bottom -= red;

-					}*/

-					canvas.drawBitmap(b.getBitmap(), null, bounds, null);

+				for (int i=0, n=bubbles.size(); i<n; i++) {

+					Bubble b = bubbles.get(i);

+					//RectF bounds = new RectF(b.getBounds());

+					canvas.drawBitmap(b.getBitmap(), null, b.getBounds(), null);

 					canvas.drawText(b.contact.getmDisplayName(), b.getPosX(), b.getPosY()-50*density, name_paint);

 				}

 			}