Bubbles cleanup and bug fixes.
diff --git a/src/com/savoirfairelinux/sflphone/client/CallActivity.java b/src/com/savoirfairelinux/sflphone/client/CallActivity.java
index e8d87de..8c59016 100644
--- a/src/com/savoirfairelinux/sflphone/client/CallActivity.java
+++ b/src/com/savoirfairelinux/sflphone/client/CallActivity.java
@@ -47,7 +47,6 @@
 import android.os.Environment;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.support.v4.view.ViewPager;
 import android.support.v4.widget.SlidingPaneLayout;
 import android.util.Log;
 import android.view.View;
@@ -63,364 +62,368 @@
 import com.savoirfairelinux.sflphone.service.CallManagerCallBack;
 import com.savoirfairelinux.sflphone.service.ISipService;
 import com.savoirfairelinux.sflphone.service.SipService;
+import com.savoirfairelinux.sflphone.views.CallPaneLayout;
 
 public class CallActivity extends Activity implements CallInterface, CallFragment.Callbacks, CallListFragment.Callbacks {
-    static final String TAG = "CallActivity";
-    private ISipService service;
+	static final String TAG = "CallActivity";
+	private ISipService service;
 
-    private String pendingAction = null;
+	private String pendingAction = null;
 
-    private ExecutorService infos_fetcher = Executors.newCachedThreadPool();
-    CallReceiver receiver;
-    
-    SlidingPaneLayout slidingPaneLayout;
+	private ExecutorService infos_fetcher = Executors.newCachedThreadPool();
+	CallReceiver receiver;
 
-    CallListFragment mCallsFragment;
-    CallFragment mCurrentCallFragment;
+	CallPaneLayout slidingPaneLayout;
 
-    // private CallPagerAdapter mCallPagerAdapter;
-    // private ViewPager mViewPager;
+	CallListFragment mCallsFragment;
+	CallFragment mCurrentCallFragment;
 
-    /*
-     * private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
-     * 
-     * @Override public void onReceive(Context context, Intent intent) { String signalName = intent.getStringExtra(CallManagerCallBack.SIGNAL_NAME);
-     * Log.d(TAG, "Signal received: " + signalName);
-     * 
-     * if (signalName.equals(CallManagerCallBack.NEW_CALL_CREATED)) { } else if (signalName.equals(CallManagerCallBack.CALL_STATE_CHANGED)) {
-     * processCallStateChangedSignal(intent); } else if (signalName.equals(CallManagerCallBack.INCOMING_CALL)) { } } };
-     */
+	// private CallPagerAdapter mCallPagerAdapter;
+	// private ViewPager mViewPager;
 
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_call_layout);
+	/*
+	 * private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
+	 * 
+	 * @Override public void onReceive(Context context, Intent intent) { String signalName = intent.getStringExtra(CallManagerCallBack.SIGNAL_NAME);
+	 * Log.d(TAG, "Signal received: " + signalName);
+	 * 
+	 * if (signalName.equals(CallManagerCallBack.NEW_CALL_CREATED)) { } else if (signalName.equals(CallManagerCallBack.CALL_STATE_CHANGED)) {
+	 * processCallStateChangedSignal(intent); } else if (signalName.equals(CallManagerCallBack.INCOMING_CALL)) { } } };
+	 */
 
-        receiver = new CallReceiver(this);
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_call_layout);
 
-        mCallsFragment = new CallListFragment();
+		receiver = new CallReceiver(this);
 
-        getFragmentManager().beginTransaction().replace(R.id.calllist_pane, mCallsFragment).commit();
+		mCallsFragment = new CallListFragment();
 
-        slidingPaneLayout = (SlidingPaneLayout) findViewById(R.id.slidingpanelayout);
-        slidingPaneLayout.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() {
+		getFragmentManager().beginTransaction().replace(R.id.calllist_pane, mCallsFragment).commit();
 
-            @Override
-            public void onPanelSlide(View view, float offSet) {
-            }
+		slidingPaneLayout = (CallPaneLayout) findViewById(R.id.slidingpanelayout);
+		// slidingPaneLayout.requestDisallowInterceptTouchEvent(disallowIntercept)
+		slidingPaneLayout.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() {
 
-            @Override
-            public void onPanelOpened(View view) {
+			@Override
+			public void onPanelSlide(View view, float offSet) {
+			}
 
-                switch (view.getId()) {
-                case R.id.calllist_pane:
-                    // getFragmentManager().findFragmentById(R.id.calllist_pane).setHasOptionsMenu(true);
-                    // getFragmentManager().findFragmentById(R.id.ongoingcall_pane).setHasOptionsMenu(false);
-                    break;
-                default:
-                    break;
-                }
-            }
+			@Override
+			public void onPanelOpened(View view) {
 
-            @Override
-            public void onPanelClosed(View view) {
+				switch (view.getId()) {
+				case R.id.calllist_pane:
+					// getFragmentManager().findFragmentById(R.id.calllist_pane).setHasOptionsMenu(true);
+					// getFragmentManager().findFragmentById(R.id.ongoingcall_pane).setHasOptionsMenu(false);
+					break;
+				default:
+					break;
+				}
+			}
 
-                switch (view.getId()) {
-                case R.id.ongoingcall_pane:
-                    // getFragmentManager().findFragmentById(R.id.calllist_pane).setHasOptionsMenu(false);
-                    // getFragmentManager().findFragmentById(R.id.ongoingcall_pane).setHasOptionsMenu(true);
-                    break;
-                default:
-                    break;
-                }
-            }
-        });
+			@Override
+			public void onPanelClosed(View view) {
 
-        Bundle b = getIntent().getExtras();
+				switch (view.getId()) {
+				case R.id.ongoingcall_pane:
+					// getFragmentManager().findFragmentById(R.id.calllist_pane).setHasOptionsMenu(false);
+					// getFragmentManager().findFragmentById(R.id.ongoingcall_pane).setHasOptionsMenu(true);
+					break;
+				default:
+					break;
+				}
+			}
+		});
 
-        Intent intent = new Intent(this, SipService.class);
+		Bundle b = getIntent().getExtras();
 
-        // setCallStateDisplay(mCall.getCallStateString());
+		Intent intent = new Intent(this, SipService.class);
 
-        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+		// setCallStateDisplay(mCall.getCallStateString());
 
-    }
+		bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
 
-    /* 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 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();
+	}
 
-    @Override
-    protected void onDestroy() {
-        // Log.i(TAG, "Destroying Call Activity for call " + mCall.getCallId());
-        // LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
-        unbindService(mConnection);
+	/* activity no more in foreground */
+	@Override
+	protected void onPause() {
+		super.onPause();
+		unregisterReceiver(receiver);
+	}
 
-        super.onDestroy();
-    }
+	@Override
+	protected void onDestroy() {
+		// Log.i(TAG, "Destroying Call Activity for call " + mCall.getCallId());
+		// LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
+		unbindService(mConnection);
 
-    /** 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);
-            Log.i(TAG, "Placing call");
-            mCurrentCallFragment = new CallFragment();
-            mCurrentCallFragment.setArguments(getIntent().getExtras());
-            getIntent().getExtras();
-            // SipCall info = getIntent().getExtras().getParcelable("CallInfo");
-            // mCallPagerAdapter.addCall(info.mCallID, newCall);
-            getFragmentManager().beginTransaction().replace(R.id.ongoingcall_pane, mCurrentCallFragment).commit();
+		super.onDestroy();
+	}
 
-        }
+	/** 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);
+			Log.i(TAG, "Placing call");
+			mCurrentCallFragment = new CallFragment();
+			mCurrentCallFragment.setArguments(getIntent().getExtras());
+			slidingPaneLayout.curFragment = mCurrentCallFragment;
+			getIntent().getExtras();
+			// SipCall info = getIntent().getExtras().getParcelable("CallInfo");
+			// mCallPagerAdapter.addCall(info.mCallID, newCall);
+			getFragmentManager().beginTransaction().replace(R.id.ongoingcall_pane, mCurrentCallFragment).commit();
 
-        @Override
-        public void onServiceDisconnected(ComponentName arg0) {
-        }
-    };
+		}
 
-    @Override
-    public void incomingCall(Intent call) {
-        Toast.makeText(this, "New Call incoming", Toast.LENGTH_LONG).show();
+		@Override
+		public void onServiceDisconnected(ComponentName arg0) {
+		}
+	};
 
-        mCallsFragment.update();
+	@Override
+	public void incomingCall(Intent call) {
+		Toast.makeText(this, "New Call incoming", Toast.LENGTH_LONG).show();
 
-    }
+		mCallsFragment.update();
 
-    @Override
-    public void callStateChanged(Intent callState) {
+	}
 
-        Bundle b = callState.getBundleExtra("com.savoirfairelinux.sflphone.service.newstate");
-        processCallStateChangedSignal(b.getString("CallID"), b.getString("State"));
+	@Override
+	public void callStateChanged(Intent callState) {
 
-    }
+		Bundle b = callState.getBundleExtra("com.savoirfairelinux.sflphone.service.newstate");
+		processCallStateChangedSignal(b.getString("CallID"), b.getString("State"));
 
-    public void processCallStateChangedSignal(String callID, String newState) {
-        /*
-         * Bundle bundle = intent.getBundleExtra("com.savoirfairelinux.sflphone.service.newstate"); String callID = bundle.getString("CallID"); String
-         * newState = bundle.getString("State");
-         */
-        // CallFragment fr = mCurrentCallFragment;
+	}
 
-        mCallsFragment.update();
-        
-        mCurrentCallFragment.changeCallState(callID, newState);
-        
-        HashMap<String, SipCall> map;
-        try {
-            map = (HashMap<String, SipCall>) service.getCallList();
-            if(map.size() == 0){
-                finish();
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, e.toString());
-        }
-        
-        
+	public void processCallStateChangedSignal(String callID, String newState) {
+		/*
+		 * Bundle bundle = intent.getBundleExtra("com.savoirfairelinux.sflphone.service.newstate"); String callID = bundle.getString("CallID"); String
+		 * newState = bundle.getString("State");
+		 */
+		// CallFragment fr = mCurrentCallFragment;
 
-        // if (newState.equals("INCOMING")) {
-        // fr.changeCallState(SipCall.state.CALL_STATE_INCOMING);
-        //
-        // } else if (newState.equals("RINGING")) {
-        // fr.changeCallState(SipCall.state.CALL_STATE_RINGING);
-        //
-        // } else if (newState.equals("CURRENT")) {
-        // fr.changeCallState(SipCall.state.CALL_STATE_CURRENT);
-        //
-        // } else if (newState.equals("HUNGUP")) {
-        // // mCallPagerAdapter.remove(callID);
-        // // if (mCallPagerAdapter.getCount() == 0) {
-        // // finish();
-        // // }
-        //
-        // } else if (newState.equals("BUSY")) {
-        // // mCallPagerAdapter.remove(callID);
-        // // if (mCallPagerAdapter.getCount() == 0) {
-        // // finish();
-        // // }
-        //
-        // } else if (newState.equals("FAILURE")) {
-        // // mCallPagerAdapter.remove(callID);
-        // // if (mCallPagerAdapter.getCount() == 0) {
-        // // finish();
-        // // }
-        //
-        // } else if (newState.equals("HOLD")) {
-        // fr.changeCallState(SipCall.state.CALL_STATE_HOLD);
-        //
-        // } else if (newState.equals("UNHOLD")) {
-        // fr.changeCallState(SipCall.state.CALL_STATE_CURRENT);
-        //
-        // } else {
-        // fr.changeCallState(SipCall.state.CALL_STATE_NONE);
-        //
-        // }
+		mCallsFragment.update();
 
-        Log.w(TAG, "processCallStateChangedSignal " + newState);
+		mCurrentCallFragment.changeCallState(callID, newState);
 
-    }
-
-    @Override
-    public void incomingText(Intent msg) {
-        Toast.makeText(this, "New Call incoming", Toast.LENGTH_LONG).show();
-
-        // TODO link text message to associate call and display it at the right place
-
-    }
-
-    @Override
-    public ISipService getService() {
-        return service;
-    }
-
-    @Override
-    public void onCallSelected(SipCall call) {
-        mCurrentCallFragment = new CallFragment();
-        Bundle b = new Bundle();
-        b.putParcelable("CallInfo", call);
-        mCurrentCallFragment.setArguments(b);
-        getFragmentManager().beginTransaction().replace(R.id.ongoingcall_pane, mCurrentCallFragment).commit();
-        
-        slidingPaneLayout.openPane();
-
-    }
-
-    @Override
-    public void callContact(SipCall call) {
-        try {
-            service.placeCall(call);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Cannot call service method", e);
-        }
-
-    }
-
-    @Override
-    public void onCallAccepted(SipCall call) {
-        int callState = call.getCallStateInt();
-        if ((callState != state.CALL_STATE_RINGING) && (callState != state.CALL_STATE_NONE)) {
-            return;
-        }
-
-        try {
-            service.accept(call.getCallId());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Cannot call service method", e);
-        }
-
-    }
-
-    @Override
-    public void onCallRejected(SipCall call) {
-        try {
-            if (call.getCallStateInt() == state.CALL_STATE_RINGING) {
-                service.refuse(call.getCallId());
-                return;
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Cannot call service method", e);
-        }
-    }
-
-    @Override
-    public void onCallEnded(SipCall call) {
-        try {
-            if ((call.getCallStateInt() == state.CALL_STATE_NONE) || (call.getCallStateInt() == state.CALL_STATE_CURRENT)
-                    || (call.getCallStateInt() == state.CALL_STATE_HOLD)) {
-                service.hangUp(call.getCallId());
-                return;
-
-            } else if (call.getCallStateInt() == state.CALL_STATE_RINGING) {
-                if (call.getCallType() == state.CALL_TYPE_INCOMING) {
-                    service.refuse(call.getCallId());
-                    return;
-                } else if (call.getCallType() == state.CALL_TYPE_OUTGOING) {
-                    service.hangUp(call.getCallId());
-                    return;
-                }
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Cannot call service method", e);
-        }
-    }
-
-    @Override
-    public void onCallSuspended(SipCall call) {
-        try {
-            if (call.getCallStateInt() == state.CALL_STATE_CURRENT) {
-                service.hold(call.getCallId());
-                return;
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Cannot call service method", e);
-        }
-    }
-
-    @Override
-    public void onCallResumed(SipCall call) {
-        try {
-            if (call.getCallStateInt() == state.CALL_STATE_HOLD) {
-                service.unhold(call.getCallId());
-                return;
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Cannot call service method", e);
-        }
+		HashMap<String, SipCall> map;
+		try {
+			map = (HashMap<String, SipCall>) service.getCallList();
+			if(map.size() == 0){
+				finish();
+			}
+		} catch (RemoteException e) {
+			Log.e(TAG, e.toString());
+		}
 
 
-    }
 
-    @Override
-    public void onCalltransfered(SipCall call,String to) {
-        try {
-            if (call.getCallStateInt() == state.CALL_STATE_CURRENT) {
-                service.transfer(call.getCallId(), to);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Cannot call service method", e);
-        }
+		// if (newState.equals("INCOMING")) {
+		// fr.changeCallState(SipCall.state.CALL_STATE_INCOMING);
+		//
+		// } else if (newState.equals("RINGING")) {
+		// fr.changeCallState(SipCall.state.CALL_STATE_RINGING);
+		//
+		// } else if (newState.equals("CURRENT")) {
+		// fr.changeCallState(SipCall.state.CALL_STATE_CURRENT);
+		//
+		// } else if (newState.equals("HUNGUP")) {
+		// // mCallPagerAdapter.remove(callID);
+		// // if (mCallPagerAdapter.getCount() == 0) {
+		// // finish();
+		// // }
+		//
+		// } else if (newState.equals("BUSY")) {
+		// // mCallPagerAdapter.remove(callID);
+		// // if (mCallPagerAdapter.getCount() == 0) {
+		// // finish();
+		// // }
+		//
+		// } else if (newState.equals("FAILURE")) {
+		// // mCallPagerAdapter.remove(callID);
+		// // if (mCallPagerAdapter.getCount() == 0) {
+		// // finish();
+		// // }
+		//
+		// } else if (newState.equals("HOLD")) {
+		// fr.changeCallState(SipCall.state.CALL_STATE_HOLD);
+		//
+		// } else if (newState.equals("UNHOLD")) {
+		// fr.changeCallState(SipCall.state.CALL_STATE_CURRENT);
+		//
+		// } else {
+		// fr.changeCallState(SipCall.state.CALL_STATE_NONE);
+		//
+		// }
 
-    }
+		Log.w(TAG, "processCallStateChangedSignal " + newState);
 
-    @Override
-    public void onRecordCall(SipCall call) {
-        try {
-            if (call.getCallStateInt() == state.CALL_STATE_CURRENT) {
-                service.setRecordPath(Environment.getExternalStorageDirectory().getAbsolutePath());
-                Log.w(TAG, "Recording path" + service.getRecordPath());
-                service.setRecordingCall(call.getCallId());
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Cannot call service method", e);
-        }
+	}
 
-    }
+	@Override
+	public void incomingText(Intent msg) {
+		Toast.makeText(this, "New Call incoming", Toast.LENGTH_LONG).show();
 
-    @Override
-    public void onSendMessage(SipCall call, String msg) {
-        try {
-            if (call.getCallStateInt() == state.CALL_STATE_CURRENT) {
-            service.sendTextMessage(call.getCallId(), msg, "Me");
-            }
-            } catch (RemoteException e) {
-            Log.e(TAG, "Cannot call service method", e);
-            }
+		// TODO link text message to associate call and display it at the right place
 
-    }
+	}
+
+	@Override
+	public ISipService getService() {
+		return service;
+	}
+
+	@Override
+	public void onCallSelected(SipCall call) {
+		mCurrentCallFragment = new CallFragment();
+		Bundle b = new Bundle();
+		b.putParcelable("CallInfo", call);
+		mCurrentCallFragment.setArguments(b);
+		getFragmentManager().beginTransaction().replace(R.id.ongoingcall_pane, mCurrentCallFragment).commit();
+
+		slidingPaneLayout.curFragment = mCurrentCallFragment;
+		slidingPaneLayout.openPane();
+
+	}
+
+	@Override
+	public void callContact(SipCall call) {
+		try {
+			service.placeCall(call);
+		} catch (RemoteException e) {
+			Log.e(TAG, "Cannot call service method", e);
+		}
+
+	}
+
+	@Override
+	public void onCallAccepted(SipCall call) {
+		int callState = call.getCallStateInt();
+		if (callState != state.CALL_STATE_RINGING && callState != state.CALL_STATE_NONE) {
+			return;
+		}
+
+		try {
+			service.accept(call.getCallId());
+		} catch (RemoteException e) {
+			Log.e(TAG, "Cannot call service method", e);
+		}
+
+	}
+
+	@Override
+	public void onCallRejected(SipCall call) {
+		try {
+			if (call.getCallStateInt() == state.CALL_STATE_RINGING) {
+				service.refuse(call.getCallId());
+				return;
+			}
+		} catch (RemoteException e) {
+			Log.e(TAG, "Cannot call service method", e);
+		}
+	}
+
+	@Override
+	public void onCallEnded(SipCall call) {
+		try {
+			if (call.getCallStateInt() == state.CALL_STATE_NONE || call.getCallStateInt() == state.CALL_STATE_CURRENT
+					|| call.getCallStateInt() == state.CALL_STATE_HOLD) {
+				service.hangUp(call.getCallId());
+				return;
+
+			} else if (call.getCallStateInt() == state.CALL_STATE_RINGING) {
+				if (call.getCallType() == state.CALL_TYPE_INCOMING) {
+					service.refuse(call.getCallId());
+					return;
+				} else if (call.getCallType() == state.CALL_TYPE_OUTGOING) {
+					service.hangUp(call.getCallId());
+					return;
+				}
+			}
+		} catch (RemoteException e) {
+			Log.e(TAG, "Cannot call service method", e);
+		}
+	}
+
+	@Override
+	public void onCallSuspended(SipCall call) {
+		try {
+			if (call.getCallStateInt() == state.CALL_STATE_CURRENT) {
+				service.hold(call.getCallId());
+				return;
+			}
+		} catch (RemoteException e) {
+			Log.e(TAG, "Cannot call service method", e);
+		}
+	}
+
+	@Override
+	public void onCallResumed(SipCall call) {
+		try {
+			if (call.getCallStateInt() == state.CALL_STATE_HOLD) {
+				service.unhold(call.getCallId());
+				return;
+			}
+		} catch (RemoteException e) {
+			Log.e(TAG, "Cannot call service method", e);
+		}
+
+
+	}
+
+	@Override
+	public void onCalltransfered(SipCall call,String to) {
+		try {
+			if (call.getCallStateInt() == state.CALL_STATE_CURRENT) {
+				service.transfer(call.getCallId(), to);
+			}
+		} catch (RemoteException e) {
+			Log.e(TAG, "Cannot call service method", e);
+		}
+
+	}
+
+	@Override
+	public void onRecordCall(SipCall call) {
+		try {
+			if (call.getCallStateInt() == state.CALL_STATE_CURRENT) {
+				service.setRecordPath(Environment.getExternalStorageDirectory().getAbsolutePath());
+				Log.w(TAG, "Recording path" + service.getRecordPath());
+				service.setRecordingCall(call.getCallId());
+			}
+		} catch (RemoteException e) {
+			Log.e(TAG, "Cannot call service method", e);
+		}
+
+	}
+
+	@Override
+	public void onSendMessage(SipCall call, String msg) {
+		try {
+			if (call.getCallStateInt() == state.CALL_STATE_CURRENT) {
+				service.sendTextMessage(call.getCallId(), msg, "Me");
+			}
+		} catch (RemoteException e) {
+			Log.e(TAG, "Cannot call service method", e);
+		}
+
+	}
 
 }
diff --git a/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java b/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
index 35f0b11..fd1287f 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
@@ -61,10 +61,12 @@
 
 	static final String TAG = "CallFragment";
 
-	static final float BUBBLE_SIZE = 100;
+	static final float BUBBLE_SIZE = 75;
+	static final float ATTRACTOR_SIZE = 40;
 
 	private SipCall mCall;
 
+	private ViewGroup rootView;
 	private BubblesView view;
 	private BubbleModel model;
 	private PointF screenCenter;
@@ -175,6 +177,8 @@
 			throw new IllegalStateException("Activity must implement fragment's callbacks.");
 		}
 
+		//rootView.requestDisallowInterceptTouchEvent(true);
+
 		mCallbacks = (Callbacks) activity;
 	}
 
@@ -182,11 +186,13 @@
 	public void onDetach() {
 		super.onDetach();
 		mCallbacks = sDummyCallbacks;
+		//rootView.requestDisallowInterceptTouchEvent(false);
 	}
 
 	@Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-		ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.frag_call, container, false);
+		rootView = (ViewGroup) inflater.inflate(R.layout.frag_call, container, false);
+		//rootView.requestDisallowInterceptTouchEvent(true);
 
 		view = (BubblesView) rootView.findViewById(R.id.main_view);
 		view.setModel(model);
@@ -225,36 +231,20 @@
 
 	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);
 
-		/*	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);
-		}
-
-		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() {
+		model.addAttractor(new Attractor(new PointF(metrics.widthPixels / 2, metrics.heightPixels * .8f), ATTRACTOR_SIZE, new Attractor.Callback() {
 			@Override
-			public void onBubbleSucked(Bubble b) {
+			public boolean onBubbleSucked(Bubble b) {
 				Log.w(TAG, "Bubble sucked ! ");
 				mCallbacks.onCallEnded(mCall);
+				bubbleRemoved(b);
+				return true;
 			}
 		}, hangup_icon));
-
-		/*	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 initIncomingCallDisplay() {
@@ -264,16 +254,19 @@
 		contacts.put(mCall.getContacts().get(0), contact_bubble);
 
 		model.clearAttractors();
-		model.addAttractor(new Attractor(new PointF(3 * metrics.widthPixels / 4, metrics.heightPixels / 4), 20, new Attractor.Callback() {
+		model.addAttractor(new Attractor(new PointF(4 * metrics.widthPixels / 5, screenCenter.y), ATTRACTOR_SIZE, new Attractor.Callback() {
 			@Override
-			public void onBubbleSucked(Bubble b) {
+			public boolean onBubbleSucked(Bubble b) {
 				mCallbacks.onCallAccepted(mCall);
+				return false;
 			}
 		}, call_icon));
-		model.addAttractor(new Attractor(new PointF(metrics.widthPixels / 4, metrics.heightPixels / 4), 20, new Attractor.Callback() {
+		model.addAttractor(new Attractor(new PointF(metrics.widthPixels / 5, screenCenter.y), ATTRACTOR_SIZE, new Attractor.Callback() {
 			@Override
-			public void onBubbleSucked(Bubble b) {
+			public boolean onBubbleSucked(Bubble b) {
 				mCallbacks.onCallRejected(mCall);
+				bubbleRemoved(b);
+				return true;
 			}
 		}, hangup_icon));
 	}
@@ -284,17 +277,15 @@
 		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() {
+		model.addAttractor(new Attractor(new PointF(metrics.widthPixels / 2, metrics.heightPixels * .8f), 40, new Attractor.Callback() {
 			@Override
-			public void onBubbleSucked(Bubble b) {
+			public boolean onBubbleSucked(Bubble b) {
 				Log.w(TAG, "Bubble sucked ! ");
 				mCallbacks.onCallEnded(mCall);
+				bubbleRemoved(b);
+				return true;
 			}
 		}, hangup_icon));
-
-		/*contact_bubble.contact = mCall.getContacts().get(0);
-		model.addBubble(contact_bubble);
-		contacts.put(mCall.getContacts().get(0), contact_bubble);*/
 	}
 
 	/**
@@ -313,6 +304,7 @@
 			return contact_bubble;
 		}
 
+		// TODO off-thread image loading
 		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);
@@ -327,6 +319,17 @@
 		return contact_bubble;
 	}
 
+	/**
+	 * Should be called when a bubble is removed from the model
+	 */
+	void bubbleRemoved(Bubble b) {
+		if(b.contact == null) {
+			return;
+		}
+
+		contacts.remove(b.contact);
+	}
+
 	public void changeCallState(String callID, String newState) {
 
 		Log.w(TAG, "Changing call state of "+callID);
@@ -340,4 +343,9 @@
 		}
 	}
 
+	public boolean draggingBubble()
+	{
+		return view == null ? false : view.isDraggingBubble();
+	}
+
 }
diff --git a/src/com/savoirfairelinux/sflphone/model/Attractor.java b/src/com/savoirfairelinux/sflphone/model/Attractor.java
index 51b1850..fed2690 100644
--- a/src/com/savoirfairelinux/sflphone/model/Attractor.java
+++ b/src/com/savoirfairelinux/sflphone/model/Attractor.java
@@ -9,7 +9,14 @@
 public class Attractor {
 
 	public interface Callback {
-		public void onBubbleSucked(Bubble b);
+
+		/**
+		 * Called when a bubble is on the "active" zone of the attractor.
+		 * 
+		 * @param b The bubble that is on the attractor.
+		 * @return true if the bubble should be removed from the model, false otherwise.
+		 */
+		public boolean onBubbleSucked(Bubble b);
 	}
 
 	final PointF pos;
@@ -20,9 +27,9 @@
 
 	private final RectF bounds = new RectF();
 
-	public Attractor(PointF pos, float radius, Callback callback, Bitmap img) {
+	public Attractor(PointF pos, float size, Callback callback, Bitmap img) {
 		this.pos = pos;
-		this.radius = radius;
+		this.radius = size/2;
 		this.callback = callback;
 		this.img = img;
 	}
diff --git a/src/com/savoirfairelinux/sflphone/model/Bubble.java b/src/com/savoirfairelinux/sflphone/model/Bubble.java
index 546bb3c..a45b746 100644
--- a/src/com/savoirfairelinux/sflphone/model/Bubble.java
+++ b/src/com/savoirfairelinux/sflphone/model/Bubble.java
@@ -37,36 +37,32 @@
 		this.attractor = attractor;
 	}
 
-	public Bubble(float x, float y, float rad, Bitmap photo) {
-		internalBMP = photo;
-		pos.set(x, y);
-
-		internalBMP = Bitmap.createScaledBitmap(internalBMP, (int) rad, (int) rad, false);
+	public Bubble(float x, float y, float size, Bitmap photo) {
+		internalBMP = Bitmap.createScaledBitmap(photo, (int) size, (int) size, false);
 		int w = internalBMP.getWidth(), h = internalBMP.getHeight();
 
-		externalBMP = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+		pos.set(x, y);
+		radius = w / 2;
+		bounds = new RectF(pos.x - radius, pos.y - radius, pos.x + radius, pos.y + radius);
+		attractor = new PointF(x, y);
 
-		radius = externalBMP.getWidth() / 2;
 		Path path = new Path();
-
 		path.addCircle(radius, radius, radius, Path.Direction.CW);
 
-		bounds = new RectF(pos.x - radius, pos.y - radius, pos.x + radius, pos.y + radius);
-
-		Paint mPaintPath = new Paint(Paint.ANTI_ALIAS_FLAG);
-		mPaintPath.setStyle(Paint.Style.FILL);
-		mPaintPath.setAntiAlias(true);
+		Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+		circlePaint.setStyle(Paint.Style.FILL);
 		Bitmap circle = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
 		Canvas circle_drawer = new Canvas(circle);
-		circle_drawer.drawOval(new RectF(0, 0, w, h), mPaintPath);
+		circle_drawer.drawOval(new RectF(0, 0, w, h), circlePaint);
 
-		attractor = new PointF(x, y);
-		mPaintPath.setFilterBitmap(false);
+		externalBMP = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+		Canvas canvas = new Canvas(externalBMP);
 
-		Canvas internalCanvas = new Canvas(externalBMP);
-		internalCanvas.drawBitmap(internalBMP, 0, 0, mPaintPath);
-		mPaintPath.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
-		internalCanvas.drawBitmap(circle, 0, 0, mPaintPath);
+		circlePaint.setFilterBitmap(false);
+		canvas.drawBitmap(internalBMP, 0, 0, circlePaint);
+
+		circlePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+		canvas.drawBitmap(circle, 0, 0, circlePaint);
 	}
 
 	public Bubble(float x, float y, float rad, Context c, int resID) {
@@ -87,10 +83,7 @@
 		pos.x = x;
 		pos.y = y;
 		float rad = scale*radius*density;
-		bounds.left = pos.x - rad;
-		bounds.right = pos.x + rad;
-		bounds.top = pos.y - rad;
-		bounds.bottom = pos.y + rad;
+		bounds.set(pos.x-rad, pos.y-rad, pos.x+rad, pos.y+rad);
 	}
 
 	public float getPosX() {
diff --git a/src/com/savoirfairelinux/sflphone/model/BubbleModel.java b/src/com/savoirfairelinux/sflphone/model/BubbleModel.java
index 87d3718..5631a86 100644
--- a/src/com/savoirfairelinux/sflphone/model/BubbleModel.java
+++ b/src/com/savoirfairelinux/sflphone/model/BubbleModel.java
@@ -101,7 +101,8 @@
 				PointF attractor_pos = b.attractor;
 				float attractor_dist = (attractor_pos.x-bx)*(attractor_pos.x-bx) + (attractor_pos.y-by)*(attractor_pos.x-by);
 
-				for(Attractor t : attractors) {
+				for(int j=0; j<attr_n; j++) {
+					Attractor t = attractors.get(j);
 					float dx = t.pos.x-bx, dy = t.pos.y-by;
 					float adist = dx*dx + dy*dy;
 					if(adist < attractor_dist) {
@@ -163,9 +164,13 @@
 				b.setPos((float)(bx+dx), (float)(by+dy));
 
 				if(attractor != null && attractor_dist < attractor_dist_suck*attractor_dist_suck) {
-					attractor.callback.onBubbleSucked(b);
-					bubbles.remove(b);
-					n--;
+					b.dragged = false;
+					if(attractor.callback.onBubbleSucked(b)) {
+						bubbles.remove(b);
+						n--;
+					} else {
+						b.target_scale = 1.f;
+					}
 				}
 			}
 
diff --git a/src/com/savoirfairelinux/sflphone/model/BubblesView.java b/src/com/savoirfairelinux/sflphone/model/BubblesView.java
index 8ca439a..2ee08fd 100644
--- a/src/com/savoirfairelinux/sflphone/model/BubblesView.java
+++ b/src/com/savoirfairelinux/sflphone/model/BubblesView.java
@@ -30,6 +30,8 @@
 	private float density;

 	private float textDensity;

 

+	private boolean dragging_bubble = false;

+

 	public BubblesView(Context context, AttributeSet attrs)

 	{

 		super(context, attrs);

@@ -48,7 +50,7 @@
 

 		attractor_paint.setColor(Color.RED);

 		//attractor_paint.set

-		name_paint.setTextSize(18*textDensity);

+		name_paint.setTextSize(18 * textDensity);

 		name_paint.setColor(0xFF303030);

 		name_paint.setTextAlign(Align.CENTER);

 	}

@@ -140,53 +142,60 @@
 			final int n_bubbles = bubbles.size();

 

 			if (action == MotionEvent.ACTION_DOWN) {

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

+				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;

+						dragging_bubble = true;

 					}

 				}

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

 				long now = System.nanoTime();

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

+				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 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) {

+						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;

+						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(int i=0; i<n_bubbles; i++) {

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

 					Bubble b = bubbles.get(i);

 					if (b.dragged) {

 						b.dragged = false;

 						b.target_scale = 1.f;

 					}

 				}

+				dragging_bubble = false;

 			}

 		}

 

 		return true;

 	}

 

+	public boolean isDraggingBubble()

+	{

+		return dragging_bubble;

+	}

+

 	class BubblesThread extends Thread

 	{

 		private boolean running = false;

@@ -251,17 +260,15 @@
 				List<Bubble> bubbles = model.getBubbles();

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

 

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

+				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, n=bubbles.size(); i<n; i++) {

+				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);

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

 				}

 			}

 		}

diff --git a/src/com/savoirfairelinux/sflphone/views/CallPaneLayout.java b/src/com/savoirfairelinux/sflphone/views/CallPaneLayout.java
new file mode 100644
index 0000000..6227732
--- /dev/null
+++ b/src/com/savoirfairelinux/sflphone/views/CallPaneLayout.java
@@ -0,0 +1,33 @@
+package com.savoirfairelinux.sflphone.views;
+
+import android.content.Context;
+import android.support.v4.widget.SlidingPaneLayout;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.savoirfairelinux.sflphone.fragments.CallFragment;
+
+public class CallPaneLayout extends SlidingPaneLayout
+{
+	public CallFragment curFragment = null;
+
+	public CallPaneLayout(Context context, AttributeSet attrs)
+	{
+		super(context, attrs);
+	}
+
+	public CallPaneLayout(Context context, AttributeSet attrs, int defStyle)
+	{
+		super(context, attrs, defStyle);
+	}
+
+	@Override
+	public boolean onInterceptTouchEvent(MotionEvent event)
+	{
+		if(curFragment!=null && curFragment.draggingBubble()) {
+			return false;
+		}
+		return super.onInterceptTouchEvent(event);
+	}
+
+}