* #31001: com.savoirfaire -> org.sflphone
diff --git a/src/org/sflphone/model/Bubble.java b/src/org/sflphone/model/Bubble.java
new file mode 100644
index 0000000..ecbc108
--- /dev/null
+++ b/src/org/sflphone/model/Bubble.java
@@ -0,0 +1,307 @@
+package org.sflphone.model;
+
+import org.sflphone.adapters.ContactPictureTask;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.RectF;
+import android.util.Log;
+
+import org.sflphone.R;
+
+public class Bubble {
+
+ // A Bitmap object that is going to be passed to the BitmapShader
+ private Bitmap internalBMP, externalBMP;
+
+ public SipCall associated_call;
+ private PointF pos = new PointF();
+ private RectF bounds;
+ public float target_scale = 1.f;
+ private 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;
+
+ 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;
+ private float expanded_radius;
+
+ public void setAttractor(PointF attractor) {
+ this.attractor = attractor;
+ }
+
+ public Bubble(Context context, SipCall call, float x, float y, float size) {
+
+ Bitmap photo = null;
+ if (call.getContact().getPhoto_id() > 0) {
+ photo = ContactPictureTask.loadContactPhoto(context.getContentResolver(), call.getContact().getId());
+ } else {
+ photo = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_contact_picture);
+ }
+
+ saved_photo = photo;
+ internalBMP = Bitmap.createScaledBitmap(photo, (int) size, (int) size, false);
+ internalBMP.setHasAlpha(true);
+ associated_call = call;
+ pos.set(x, y);
+ radius = internalBMP.getWidth() / 2;
+ expanded_radius = (float) (size * 1.5);
+ bounds = new RectF(pos.x - radius, pos.y - radius, pos.x + radius, pos.y + radius);
+ attractor = new PointF(x, y);
+
+ Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ circlePaint.setStyle(Paint.Style.FILL);
+ Bitmap circle = Bitmap.createBitmap(internalBMP.getWidth(), internalBMP.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas circle_drawer = new Canvas(circle);
+ circle_drawer.drawOval(new RectF(0, 0, internalBMP.getWidth(), internalBMP.getHeight()), circlePaint);
+
+ externalBMP = Bitmap.createBitmap(internalBMP.getWidth(), internalBMP.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(externalBMP);
+
+ circlePaint.setFilterBitmap(false);
+ canvas.drawBitmap(internalBMP, 0, 0, circlePaint);
+
+ circlePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+ canvas.drawBitmap(circle, 0, 0, circlePaint);
+ }
+
+ public Bitmap getBitmap() {
+ return externalBMP;
+ }
+
+ public RectF getBounds() {
+ return bounds;
+ }
+
+ public void set(float x, float y, float s) {
+ scale = s;
+ pos.x = x;
+ pos.y = y;
+ float rad = scale * getRadius() * density;
+ bounds.set(pos.x - rad, pos.y - rad, pos.x + rad, pos.y + rad);
+ }
+
+ public float getPosX() {
+ return pos.x;
+ }
+
+ public float getPosY() {
+ return pos.y;
+ }
+
+ public void setPos(float x, float y) {
+ set(x, y, scale);
+ }
+
+ public PointF getPos() {
+ return pos;
+ }
+
+ public float getScale() {
+ return scale;
+ }
+
+ public void setScale(float s) {
+ set(pos.x, pos.y, s);
+ }
+
+ public float getRadius() {
+ return expanded ? expanded_radius : radius;
+ }
+
+ /**
+ * Point intersection test.
+ */
+ boolean intersects(float x, float y) {
+ float dx = x - pos.x;
+ float dy = y - pos.y;
+
+ return dx * dx + dy * dy < getRadius() * density * getRadius() * density;
+ }
+
+ /**
+ * Other circle intersection test.
+ */
+ boolean intersects(float x, float y, float radius) {
+ float dx = x - pos.x, dy = y - pos.y;
+ float tot_radius = getRadius() + radius;
+ return dx * dx + dy * dy < tot_radius * tot_radius;
+ }
+
+ public void setDensity(float density) {
+ this.density = density;
+ }
+
+ public void expand() {
+
+ expanded = true;
+ internalBMP = Bitmap.createScaledBitmap(saved_photo, (int) (2 * radius), (int) (2 * radius), false);
+
+ bounds = new RectF(pos.x - getRadius(), pos.y - getRadius(), pos.x + getRadius(), pos.y + getRadius());
+
+ Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ circlePaint.setAntiAlias(true);
+ circlePaint.setDither(true);
+ circlePaint.setStyle(Paint.Style.FILL);
+ circlePaint.setColor(Color.RED);
+
+ Bitmap circle = Bitmap.createBitmap(internalBMP.getWidth(), internalBMP.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas circle_drawer = new Canvas(circle);
+ circle_drawer.drawOval(new RectF(0, 0, internalBMP.getWidth(), internalBMP.getHeight()), circlePaint);
+
+ Canvas canvas = new Canvas(internalBMP);
+ circlePaint.setFilterBitmap(false);
+ canvas.drawBitmap(internalBMP, 0, 0, circlePaint);
+
+ circlePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+ canvas.drawBitmap(circle, 0, 0, circlePaint);
+ circle_drawer.drawOval(new RectF(0, 0, internalBMP.getWidth(), internalBMP.getHeight()), circlePaint);
+
+ externalBMP = Bitmap.createBitmap((int) (getRadius() * 2), (int) (getRadius() * 2), Bitmap.Config.ARGB_8888);
+ Canvas canvasf = new Canvas(externalBMP);
+
+ Paint mPaintPath = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaintPath.setStyle(Paint.Style.FILL);
+ mPaintPath.setColor(0xAA000000);
+
+ Paint fatality = new Paint(Paint.ANTI_ALIAS_FLAG);
+ fatality.setAntiAlias(true);
+ fatality.setDither(true);
+ 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());
+ for (int i = 0; i < internalBMP.getHeight() * internalBMP.getWidth(); i++) {
+ // Log.i("Bubble", "allpixels[i]:"+allpixels[i]);
+ if (allpixels[i] == Color.BLACK) {
+ allpixels[i] = 0xAA000000;
+ }
+ }
+ internalBMP.setPixels(allpixels, 0, internalBMP.getWidth(), 0, 0, internalBMP.getWidth(), internalBMP.getHeight());
+
+ canvasf.drawBitmap(internalBMP, (float) (getRadius() - radius), (float) (getRadius() - radius), fatality);
+
+ }
+
+ public void retract() {
+ expanded = false;
+ internalBMP = Bitmap.createScaledBitmap(saved_photo, (int) (2 * radius), (int) (2 * radius), false);
+
+ bounds = new RectF(pos.x - getRadius(), pos.y - getRadius(), pos.x + getRadius(), pos.y + getRadius());
+
+ Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ circlePaint.setAntiAlias(true);
+ circlePaint.setDither(true);
+ circlePaint.setStyle(Paint.Style.FILL);
+
+ Bitmap circle = Bitmap.createBitmap(internalBMP.getWidth(), internalBMP.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas circle_drawer = new Canvas(circle);
+ circle_drawer.drawOval(new RectF(0, 0, internalBMP.getWidth(), internalBMP.getHeight()), circlePaint);
+
+ externalBMP = Bitmap.createBitmap(internalBMP.getWidth(), internalBMP.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(externalBMP);
+
+ circlePaint.setFilterBitmap(false);
+ canvas.drawBitmap(internalBMP, 0, 0, circlePaint);
+
+ circlePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+ canvas.drawBitmap(circle, 0, 0, circlePaint);
+
+ }
+
+ /**
+ * Compare bubbles based on call ID
+ */
+ @Override
+ public boolean equals(Object c) {
+ if (c instanceof Bubble && ((Bubble) c).associated_call.getCallId().contentEquals(associated_call.getCallId())) {
+ return true;
+ }
+ return false;
+
+ }
+
+ /**
+ * When the bubble is expanded we need to check on wich action button the user tap
+ *
+ * @param x
+ * @param y
+ * @return
+ */
+ public int getAction(float x, float y) {
+ float relativeX = x - pos.x + externalBMP.getWidth() / 2;
+ float relativeY = y - pos.y + externalBMP.getHeight() / 2;
+
+ // Log.i("Bubble", "relativeX:" + relativeX);
+ // Log.i("Bubble", "relativeY:" + relativeY);
+ //
+ // Log.i("Bubble", "pos.x:" + pos.x);
+ // Log.i("Bubble", "pos.y:" + pos.y);
+ //
+ // Log.i("Bubble", "externalBMP.getWidth():" + externalBMP.getWidth());
+ // Log.i("Bubble", "externalBMP.getHeight():" + externalBMP.getHeight());
+
+ // Hold - Left
+ if (relativeX < externalBMP.getWidth() / 3 && relativeY > externalBMP.getHeight() / 3) {
+ Log.i("Bubble", "Holding");
+ return 1;
+ }
+
+ // Record - Right
+ if (relativeX > externalBMP.getWidth() * 2 / 3 && relativeY > externalBMP.getHeight() / 3) {
+ Log.i("Bubble", "Record");
+ return 2;
+ }
+
+ // Transfer - Bottom
+ if (relativeY > externalBMP.getHeight() * 2 / 3) {
+ Log.i("Bubble", "Transfer");
+ return 3;
+ }
+ 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
+ *
+ * @return
+ */
+ public float getRetractedRadius() {
+ return radius;
+ }
+
+ public int getHoldStatus() {
+ if (associated_call.isOnHold())
+ return R.string.action_call_unhold;
+ else
+ return R.string.action_call_hold;
+ }
+
+ public int getRecordStatus() {
+ if (associated_call.isRecording())
+ return R.string.action_call_stop_record;
+ else
+ return R.string.action_call_record;
+ }
+}