blob: f764b341ddd53769e2341f6f30f82626117f33fa [file] [log] [blame]
Adrien Béraud04463092013-05-06 14:17:22 +10001package com.savoirfairelinux.sflphone.model;
alisionfe9cf712013-05-03 17:26:08 -04002
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +10003import java.util.List;
4
alisionfe9cf712013-05-03 17:26:08 -04005import android.content.Context;
6import android.graphics.Canvas;
7import android.graphics.Color;
Adrien Béraud33268882013-05-18 03:41:15 +10008import android.graphics.Paint;
Adrien Béraud6bbce912013-05-24 00:48:13 +10009import android.graphics.Paint.Align;
Adrien Béraud04463092013-05-06 14:17:22 +100010import android.os.Handler;
11import android.os.Message;
alisionfe9cf712013-05-03 17:26:08 -040012import android.util.AttributeSet;
13import android.util.Log;
14import android.view.MotionEvent;
Adrien Béraud04463092013-05-06 14:17:22 +100015import android.view.SurfaceHolder;
16import android.view.SurfaceView;
alisionfe9cf712013-05-03 17:26:08 -040017import android.view.View;
Adrien Béraud04463092013-05-06 14:17:22 +100018import android.view.View.OnTouchListener;
alisionfe9cf712013-05-03 17:26:08 -040019
Adrien Béraud04463092013-05-06 14:17:22 +100020public class BubblesView extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener
21{
22 private static final String TAG = BubblesView.class.getSimpleName();
alisionfe9cf712013-05-03 17:26:08 -040023
Adrien Béraud04463092013-05-06 14:17:22 +100024 private BubblesThread thread = null;
25 private BubbleModel model;
alisionfe9cf712013-05-03 17:26:08 -040026
Adrien Béraud33268882013-05-18 03:41:15 +100027 private Paint attractor_paint = new Paint();
Adrien Béraud6bbce912013-05-24 00:48:13 +100028 private Paint name_paint = new Paint(Paint.ANTI_ALIAS_FLAG);
29
30 private float density;
31 private float textDensity;
Adrien Béraud33268882013-05-18 03:41:15 +100032
Adrien Béraudc9c424d2013-05-30 17:47:35 +100033 private boolean dragging_bubble = false;
34
Adrien Béraud04463092013-05-06 14:17:22 +100035 public BubblesView(Context context, AttributeSet attrs)
36 {
37 super(context, attrs);
alisionfe9cf712013-05-03 17:26:08 -040038
Adrien Béraud6bbce912013-05-24 00:48:13 +100039 density = getResources().getDisplayMetrics().density;
40 textDensity = getResources().getDisplayMetrics().scaledDensity;
41
Adrien Béraud04463092013-05-06 14:17:22 +100042 SurfaceHolder holder = getHolder();
43 holder.addCallback(this);
alisionfe9cf712013-05-03 17:26:08 -040044
Adrien Béraud04463092013-05-06 14:17:22 +100045 // create thread only; it's started in surfaceCreated()
46 createThread();
alisionfe9cf712013-05-03 17:26:08 -040047
Adrien Béraud04463092013-05-06 14:17:22 +100048 setOnTouchListener(this);
49 setFocusable(true);
Adrien Béraud33268882013-05-18 03:41:15 +100050
51 attractor_paint.setColor(Color.RED);
52 //attractor_paint.set
Adrien Béraudc9c424d2013-05-30 17:47:35 +100053 name_paint.setTextSize(18 * textDensity);
Adrien Béraud6bbce912013-05-24 00:48:13 +100054 name_paint.setColor(0xFF303030);
55 name_paint.setTextAlign(Align.CENTER);
Adrien Béraud04463092013-05-06 14:17:22 +100056 }
alisionfe9cf712013-05-03 17:26:08 -040057
Adrien Béraude0ef0c22013-05-18 01:56:27 +100058 private void createThread()
59 {
60 if (thread != null)
61 return;
Adrien Béraud04463092013-05-06 14:17:22 +100062 thread = new BubblesThread(getHolder(), getContext(), new Handler() {
63 @Override
64 public void handleMessage(Message m)
65 {
66 /* mStatusText.setVisibility(m.getData().getInt("viz"));
67 mStatusText.setText(m.getData().getString("text"));*/
68 }
69 });
Adrien Béraude0ef0c22013-05-18 01:56:27 +100070 if (model != null)
Adrien Béraud65ba5b12013-05-06 15:42:50 +100071 thread.setModel(model);
Adrien Béraud04463092013-05-06 14:17:22 +100072 }
alisionfe9cf712013-05-03 17:26:08 -040073
Adrien Béraud04463092013-05-06 14:17:22 +100074 public void setModel(BubbleModel model)
75 {
76 this.model = model;
77 thread.setModel(model);
78 }
alisionfe9cf712013-05-03 17:26:08 -040079
Adrien Béraud04463092013-05-06 14:17:22 +100080 /*@Override
81 public void onWindowFocusChanged(boolean hasWindowFocus) {
82 if (!hasWindowFocus) {
83 thread.pause();
84 }
85 }*/
alisionfe9cf712013-05-03 17:26:08 -040086
Adrien Béraud04463092013-05-06 14:17:22 +100087 @Override
88 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
89 {
Adrien Béraud13cde0b2013-05-30 20:27:20 +100090 Log.w(TAG, "surfaceChanged "+width+"-"+height);
Adrien Béraud04463092013-05-06 14:17:22 +100091 thread.setSurfaceSize(width, height);
92 }
alisionfe9cf712013-05-03 17:26:08 -040093
Adrien Béraud04463092013-05-06 14:17:22 +100094 /*
95 * Callback invoked when the Surface has been created and is ready to be
96 * used.
97 */
98 @Override
99 public void surfaceCreated(SurfaceHolder holder)
100 {
101 // start the thread here so that we don't busy-wait in run()
102 // waiting for the surface to be created
103 createThread();
alisionfe9cf712013-05-03 17:26:08 -0400104
Adrien Béraud04463092013-05-06 14:17:22 +1000105 Log.w(TAG, "surfaceCreated");
106 thread.setRunning(true);
107 thread.start();
108 }
alisionfe9cf712013-05-03 17:26:08 -0400109
Adrien Béraud04463092013-05-06 14:17:22 +1000110 /*
111 * Callback invoked when the Surface has been destroyed and must no longer
112 * be touched. WARNING: after this method returns, the Surface/Canvas must
113 * never be touched again!
114 */
115 @Override
116 public void surfaceDestroyed(SurfaceHolder holder)
117 {
118 // we have to tell thread to shut down & wait for it to finish, or else
119 // it might touch the Surface after we return and explode
120 Log.w(TAG, "surfaceDestroyed");
121 boolean retry = true;
122 thread.setRunning(false);
Adrien Béraud25fc4092013-05-06 15:28:39 +1000123 while (retry) {
Adrien Béraud04463092013-05-06 14:17:22 +1000124 try {
125 thread.join();
126 retry = false;
127 } catch (InterruptedException e) {
128 }
Adrien Béraud25fc4092013-05-06 15:28:39 +1000129 }
Adrien Béraud04463092013-05-06 14:17:22 +1000130 thread = null;
131 }
alisionfe9cf712013-05-03 17:26:08 -0400132
Adrien Béraud04463092013-05-06 14:17:22 +1000133 @Override
134 public boolean onTouch(View v, MotionEvent event)
135 {
136 Log.w(TAG, "onTouch " + event.getAction());
Adrien Béraud25fc4092013-05-06 15:28:39 +1000137
138 int action = event.getActionMasked();
139
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000140 synchronized (model) {
141 List<Bubble> bubbles = model.getBubbles();
142 final int n_bubbles = bubbles.size();
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000143
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000144 if (action == MotionEvent.ACTION_DOWN) {
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000145 for (int i = 0; i < n_bubbles; i++) {
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000146 Bubble b = bubbles.get(i);
147 if (b.intersects(event.getX(), event.getY())) {
148 b.dragged = true;
149 b.last_drag = System.nanoTime();
150 b.setPos(event.getX(), event.getY());
151 b.target_scale = .8f;
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000152 dragging_bubble = true;
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000153 }
154 }
155 } else if (action == MotionEvent.ACTION_MOVE) {
156 long now = System.nanoTime();
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000157 for (int i = 0; i < n_bubbles; i++) {
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000158 Bubble b = bubbles.get(i);
159 if (b.dragged) {
160 float x = event.getX(), y = event.getY();
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000161 float dt = (float) ((now - b.last_drag) / 1000000000.);
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000162 float dx = x - b.getPosX(), dy = y - b.getPosY();
163 b.last_drag = now;
164
165 b.setPos(event.getX(), event.getY());
166 /*int hn = event.getHistorySize() - 2;
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000167 Log.w(TAG, "event.getHistorySize() : " + event.getHistorySize());
168 if(hn > 0) {
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000169 float dx = x-event.getHistoricalX(hn);
170 float dy = y-event.getHistoricalY(hn);
171 float dt = event.getHistoricalEventTime(hn)/1000.f;*/
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000172 b.speed.x = dx / dt;
173 b.speed.y = dy / dt;
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000174 //Log.w(TAG, "onTouch dx:" + b.speed.x + " dy:" + b.speed.y);
175 //}
176 return true;
177 }
Adrien Béraud04463092013-05-06 14:17:22 +1000178 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000179 } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000180 for (int i = 0; i < n_bubbles; i++) {
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000181 Bubble b = bubbles.get(i);
182 if (b.dragged) {
183 b.dragged = false;
184 b.target_scale = 1.f;
185 }
Adrien Béraud25fc4092013-05-06 15:28:39 +1000186 }
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000187 dragging_bubble = false;
Adrien Béraud25fc4092013-05-06 15:28:39 +1000188 }
189 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000190
Adrien Béraud04463092013-05-06 14:17:22 +1000191 return true;
192 }
alisionfe9cf712013-05-03 17:26:08 -0400193
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000194 public boolean isDraggingBubble()
195 {
196 return dragging_bubble;
197 }
198
Adrien Béraud04463092013-05-06 14:17:22 +1000199 class BubblesThread extends Thread
200 {
201 private boolean running = false;
202 private SurfaceHolder surfaceHolder;
alisionfe9cf712013-05-03 17:26:08 -0400203
Adrien Béraud04463092013-05-06 14:17:22 +1000204 BubbleModel model = null;
alisionfe9cf712013-05-03 17:26:08 -0400205
Adrien Béraud04463092013-05-06 14:17:22 +1000206 public BubblesThread(SurfaceHolder holder, Context context, Handler handler)
207 {
208 surfaceHolder = holder;
209 }
alisionfe9cf712013-05-03 17:26:08 -0400210
Adrien Béraud04463092013-05-06 14:17:22 +1000211 public void setModel(BubbleModel model)
212 {
213 this.model = model;
214 }
alisionfe9cf712013-05-03 17:26:08 -0400215
Adrien Béraud04463092013-05-06 14:17:22 +1000216 @Override
217 public void run()
218 {
219 while (running) {
220 Canvas c = null;
221 try {
222 c = surfaceHolder.lockCanvas(null);
Adrien Béraud7ed23dc2013-05-06 16:27:24 +1000223
224 // for the case the surface is destroyed while already in the loop
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000225 if (c == null || model == null)
226 continue;
Adrien Béraud7ed23dc2013-05-06 16:27:24 +1000227
Adrien Béraud04463092013-05-06 14:17:22 +1000228 synchronized (surfaceHolder) {
Adrien Béraud25fc4092013-05-06 15:28:39 +1000229 //Log.w(TAG, "Thread doDraw");
230 model.update();
Adrien Béraud04463092013-05-06 14:17:22 +1000231 doDraw(c);
232 }
233 } finally {
Adrien Béraud04463092013-05-06 14:17:22 +1000234 if (c != null)
235 surfaceHolder.unlockCanvasAndPost(c);
236 }
237 }
238 }
239
240 public void setRunning(boolean b)
241 {
242 running = b;
243 }
244
245 public void setSurfaceSize(int width, int height)
246 {
247 synchronized (surfaceHolder) {
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000248 if (model != null) {
Adrien Béraud25fc4092013-05-06 15:28:39 +1000249 model.width = width;
250 model.height = height;
251 }
Adrien Béraud04463092013-05-06 14:17:22 +1000252 }
253 }
254
Adrien Béraud04463092013-05-06 14:17:22 +1000255 private void doDraw(Canvas canvas)
256 {
257 canvas.drawColor(Color.WHITE);
258
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000259 synchronized (model) {
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000260 List<Bubble> bubbles = model.getBubbles();
261 List<Attractor> attractors = model.getAttractors();
262
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000263 for (int i = 0, n = attractors.size(); i < n; i++) {
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000264 Attractor a = attractors.get(i);
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000265 canvas.drawBitmap(a.getBitmap(), null, a.getBounds(), null);
Adrien Béraud33268882013-05-18 03:41:15 +1000266 }
267
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000268 for (int i = 0, n = bubbles.size(); i < n; i++) {
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000269 Bubble b = bubbles.get(i);
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000270 canvas.drawBitmap(b.getBitmap(), null, b.getBounds(), null);
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000271 canvas.drawText(b.contact.getmDisplayName(), b.getPosX(), b.getPosY() - 50 * density, name_paint);
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000272 }
Adrien Béraud25fc4092013-05-06 15:28:39 +1000273 }
Adrien Béraud04463092013-05-06 14:17:22 +1000274 }
275 }
276
alisionfe9cf712013-05-03 17:26:08 -0400277}