OSDN Git Service

#19468
[tokyorunners/tokyorunners.git] / src / net / kazhik / android / tokyorunners / MapMode.java
1 package net.kazhik.android.tokyorunners;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.Iterator;\r
5 import java.util.List;\r
6 \r
7 import android.app.AlertDialog;\r
8 import android.app.Dialog;\r
9 import android.content.BroadcastReceiver;\r
10 import android.content.Context;\r
11 import android.content.DialogInterface;\r
12 import android.content.Intent;\r
13 import android.content.IntentFilter;\r
14 import android.graphics.Canvas;\r
15 import android.graphics.Color;\r
16 import android.graphics.Paint;\r
17 import android.graphics.Path;\r
18 import android.graphics.Point;\r
19 import android.graphics.PointF;\r
20 import android.graphics.RectF;\r
21 import android.graphics.Paint.FontMetrics;\r
22 import android.graphics.drawable.ShapeDrawable;\r
23 import android.graphics.drawable.shapes.PathShape;\r
24 import android.location.Location;\r
25 import android.location.LocationManager;\r
26 import android.os.Bundle;\r
27 import android.os.Debug;\r
28 import android.view.KeyEvent;\r
29 import android.view.Menu;\r
30 import android.view.MenuItem;\r
31 \r
32 import com.google.android.maps.GeoPoint;\r
33 import com.google.android.maps.MapActivity;\r
34 import com.google.android.maps.MapController;\r
35 import com.google.android.maps.MapView;\r
36 import com.google.android.maps.MyLocationOverlay;\r
37 import com.google.android.maps.Overlay;\r
38 import com.google.android.maps.Projection;\r
39 \r
40 // TODO: Auto-generated Javadoc\r
41 /**\r
42  * The Class MapMode.\r
43  */\r
44 public class MapMode extends MapActivity {\r
45 \r
46         /** The m_controller. */\r
47         private MapController m_controller;\r
48 \r
49         /** The m_map overlays. */\r
50         private List<Overlay> m_mapOverlays;\r
51 \r
52         /** The m_start time. */\r
53         private long m_startTime = 0;\r
54 \r
55         /** The m_route paint. */\r
56         private static Paint m_routePaint;\r
57 \r
58         /** The m_text paint. */\r
59         private static Paint m_textPaint;\r
60 \r
61         /** The m_info paint. */\r
62         private static Paint m_infoPaint;\r
63 \r
64         private RunningRoute m_route;\r
65 \r
66         static {\r
67                 m_routePaint = new Paint(Paint.ANTI_ALIAS_FLAG);\r
68                 m_routePaint.setStyle(Paint.Style.STROKE);\r
69                 m_routePaint.setAntiAlias(true);\r
70                 m_routePaint.setStrokeWidth(3);\r
71                 m_routePaint.setColor(Color.YELLOW);\r
72 \r
73                 m_textPaint = new Paint();\r
74                 m_textPaint.setColor(Color.BLACK);\r
75 \r
76                 m_infoPaint = new Paint();\r
77                 m_infoPaint.setTextSize(20);\r
78                 m_infoPaint.setAntiAlias(true);\r
79                 m_infoPaint.setFakeBoldText(true);\r
80                 m_infoPaint.setColor(Color.LTGRAY);\r
81 \r
82         }\r
83 \r
84         /**\r
85          * The Class RunningRoute.\r
86          */\r
87         public class RunningRoute extends Overlay {\r
88 \r
89                 private ArrayList<GeoPoint> m_pointList = new ArrayList<GeoPoint>();\r
90 \r
91                 public RunningRoute() {\r
92 \r
93                 }\r
94 \r
95                 public void addPoint(GeoPoint pt) {\r
96                         m_pointList.add(pt);\r
97                 }\r
98 \r
99                 /*\r
100                  * (non-Javadoc)\r
101                  * \r
102                  * @see com.google.android.maps.Overlay#draw(android.graphics.Canvas,\r
103                  * com.google.android.maps.MapView, boolean)\r
104                  */\r
105                 @Override\r
106                 public void draw(Canvas canvas, MapView mapView, boolean shadow) {\r
107                         super.draw(canvas, mapView, shadow);\r
108 \r
109                         if (!shadow) {\r
110                                 Projection projection = mapView.getProjection();\r
111                                 Point pxStart = null;\r
112                                 Point pxEnd = null;\r
113                                 GeoPoint gpCenter = mapView.getMapCenter();\r
114                                 int latFrom = gpCenter.getLatitudeE6()\r
115                                                 - (mapView.getLatitudeSpan() / 2);\r
116                                 int latTo = gpCenter.getLatitudeE6()\r
117                                                 + (mapView.getLatitudeSpan() / 2);\r
118                                 int lonFrom = gpCenter.getLongitudeE6()\r
119                                                 - (mapView.getLongitudeSpan() / 2);\r
120                                 int lonTo = gpCenter.getLongitudeE6()\r
121                                                 + (mapView.getLongitudeSpan() / 2);\r
122                                 for (Iterator<GeoPoint> it = m_pointList.iterator(); it\r
123                                                 .hasNext();) {\r
124                                         GeoPoint gp = it.next();\r
125 \r
126                                         int lat = gp.getLatitudeE6();\r
127                                         int lon = gp.getLongitudeE6();\r
128                                         // 表示されない部分は描画しない\r
129                                         if (lat < latFrom || lat > latTo || lon < lonFrom\r
130                                                         || lon > lonTo) {\r
131                                                 continue;\r
132                                         }\r
133 \r
134                                         pxEnd = projection.toPixels(gp, null);\r
135                                         if (pxStart != null) {\r
136 \r
137                                                 canvas.drawLine(pxStart.x, pxStart.y, pxEnd.x, pxEnd.y,\r
138                                                                 m_routePaint);\r
139                                         }\r
140 \r
141                                         pxStart = pxEnd;\r
142                                 }\r
143                         }\r
144                 }\r
145         }\r
146 \r
147         /**\r
148          * The Class TextOverlay.\r
149          */\r
150         public class TextOverlay extends Overlay {\r
151 \r
152                 /** The m_text. */\r
153                 private String m_text;\r
154 \r
155                 /** The m_point. */\r
156                 private GeoPoint m_point;\r
157 \r
158                 /**\r
159                  * Instantiates a new text overlay.\r
160                  * \r
161                  * @param point\r
162                  *            the point\r
163                  * @param text\r
164                  *            the text\r
165                  */\r
166                 public TextOverlay(GeoPoint point, String text) {\r
167                         m_point = point;\r
168                         m_text = text;\r
169                 }\r
170 \r
171                 /*\r
172                  * (non-Javadoc)\r
173                  * \r
174                  * @see com.google.android.maps.Overlay#draw(android.graphics.Canvas,\r
175                  * com.google.android.maps.MapView, boolean)\r
176                  */\r
177                 @Override\r
178                 public void draw(Canvas canvas, MapView mapView, boolean shadow) {\r
179                         super.draw(canvas, mapView, shadow);\r
180 \r
181                         if (!shadow) {\r
182                                 Projection projection = mapView.getProjection();\r
183                                 Point pt = projection.toPixels(m_point, null);\r
184 \r
185                                 drawBalloon(canvas, pt);\r
186                         }\r
187                 }\r
188 \r
189                 /**\r
190                  * Draw balloon.\r
191                  * \r
192                  * @param canvas\r
193                  *            the canvas\r
194                  * @param pt\r
195                  *            the pt\r
196                  */\r
197                 private void drawBalloon(Canvas canvas, Point pt) {\r
198                         FontMetrics fontMetrics = m_textPaint.getFontMetrics();\r
199                         float textWidth = m_textPaint.measureText(m_text);\r
200                         float textHeight = Math.abs(fontMetrics.top) + fontMetrics.bottom;\r
201 \r
202                         float triangleHeight = textHeight;\r
203                         float triangleWidth = triangleHeight;\r
204 \r
205                         final float margin = 5;\r
206                         float textX = pt.x - textWidth / 2;\r
207 \r
208                         float textY = pt.y - margin - triangleHeight;\r
209 \r
210                         RectF infoRect = new RectF(textX - margin, pt.y - textHeight\r
211                                         - (margin * 2) - triangleHeight,\r
212                                         textX + textWidth + margin, pt.y - triangleHeight);\r
213 \r
214                         final float radius = 5;\r
215                         // テキストが入る四角形を描画\r
216                         canvas.drawRoundRect(infoRect, radius, radius, m_infoPaint);\r
217 \r
218                         // ポイントを指す三角形を描画\r
219 \r
220                         PointF[] cornerPoint = new PointF[3];\r
221                         PointF point = new PointF(infoRect.centerX() - triangleWidth / 2,\r
222                                         infoRect.bottom);\r
223                         cornerPoint[0] = new PointF(0, 0);\r
224                         cornerPoint[1] = new PointF(triangleWidth, 0);\r
225                         cornerPoint[2] = new PointF(triangleWidth / 2, triangleHeight);\r
226 \r
227                         drawShape(canvas, point, cornerPoint, m_infoPaint.getColor());\r
228 \r
229                         // テキストを描画\r
230                         canvas.drawText(m_text, textX, textY, m_textPaint);\r
231 \r
232                 }\r
233 \r
234                 /**\r
235                  * 多角形の描画.\r
236                  * \r
237                  * @param canvas\r
238                  *            the canvas\r
239                  * @param point\r
240                  *            描画位置\r
241                  * @param corners\r
242                  *            描画する頂点を表わすポイント\r
243                  * @param color\r
244                  *            描画色\r
245                  */\r
246                 private void drawShape(Canvas canvas, PointF point, PointF[] corners,\r
247                                 int color) {\r
248                         float maxWidth = 0;\r
249                         float maxHeight = 0;\r
250 \r
251                         // Pointを結ぶ頂点のパス作成\r
252                         Path path = new Path();\r
253                         for (int cornerCnt = 0; cornerCnt < corners.length; cornerCnt++) {\r
254                                 float x = corners[cornerCnt].x;\r
255                                 float y = corners[cornerCnt].y;\r
256                                 // はじめの頂点はmoveTo\r
257                                 if (cornerCnt == 0) {\r
258                                         path.moveTo(x, y);\r
259                                 } else {\r
260                                         path.lineTo(x, y);\r
261                                 }\r
262 \r
263                                 if (maxWidth < x) {\r
264                                         maxWidth = x;\r
265                                 }\r
266                                 if (maxHeight < y) {\r
267                                         maxHeight = y;\r
268                                 }\r
269                         }\r
270                         // パスを閉じる\r
271                         path.close();\r
272 \r
273                         ShapeDrawable drawable = new ShapeDrawable(new PathShape(path,\r
274                                         maxWidth, maxHeight));\r
275                         drawable.getPaint().setColor(color);\r
276                         drawable.setBounds((int) point.x, (int) point.y, (int) point.x\r
277                                         + (int) maxWidth, (int) point.y + (int) maxHeight);\r
278                         drawable.draw(canvas);\r
279                 }\r
280         }\r
281 \r
282         /** The m_running record receiver. */\r
283         private BroadcastReceiver m_runningRecordReceiver = new BroadcastReceiver() {\r
284                 @Override\r
285                 public void onReceive(Context context, Intent intent) {\r
286                         String action = intent.getAction();\r
287                         if (action.equals("NewRunningRecord")) {\r
288                                 long recordDate = intent.getLongExtra("RunningRecord", 0);\r
289 \r
290                                 Record rec = TokyoRunners.getRecord(recordDate);\r
291 \r
292                                 if (rec == null) {\r
293                                         ExLog.put("No record: " + recordDate);\r
294                                         return;\r
295                                 }\r
296 \r
297                                 GeoPoint gp = new GeoPoint(rec.getLatitudeE6(), rec\r
298                                                 .getLongitudeE6());\r
299                                 m_controller.animateTo(gp);\r
300 \r
301                                 m_route.addPoint(gp);\r
302                                 // Split point\r
303                                 if (rec.getName().length() > 0) {\r
304                                         TextOverlay textOverlay = new TextOverlay(gp, rec.getName());\r
305                                         m_mapOverlays.add(textOverlay);\r
306                                 }\r
307                         }\r
308 \r
309                 }\r
310         };\r
311 \r
312         /*\r
313          * (non-Javadoc)\r
314          * \r
315          * @see com.google.android.maps.MapActivity#isRouteDisplayed()\r
316          */\r
317         @Override\r
318         protected boolean isRouteDisplayed() {\r
319                 return false;\r
320         }\r
321 \r
322         /*\r
323          * (non-Javadoc)\r
324          * \r
325          * @see com.google.android.maps.MapActivity#onResume()\r
326          */\r
327         @Override\r
328         public void onResume() {\r
329                 super.onResume();\r
330                 IntentFilter filter = new IntentFilter();\r
331                 filter.addAction("NewRunningRecord");\r
332 \r
333                 registerReceiver(m_runningRecordReceiver, filter);\r
334 \r
335                 // 履歴が読み込まれた場合は再描画\r
336                 Record rec = TokyoRunners.getRecord(m_startTime);\r
337                 if (rec == null) {\r
338                         MapView mapView = (MapView) findViewById(R.id.mapview);\r
339                         drawOverlays(mapView);\r
340                 }\r
341 \r
342         }\r
343 \r
344         /*\r
345          * (non-Javadoc)\r
346          * \r
347          * @see com.google.android.maps.MapActivity#onPause()\r
348          */\r
349         @Override\r
350         public void onPause() {\r
351                 super.onPause();\r
352 \r
353                 unregisterReceiver(m_runningRecordReceiver);\r
354         }\r
355 \r
356         /*\r
357          * (non-Javadoc)\r
358          * \r
359          * @see com.google.android.maps.MapActivity#onCreate(android.os.Bundle)\r
360          */\r
361         @Override\r
362         public void onCreate(Bundle savedInstanceState) {\r
363                 super.onCreate(savedInstanceState);\r
364 \r
365                 setContentView(R.layout.map);\r
366 \r
367                 MapView mapView = (MapView) findViewById(R.id.mapview);\r
368                 mapView.setBuiltInZoomControls(true);\r
369 \r
370                 m_controller = mapView.getController();\r
371                 m_controller.setZoom(16);\r
372 \r
373                 m_mapOverlays = mapView.getOverlays();\r
374 \r
375                 m_route = new RunningRoute();\r
376                 m_mapOverlays.add(m_route);\r
377 \r
378                 drawOverlays(mapView);\r
379         }\r
380 \r
381         /**\r
382          * Draw overlays.\r
383          * \r
384          * @param mapView\r
385          *            the map view\r
386          */\r
387         private void drawOverlays(MapView mapView) {\r
388 \r
389                 m_mapOverlays.clear();\r
390 \r
391                 MyLocationOverlay myLocationOverlay = new MyLocationOverlay(this,\r
392                                 mapView);\r
393                 myLocationOverlay.enableMyLocation();\r
394 \r
395                 m_mapOverlays.add(myLocationOverlay);\r
396 \r
397                 Iterator<Record> it = TokyoRunners.getRecordIterator();\r
398                 GeoPoint gp = null;\r
399                 RunningRoute route = new RunningRoute();\r
400                 while (it.hasNext()) {\r
401                         Record rec = it.next();\r
402                         if (rec.hasLocation()) {\r
403                                 gp = new GeoPoint(rec.getLatitudeE6(), rec.getLongitudeE6());\r
404                                 route.addPoint(gp);\r
405 \r
406                                 if (rec.getName().length() > 0) {\r
407                                         TextOverlay textOverlay = new TextOverlay(gp, rec.getName());\r
408                                         m_mapOverlays.add(textOverlay);\r
409                                         // drawSplitPoint(gp, rec.getName(), rec.getDate());\r
410                                 }\r
411                         }\r
412                         if (m_startTime == 0) {\r
413                                 m_startTime = rec.getDate().getTime();\r
414                         }\r
415                 }\r
416                 m_mapOverlays.add(route);\r
417                 if (gp != null) {\r
418                         m_controller.setCenter(gp);\r
419                 }\r
420 \r
421         }\r
422 \r
423         /*\r
424          * (non-Javadoc)\r
425          * \r
426          * @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)\r
427          */\r
428         public boolean onKeyDown(int keyCode, KeyEvent event) {\r
429                 if (keyCode == KeyEvent.KEYCODE_BACK) {\r
430                         showDialog(Constants.DIALOG_EXIT_ID);\r
431                         return true;\r
432                 }\r
433 \r
434                 return super.onKeyDown(keyCode, event);\r
435 \r
436         }\r
437 \r
438         /*\r
439          * (non-Javadoc)\r
440          * \r
441          * @see android.app.Activity#onCreateDialog(int)\r
442          */\r
443         @Override\r
444         public Dialog onCreateDialog(int id) {\r
445 \r
446                 AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
447                 switch (id) {\r
448                 case Constants.DIALOG_EXIT_ID:\r
449                         builder.setTitle(R.string.dialog_exit_title);\r
450                         builder.setMessage(R.string.dialog_exit_message);\r
451                         builder.setPositiveButton(R.string.dialog_yes,\r
452                                         new DialogInterface.OnClickListener() {\r
453                                                 @Override\r
454                                                 public void onClick(DialogInterface dialog, int which) {\r
455                                                         Debug.stopMethodTracing();\r
456                                                         finish();\r
457 \r
458                                                 }\r
459                                         });\r
460                         builder.setNegativeButton(R.string.dialog_no,\r
461                                         new DialogInterface.OnClickListener() {\r
462                                                 @Override\r
463                                                 public void onClick(DialogInterface dialog, int which) {\r
464                                                         dialog.cancel();\r
465 \r
466                                                 }\r
467                                         });\r
468 \r
469                         break;\r
470                 default:\r
471                         break;\r
472                 }\r
473 \r
474                 AlertDialog alertDialog = builder.create();\r
475                 return alertDialog;\r
476         }\r
477 \r
478         /*\r
479          * (non-Javadoc)\r
480          * \r
481          * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)\r
482          */\r
483         @Override\r
484         public boolean onCreateOptionsMenu(Menu menu) {\r
485                 menu.add(Menu.NONE, Constants.MENU_HERE, Menu.NONE, R.string.menu_here)\r
486                                 .setIcon(android.R.drawable.ic_menu_mylocation);\r
487                 return super.onCreateOptionsMenu(menu);\r
488         }\r
489 \r
490         /*\r
491          * (non-Javadoc)\r
492          * \r
493          * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)\r
494          */\r
495         @Override\r
496         public boolean onOptionsItemSelected(MenuItem item) {\r
497                 Intent intent;\r
498                 switch (item.getItemId()) {\r
499                 case Constants.MENU_SETTING:\r
500                         intent = new Intent(this, Config.class);\r
501                         intent.setAction(Intent.ACTION_VIEW);\r
502                         startActivity(intent);\r
503                         break;\r
504                 case Constants.MENU_HERE:\r
505                         LocationManager locMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);\r
506                         Location loc = locMgr\r
507                                         .getLastKnownLocation(LocationManager.GPS_PROVIDER);\r
508                         if (loc != null) {\r
509                                 GeoPoint gp = new GeoPoint((int) (loc.getLatitude() * 1E6),\r
510                                                 (int) (loc.getLongitude() * 1E6));\r
511                                 m_controller.animateTo(gp);\r
512                         }\r
513                         break;\r
514                 default:\r
515                         break;\r
516                 }\r
517                 return false;\r
518         }\r
519 \r
520 }\r