| package com.savoirfairelinux.sflphone.model; |
| |
| 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 com.savoirfairelinux.sflphone.R; |
| import com.savoirfairelinux.sflphone.adapters.ContactPictureTask; |
| |
| 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) { |
| return 1; |
| } |
| |
| // Record - Right |
| if (relativeX > externalBMP.getWidth() * 2 / 3 && relativeY > externalBMP.getHeight() / 3) { |
| return 2; |
| } |
| |
| // Transfer - Bottom |
| if (relativeY > externalBMP.getHeight() * 2 / 3) { |
| 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; |
| } |
| } |