* #30525: removed hangup and transfer icon
* replaced with hangup fling
diff --git a/src/com/savoirfairelinux/sflphone/client/CallActivity.java b/src/com/savoirfairelinux/sflphone/client/CallActivity.java
index 1306e73..1effb7b 100644
--- a/src/com/savoirfairelinux/sflphone/client/CallActivity.java
+++ b/src/com/savoirfairelinux/sflphone/client/CallActivity.java
@@ -41,6 +41,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.graphics.PixelFormat;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -50,6 +51,7 @@
 import android.support.v4.widget.SlidingPaneLayout;
 import android.util.Log;
 import android.view.View;
+import android.view.Window;
 import android.widget.Toast;
 
 import com.savoirfairelinux.sflphone.R;
@@ -74,9 +76,9 @@
 
     CallPaneLayout slidingPaneLayout;
 
-//    CallListFragment mCallsFragment;
+    // CallListFragment mCallsFragment;
     CallFragment mCurrentCallFragment;
-    private boolean fragIsChanging;
+    // private boolean fragIsChanging;
 
     /* result code sent in case of call failure */
     public static int RESULT_FAILURE = -10;
@@ -88,9 +90,9 @@
 
         receiver = new CallReceiver(this);
 
-//        mCallsFragment = new CallListFragment();
+        // mCallsFragment = new CallListFragment();
 
-//        getFragmentManager().beginTransaction().replace(R.id.calllist_pane, mCallsFragment).commit();
+        // getFragmentManager().beginTransaction().replace(R.id.calllist_pane, mCallsFragment).commit();
 
         slidingPaneLayout = (CallPaneLayout) findViewById(R.id.slidingpanelayout);
 
@@ -116,20 +118,20 @@
             @Override
             public void onPanelClosed(View view) {
 
-//                switch (view.getId()) {
-//                case R.id.ongoingcall_pane:
-//                    if (fragIsChanging) {
-//                        getFragmentManager().beginTransaction().replace(R.id.ongoingcall_pane, mCurrentCallFragment).commit();
-//
-//                        fragIsChanging = false;
-//                    } else if (mCurrentCallFragment != null && mCurrentCallFragment.getBubbleView() != null) {
-//                        mCurrentCallFragment.getBubbleView().restartDrawing();
-//                    }
-//
-//                    break;
-//                default:
-//                    break;
-//                }
+                // switch (view.getId()) {
+                // case R.id.ongoingcall_pane:
+                // if (fragIsChanging) {
+                // getFragmentManager().beginTransaction().replace(R.id.ongoingcall_pane, mCurrentCallFragment).commit();
+                //
+                // fragIsChanging = false;
+                // } else if (mCurrentCallFragment != null && mCurrentCallFragment.getBubbleView() != null) {
+                // mCurrentCallFragment.getBubbleView().restartDrawing();
+                // }
+                //
+                // break;
+                // default:
+                // break;
+                // }
             }
         });
 
@@ -154,13 +156,20 @@
         super.onResume();
     }
 
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        Window window = getWindow();
+        window.setFormat(PixelFormat.RGBA_8888);
+    }
+
     private Handler mHandler = new Handler();
     private Runnable mUpdateTimeTask = new Runnable() {
         @Override
         public void run() {
-            if(mCurrentCallFragment != null)
+            if (mCurrentCallFragment != null)
                 mCurrentCallFragment.updateTime();
-//            mCallsFragment.update();
+            // mCallsFragment.update();
 
             mHandler.postAtTime(this, SystemClock.uptimeMillis() + 1000);
         }
@@ -234,9 +243,9 @@
 
             }
 
-//            slidingPaneLayout.setCurFragment(mCurrentCallFragment);
+            // slidingPaneLayout.setCurFragment(mCurrentCallFragment);
             getIntent().getExtras();
-//            mCallsFragment.update();
+            // mCallsFragment.update();
             getFragmentManager().beginTransaction().replace(R.id.ongoingcall_pane, mCurrentCallFragment).commit();
 
         }
@@ -250,7 +259,7 @@
     public void incomingCall(Intent call) {
         Toast.makeText(this, "New Call incoming", Toast.LENGTH_LONG).show();
 
-//        mCallsFragment.update();
+        // mCallsFragment.update();
 
     }
 
@@ -262,7 +271,8 @@
 
     }
 
-    @SuppressWarnings("unchecked") // No proper solution with HashMap runtime cast
+    @SuppressWarnings("unchecked")
+    // No proper solution with HashMap runtime cast
     public void processCallStateChangedSignal(String callID, String newState) {
         /*
          * Bundle bundle = intent.getBundleExtra("com.savoirfairelinux.sflphone.service.newstate"); String callID = bundle.getString("CallID"); String
@@ -270,7 +280,7 @@
          */
         // CallFragment fr = mCurrentCallFragment;
 
-//        mCallsFragment.update();
+        // mCallsFragment.update();
 
         if (mCurrentCallFragment != null)
             mCurrentCallFragment.changeCallState(callID, newState);
@@ -284,8 +294,8 @@
             }
 
             if (callMap.size() > 0) {
-//                ArrayList<SipCall> calls = new ArrayList<SipCall>(callMap.values());
-//                HashMap<String, String> details = (HashMap<String, String>) service.getCallDetails(calls.get(0).getCallId());
+                // ArrayList<SipCall> calls = new ArrayList<SipCall>(callMap.values());
+                // HashMap<String, String> details = (HashMap<String, String>) service.getCallDetails(calls.get(0).getCallId());
 
             }
         } catch (RemoteException e) {
@@ -328,9 +338,9 @@
         // onCallResumed(calls.get(0));
         // }
 
-//        slidingPaneLayout.setCurFragment(mCurrentCallFragment);
+        // slidingPaneLayout.setCurFragment(mCurrentCallFragment);
         slidingPaneLayout.closePane();
-        fragIsChanging = true;
+        // fragIsChanging = true;
 
     }
 
@@ -373,6 +383,18 @@
 
     @Override
     public void onCallEnded(SipCall call) {
+
+        if (call.getContact().isUser()) {
+            Conference displayed = mCurrentCallFragment.getConference();
+            try {
+            if (displayed.hasMultipleParticipants())
+                service.hangUpConference(displayed.getId());
+            else
+                service.hangUp(displayed.getParticipants().get(0).getCallId());
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
         try {
             if (call.getCallStateInt() == state.CALL_STATE_NONE || call.getCallStateInt() == state.CALL_STATE_CURRENT
                     || call.getCallStateInt() == state.CALL_STATE_HOLD) {
@@ -466,18 +488,18 @@
 
     @Override
     public void confCreated(Intent intent) {
-//        mCallsFragment.update();
+        // mCallsFragment.update();
 
     }
 
     @Override
     public void confRemoved(Intent intent) {
-//        mCallsFragment.update();
+        // mCallsFragment.update();
     }
 
     @Override
     public void confChanged(Intent intent) {
-//        mCallsFragment.update();
+        // mCallsFragment.update();
     }
 
     @Override
@@ -487,7 +509,7 @@
 
     @Override
     public void recordingChanged(Intent intent) {
-//        mCallsFragment.update();
+        // mCallsFragment.update();
     }
 
     @Override
diff --git a/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java b/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
index bdbf740..919e1da 100644
--- a/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
+++ b/src/com/savoirfairelinux/sflphone/fragments/CallFragment.java
@@ -249,14 +249,14 @@
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                 }
-                Toast.makeText(getActivity(), "Transfer complete", Toast.LENGTH_LONG).show();
+//                Toast.makeText(getActivity(), "Transfer complete", Toast.LENGTH_LONG).show();
                 break;
 
             case TransferDFragment.RESULT_TRANSFER_NUMBER:
                 String to = data.getStringExtra("to_number");
                 transfer = data.getParcelableExtra("transfer");
                 try {
-                    Toast.makeText(getActivity(), "Transferring " + transfer.getContact().getmDisplayName() + " to " + to, Toast.LENGTH_SHORT).show();
+//                    Toast.makeText(getActivity(), "Transferring " + transfer.getContact().getmDisplayName() + " to " + to, Toast.LENGTH_SHORT).show();
                     mCallbacks.getService().transfer(transfer.getCallId(), to);
                     mCallbacks.getService().hangUp(transfer.getCallId());
                 } catch (RemoteException e) {
@@ -315,40 +315,40 @@
         }
 
         model.clearAttractors();
-        model.addAttractor(new Attractor(new PointF(model.width * .2f, model.height * 0.9f), ATTRACTOR_SIZE, new Attractor.Callback() {
-            @Override
-            public boolean onBubbleSucked(Bubble b) {
-                Log.w(TAG, "Bubble sucked ! ");
+//        model.addAttractor(new Attractor(new PointF(model.width * .2f, model.height * 0.9f), ATTRACTOR_SIZE, new Attractor.Callback() {
+//            @Override
+//            public boolean onBubbleSucked(Bubble b) {
+//                Log.w(TAG, "Bubble sucked ! ");
+//
+//                if (b.associated_call.getContact().isUser()) {
+//
+//                    try {
+//                        if (conf.hasMultipleParticipants())
+//                            mCallbacks.getService().hangUpConference(conf.getId());
+//                        else
+//                            mCallbacks.onCallEnded(conf.getParticipants().get(0));
+//
+//                        model.clearAttractors();
+//                    } catch (RemoteException e) {
+//                        e.printStackTrace();
+//                    }
+//
+//                } else {
+//                    mCallbacks.onCallEnded(b.associated_call);
+//                }
+//                bubbleRemoved(b);
+//                return true;
+//            }
+//        }, hangup_icon));
 
-                if (b.associated_call.getContact().isUser()) {
-
-                    try {
-                        if (conf.hasMultipleParticipants())
-                            mCallbacks.getService().hangUpConference(conf.getId());
-                        else
-                            mCallbacks.onCallEnded(conf.getParticipants().get(0));
-
-                        model.clearAttractors();
-                    } catch (RemoteException e) {
-                        e.printStackTrace();
-                    }
-
-                } else {
-                    mCallbacks.onCallEnded(b.associated_call);
-                }
-                bubbleRemoved(b);
-                return true;
-            }
-        }, hangup_icon));
-
-        model.addAttractor(new Attractor(new PointF(model.width * .8f, model.height * 0.9f), ATTRACTOR_SIZE, new Attractor.Callback() {
-            @Override
-            public boolean onBubbleSucked(Bubble b) {
-                Log.w(TAG, "Bubble sucked ! ");
-                makeTransfer(b);
-                return true;
-            }
-        }, transfer_icon));
+//        model.addAttractor(new Attractor(new PointF(model.width * .8f, model.height * 0.9f), ATTRACTOR_SIZE, new Attractor.Callback() {
+//            @Override
+//            public boolean onBubbleSucked(Bubble b) {
+//                Log.w(TAG, "Bubble sucked ! ");
+//                makeTransfer(b);
+//                return true;
+//            }
+//        }, transfer_icon));
 
         // if (conf.hasMultipleParticipants()) {
         // model.addAttractor(new Attractor(new PointF(model.width / 1.1f, model.height * .9f), ATTRACTOR_SIZE, new Attractor.Callback() {
@@ -422,15 +422,15 @@
 
         model.clearAttractors();
 
-        model.addAttractor(new Attractor(new PointF(model.width / 2f, model.height * .9f), 40, new Attractor.Callback() {
-            @Override
-            public boolean onBubbleSucked(Bubble b) {
-                Log.w(TAG, "Bubble sucked ! ");
-                mCallbacks.onCallEnded(conf.getParticipants().get(0));
-                bubbleRemoved(b);
-                return true;
-            }
-        }, hangup_icon));
+//        model.addAttractor(new Attractor(new PointF(model.width / 2f, model.height * .9f), 40, new Attractor.Callback() {
+//            @Override
+//            public boolean onBubbleSucked(Bubble b) {
+//                Log.w(TAG, "Bubble sucked ! ");
+//                mCallbacks.onCallEnded(conf.getParticipants().get(0));
+//                bubbleRemoved(b);
+//                return true;
+//            }
+//        }, hangup_icon));
     }
 
     /**
@@ -596,4 +596,8 @@
         // Sensor.TYPE_PROXIMITY
 
     }
+
+    public Conference getConference() {
+        return conf;
+    }
 }
diff --git a/src/com/savoirfairelinux/sflphone/model/Bubble.java b/src/com/savoirfairelinux/sflphone/model/Bubble.java
index f71a385..843fe50 100644
--- a/src/com/savoirfairelinux/sflphone/model/Bubble.java
+++ b/src/com/savoirfairelinux/sflphone/model/Bubble.java
@@ -32,6 +32,8 @@
     public PointF attractor = null;
 
     public boolean dragged = false;
+    
+    public boolean markedToDie = false;
     public long last_drag;
     public boolean expanded; // determine if we draw the buttons around the bubble
     private Bitmap saved_photo;
@@ -181,7 +183,7 @@
         fatality.setStyle(Paint.Style.FILL);
 
         canvasf.drawOval(new RectF(0, 0, getRadius() * 2, getRadius() * 2), mPaintPath); // background with buttons
-        
+
         int[] allpixels = new int[internalBMP.getHeight() * internalBMP.getWidth()];
 
         internalBMP.getPixels(allpixels, 0, internalBMP.getWidth(), 0, 0, internalBMP.getWidth(), internalBMP.getHeight());
@@ -192,7 +194,7 @@
             }
         }
         internalBMP.setPixels(allpixels, 0, internalBMP.getWidth(), 0, 0, internalBMP.getWidth(), internalBMP.getHeight());
-        
+
         canvasf.drawBitmap(internalBMP, (float) (getRadius() - radius), (float) (getRadius() - radius), fatality);
 
     }
@@ -272,6 +274,10 @@
         return 0;
     }
 
+    public boolean isOnBorder(float w, float h) {
+        return (bounds.left < 0 || bounds.right > w || bounds.top < 0 || bounds.bottom > h);
+    }
+
     /**
      * Always return the normal radius of the bubble
      * 
diff --git a/src/com/savoirfairelinux/sflphone/model/BubbleModel.java b/src/com/savoirfairelinux/sflphone/model/BubbleModel.java
index b02b84f..8c68499 100644
--- a/src/com/savoirfairelinux/sflphone/model/BubbleModel.java
+++ b/src/com/savoirfairelinux/sflphone/model/BubbleModel.java
@@ -94,7 +94,10 @@
 		// to avoid garbage collection glitches caused by iterator objects.
 		for(int i=0, n=bubbles.size(); i<n; i++) {
 			Bubble b = bubbles.get(i);
-			//Log.w(TAG, "update b");
+			
+			if(b.markedToDie){
+			    continue;
+			}
 
 			if(!b.dragged) {
 				float bx=b.getPosX(), by=b.getPosY();
diff --git a/src/com/savoirfairelinux/sflphone/model/BubblesView.java b/src/com/savoirfairelinux/sflphone/model/BubblesView.java
index 845188e..9f61622 100644
--- a/src/com/savoirfairelinux/sflphone/model/BubblesView.java
+++ b/src/com/savoirfairelinux/sflphone/model/BubblesView.java
@@ -37,8 +37,11 @@
 import android.content.Context;

 import android.graphics.Canvas;

 import android.graphics.Color;

+import android.graphics.LinearGradient;

 import android.graphics.Paint;

 import android.graphics.Paint.Align;

+import android.graphics.RectF;

+import android.graphics.Shader.TileMode;

 import android.os.Handler;

 import android.os.Message;

 import android.util.AttributeSet;

@@ -52,6 +55,7 @@
 import android.view.View.OnTouchListener;

 import android.widget.Toast;

 

+import com.savoirfairelinux.sflphone.R;

 import com.savoirfairelinux.sflphone.client.CallActivity;

 import com.savoirfairelinux.sflphone.fragments.CallFragment;

 

@@ -253,11 +257,51 @@
          * @param canvas

          */

         private void doDraw(Canvas canvas) {

-            canvas.drawColor(Color.WHITE);

 

             synchronized (model) {

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

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

+

+                Paint tryMe = new Paint();

+

+                canvas.drawColor(Color.WHITE);

+

+                if (dragging_bubble) {

+                    // Draw red gradient around to hang up call

+                    // canvas.drawColor(Color.RED);

+

+                    LinearGradient grTop = new LinearGradient(0, 0, 0, 40, Color.RED, Color.WHITE, TileMode.CLAMP);

+                    Paint p = new Paint();

+                    p.setDither(true);

+                    p.setShader(grTop);

+                    canvas.drawRect(new RectF(0, 0, model.width, 40), p);

+

+                    LinearGradient grBottom = new LinearGradient(0, model.height, 0, model.height - 40, Color.RED, Color.WHITE, TileMode.CLAMP);

+                    p.setDither(true);

+                    p.setShader(grBottom);

+                    canvas.drawRect(new RectF(0, model.height - 40, model.width, model.height), p);

+

+                    LinearGradient grLeft = new LinearGradient(0, 0, 40, 0, Color.RED, Color.WHITE, TileMode.CLAMP);

+                    p.setDither(true);

+                    p.setShader(grLeft);

+                    canvas.drawRect(new RectF(0, 0, 40, model.height), p);

+

+                    LinearGradient grRight = new LinearGradient(model.width, 0, model.width - 40, 0, Color.RED, Color.WHITE, TileMode.CLAMP);

+                    p.setDither(true);

+                    p.setShader(grRight);

+                    canvas.drawRect(new RectF(model.width - 40, 0, model.width, model.height), p);

+

+                    // tryMe.setColor(getResources().getColor(R.color.lighter_gray));

+                    // tryMe.setStyle(Paint.Style.FILL);

+                    // tryMe.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));

+                    // canvas.drawArc(new RectF(15, 30, model.width - 15, model.height - 30), 0, 360, false, tryMe);

+                }

+

+                tryMe.setStyle(Paint.Style.STROKE);

+                tryMe.setColor(getResources().getColor(R.color.darker_gray));

+                tryMe.setXfermode(null);

+                canvas.drawCircle(model.width / 2, model.height / 2, model.width / 2 - getResources().getDimension(R.dimen.bubble_size), tryMe);

+

                 try {

 

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

@@ -267,20 +311,21 @@
 

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

                         Bubble b = bubbles.get(i);

-                        if(b.expanded){

+                        if (b.expanded) {

                             continue;

                         }

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

-                        canvas.drawText(b.associated_call.getContact().getmDisplayName(), b.getPosX(),

-                                (float) (b.getPosY() - b.getRetractedRadius() * 1.2 * density), getNamePaint(b));

+                        canvas.drawText(b.associated_call.getContact().getmDisplayName(), b.getPosX(), (float) (b.getPosY() - b.getRetractedRadius()

+                                * 1.2 * density), getNamePaint(b));

                     }

+

                     Bubble first_plan = getExpandedBubble();

                     if (first_plan != null) {

                         canvas.drawBitmap(first_plan.getBitmap(), null, first_plan.getBounds(), null);

-                        

+

                         canvas.drawText(first_plan.associated_call.getContact().getmDisplayName(), first_plan.getPosX(),

                                 (float) (first_plan.getPosY() - first_plan.getRetractedRadius() * 1.2 * density), getNamePaint(first_plan));

-                        

+

                         canvas.drawText("Transfer", first_plan.getPosX(), (float) (first_plan.getPosY() + first_plan.getRetractedRadius() * 1.5

                                 * density), getNamePaint(first_plan));

 

@@ -330,6 +375,10 @@
                 if (b.dragged) {

                     b.dragged = false;

                     b.target_scale = 1.f;

+                    if (b.isOnBorder(model.width, model.height)){

+                        b.markedToDie = true;

+                        ((CallActivity) callback.getActivity()).onCallEnded(b.associated_call);

+                    }

                 }

             }

             dragging_bubble = false;