Bubbles: Honor screen density when drawing bubbles and attractors.
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);

 				}

 			}