blob: 82b5ad23cef4e5cefb98111e6ca444d614ac4389 [file] [log] [blame]
Adrien Béraud04463092013-05-06 14:17:22 +10001package com.savoirfairelinux.sflphone.model;
alisionfe9cf712013-05-03 17:26:08 -04002
3import android.content.Context;
4import android.graphics.Canvas;
5import android.graphics.Color;
Adrien Béraud04463092013-05-06 14:17:22 +10006import android.os.Handler;
7import android.os.Message;
alisionfe9cf712013-05-03 17:26:08 -04008import android.util.AttributeSet;
9import android.util.Log;
10import android.view.MotionEvent;
Adrien Béraud04463092013-05-06 14:17:22 +100011import android.view.SurfaceHolder;
12import android.view.SurfaceView;
alisionfe9cf712013-05-03 17:26:08 -040013import android.view.View;
Adrien Béraud04463092013-05-06 14:17:22 +100014import android.view.View.OnTouchListener;
alisionfe9cf712013-05-03 17:26:08 -040015
Adrien Béraud04463092013-05-06 14:17:22 +100016public class BubblesView extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener
17{
18 private static final String TAG = BubblesView.class.getSimpleName();
alisionfe9cf712013-05-03 17:26:08 -040019
Adrien Béraud04463092013-05-06 14:17:22 +100020 private BubblesThread thread = null;
21 private BubbleModel model;
alisionfe9cf712013-05-03 17:26:08 -040022
Adrien Béraud04463092013-05-06 14:17:22 +100023 public BubblesView(Context context, AttributeSet attrs)
24 {
25 super(context, attrs);
alisionfe9cf712013-05-03 17:26:08 -040026
Adrien Béraud04463092013-05-06 14:17:22 +100027 SurfaceHolder holder = getHolder();
28 holder.addCallback(this);
alisionfe9cf712013-05-03 17:26:08 -040029
Adrien Béraud04463092013-05-06 14:17:22 +100030 // create thread only; it's started in surfaceCreated()
31 createThread();
alisionfe9cf712013-05-03 17:26:08 -040032
Adrien Béraud04463092013-05-06 14:17:22 +100033 setOnTouchListener(this);
34 setFocusable(true);
35 }
alisionfe9cf712013-05-03 17:26:08 -040036
Adrien Béraude0ef0c22013-05-18 01:56:27 +100037 private void createThread()
38 {
39 if (thread != null)
40 return;
Adrien Béraud04463092013-05-06 14:17:22 +100041 thread = new BubblesThread(getHolder(), getContext(), new Handler() {
42 @Override
43 public void handleMessage(Message m)
44 {
45 /* mStatusText.setVisibility(m.getData().getInt("viz"));
46 mStatusText.setText(m.getData().getString("text"));*/
47 }
48 });
Adrien Béraude0ef0c22013-05-18 01:56:27 +100049 if (model != null)
Adrien Béraud65ba5b12013-05-06 15:42:50 +100050 thread.setModel(model);
Adrien Béraud04463092013-05-06 14:17:22 +100051 }
alisionfe9cf712013-05-03 17:26:08 -040052
Adrien Béraud04463092013-05-06 14:17:22 +100053 public void setModel(BubbleModel model)
54 {
55 this.model = model;
56 thread.setModel(model);
57 }
alisionfe9cf712013-05-03 17:26:08 -040058
Adrien Béraud04463092013-05-06 14:17:22 +100059 /*@Override
60 public void onWindowFocusChanged(boolean hasWindowFocus) {
61 if (!hasWindowFocus) {
62 thread.pause();
63 }
64 }*/
alisionfe9cf712013-05-03 17:26:08 -040065
Adrien Béraud04463092013-05-06 14:17:22 +100066 @Override
67 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
68 {
69 Log.w(TAG, "surfaceChanged");
70 thread.setSurfaceSize(width, height);
71 }
alisionfe9cf712013-05-03 17:26:08 -040072
Adrien Béraud04463092013-05-06 14:17:22 +100073 /*
74 * Callback invoked when the Surface has been created and is ready to be
75 * used.
76 */
77 @Override
78 public void surfaceCreated(SurfaceHolder holder)
79 {
80 // start the thread here so that we don't busy-wait in run()
81 // waiting for the surface to be created
82 createThread();
alisionfe9cf712013-05-03 17:26:08 -040083
Adrien Béraud04463092013-05-06 14:17:22 +100084 Log.w(TAG, "surfaceCreated");
85 thread.setRunning(true);
86 thread.start();
87 }
alisionfe9cf712013-05-03 17:26:08 -040088
Adrien Béraud04463092013-05-06 14:17:22 +100089 /*
90 * Callback invoked when the Surface has been destroyed and must no longer
91 * be touched. WARNING: after this method returns, the Surface/Canvas must
92 * never be touched again!
93 */
94 @Override
95 public void surfaceDestroyed(SurfaceHolder holder)
96 {
97 // we have to tell thread to shut down & wait for it to finish, or else
98 // it might touch the Surface after we return and explode
99 Log.w(TAG, "surfaceDestroyed");
100 boolean retry = true;
101 thread.setRunning(false);
Adrien Béraud25fc4092013-05-06 15:28:39 +1000102 while (retry) {
Adrien Béraud04463092013-05-06 14:17:22 +1000103 try {
104 thread.join();
105 retry = false;
106 } catch (InterruptedException e) {
107 }
Adrien Béraud25fc4092013-05-06 15:28:39 +1000108 }
Adrien Béraud04463092013-05-06 14:17:22 +1000109 thread = null;
110 }
alisionfe9cf712013-05-03 17:26:08 -0400111
Adrien Béraud04463092013-05-06 14:17:22 +1000112 @Override
113 public boolean onTouch(View v, MotionEvent event)
114 {
115 Log.w(TAG, "onTouch " + event.getAction());
Adrien Béraud25fc4092013-05-06 15:28:39 +1000116
117 int action = event.getActionMasked();
118
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000119 if (action == MotionEvent.ACTION_DOWN) {
Adrien Béraud04463092013-05-06 14:17:22 +1000120 for (Bubble b : model.listBubbles) {
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000121 if (b.intersects(event.getX(), event.getY())) {
Adrien Béraud25fc4092013-05-06 15:28:39 +1000122 b.dragged = true;
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000123 b.last_drag = System.nanoTime();
Adrien Béraud25fc4092013-05-06 15:28:39 +1000124 }
125 }
126 } else if (action == MotionEvent.ACTION_MOVE) {
127 for (Bubble b : model.listBubbles) {
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000128 if (b.dragged) {
129 float x = event.getX(), y = event.getY();
130 long now = System.nanoTime();
131 float dt = (float) ((now-b.last_drag)/1000000000.);
132 float dx = x - b.getPosX(), dy = y - b.getPosY();
133 b.last_drag = now;
134
Adrien Béraud25fc4092013-05-06 15:28:39 +1000135 b.setPos(event.getX(), event.getY());
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000136 /*int hn = event.getHistorySize() - 2;
137 Log.w(TAG, "event.getHistorySize() : " + event.getHistorySize());
138 if(hn > 0) {
139 float dx = x-event.getHistoricalX(hn);
140 float dy = y-event.getHistoricalY(hn);
141 float dt = event.getHistoricalEventTime(hn)/1000.f;*/
142 b.speed.x = dx/dt;
143 b.speed.y = dy/dt;
144 //Log.w(TAG, "onTouch dx:" + b.speed.x + " dy:" + b.speed.y);
145 //}
Adrien Béraud04463092013-05-06 14:17:22 +1000146 return true;
147 }
148 }
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000149 } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
Adrien Béraud25fc4092013-05-06 15:28:39 +1000150 for (Bubble b : model.listBubbles) {
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000151 if (b.dragged) {
Adrien Béraud25fc4092013-05-06 15:28:39 +1000152 b.dragged = false;
153 }
154 }
155 }
Adrien Béraud04463092013-05-06 14:17:22 +1000156 return true;
157 }
alisionfe9cf712013-05-03 17:26:08 -0400158
Adrien Béraud04463092013-05-06 14:17:22 +1000159 class BubblesThread extends Thread
160 {
161 private boolean running = false;
162 private SurfaceHolder surfaceHolder;
alisionfe9cf712013-05-03 17:26:08 -0400163
Adrien Béraud04463092013-05-06 14:17:22 +1000164 BubbleModel model = null;
alisionfe9cf712013-05-03 17:26:08 -0400165
Adrien Béraud04463092013-05-06 14:17:22 +1000166 public BubblesThread(SurfaceHolder holder, Context context, Handler handler)
167 {
168 surfaceHolder = holder;
169 }
alisionfe9cf712013-05-03 17:26:08 -0400170
Adrien Béraud04463092013-05-06 14:17:22 +1000171 public void setModel(BubbleModel model)
172 {
173 this.model = model;
174 }
alisionfe9cf712013-05-03 17:26:08 -0400175
Adrien Béraud04463092013-05-06 14:17:22 +1000176 @Override
177 public void run()
178 {
179 while (running) {
180 Canvas c = null;
181 try {
182 c = surfaceHolder.lockCanvas(null);
Adrien Béraud7ed23dc2013-05-06 16:27:24 +1000183
184 // for the case the surface is destroyed while already in the loop
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000185 if (c == null || model == null)
186 continue;
Adrien Béraud7ed23dc2013-05-06 16:27:24 +1000187
Adrien Béraud04463092013-05-06 14:17:22 +1000188 synchronized (surfaceHolder) {
Adrien Béraud25fc4092013-05-06 15:28:39 +1000189 //Log.w(TAG, "Thread doDraw");
190 model.update();
Adrien Béraud04463092013-05-06 14:17:22 +1000191 doDraw(c);
192 }
193 } finally {
194 // do this in a finally so that if an exception is thrown
195 // during the above, we don't leave the Surface in an
196 // inconsistent state
197 if (c != null)
198 surfaceHolder.unlockCanvasAndPost(c);
199 }
200 }
201 }
202
203 public void setRunning(boolean b)
204 {
205 running = b;
206 }
207
208 public void setSurfaceSize(int width, int height)
209 {
210 synchronized (surfaceHolder) {
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000211 if (model != null) {
Adrien Béraud25fc4092013-05-06 15:28:39 +1000212 model.width = width;
213 model.height = height;
214 }
Adrien Béraud04463092013-05-06 14:17:22 +1000215
216 // don't forget to resize the background image
217 // mBackgroundImage = Bitmap.createScaledBitmap(mBackgroundImage, width, height, true);
218 }
219 }
220
Adrien Béraud04463092013-05-06 14:17:22 +1000221 private void doDraw(Canvas canvas)
222 {
223 canvas.drawColor(Color.WHITE);
224
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000225 synchronized (model) {
226 for (int i = 0; i < model.listBubbles.size(); i++) {
227 Bubble b = model.listBubbles.get(i);
228 canvas.drawBitmap(b.getBitmap(), null, b.getBounds(), null);
229 }
Adrien Béraud25fc4092013-05-06 15:28:39 +1000230 }
Adrien Béraud04463092013-05-06 14:17:22 +1000231 }
232 }
233
alisionfe9cf712013-05-03 17:26:08 -0400234}