Tokyo Runnersソースコード及びドキュメント
リビジョン | b10bb2a2315f98ab15bfe6bfc0b349cc81127a04 (tree) |
---|---|
日時 | 2009-10-30 12:01:18 |
作者 | kazhik <kazhik@gmai...> |
コミッター | kazhik |
gpx file
@@ -1,7 +1,7 @@ | ||
1 | -<?xml version="1.0" encoding="UTF-8"?> | |
2 | -<classpath> | |
3 | - <classpathentry kind="src" path="src"/> | |
4 | - <classpathentry kind="src" path="gen"/> | |
5 | - <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> | |
6 | - <classpathentry kind="output" path="bin"/> | |
7 | -</classpath> | |
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<classpath> | |
3 | + <classpathentry kind="src" path="src"/> | |
4 | + <classpathentry kind="src" path="gen"/> | |
5 | + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> | |
6 | + <classpathentry kind="output" path="bin"/> | |
7 | +</classpath> |
@@ -16,7 +16,7 @@ | ||
16 | 16 | </activity> |
17 | 17 | <activity android:name="MapMode"> |
18 | 18 | <intent-filter> |
19 | - <action android:name="RunningRecord" /> | |
19 | + <action android:name="NewRunningRecord" /> | |
20 | 20 | </intent-filter> |
21 | 21 | </activity> |
22 | 22 | <activity android:name="Config"></activity> |
@@ -5,5 +5,5 @@ | ||
5 | 5 | android:layout_width="fill_parent" |
6 | 6 | android:textColor="#7CFC00" |
7 | 7 | |
8 | - android:layout_height="50dp"> | |
8 | + android:layout_height="72dp"> | |
9 | 9 | </TextView> |
@@ -19,6 +19,7 @@ | ||
19 | 19 | |
20 | 20 | <string name="contextmenu_deletethis">Delete this</string> |
21 | 21 | <string name="contextmenu_deleteall">Delete all</string> |
22 | + <string name="contextmenu_save_gpx">Save as GPX file</string> | |
22 | 23 | |
23 | 24 | <string name="dialog_save_title">Save record</string> |
24 | 25 | <string name="dialog_save_message">Do you want to save the current record?</string> |
@@ -3,13 +3,9 @@ package net.kazhik.android.tokyorunners; | ||
3 | 3 | import android.view.Menu; |
4 | 4 | |
5 | 5 | public class Constants { |
6 | - public static final int MENU_STOPWATCH = Menu.FIRST + 1; | |
7 | - public static final int MENU_MAP = Menu.FIRST + 2; | |
8 | - public static final int MENU_SETTING = Menu.FIRST + 3; | |
9 | - public static final int MENU_SAVE = Menu.FIRST + 4; | |
10 | - public static final int MENU_HISTORY = Menu.FIRST + 5; | |
6 | + public static final int MENU_SETTING = Menu.FIRST + 1; | |
7 | + public static final int MENU_HISTORY = Menu.FIRST + 2; | |
11 | 8 | |
12 | - public static final int DIALOG_SAVE_ID = 4000; | |
13 | 9 | public static final int DIALOG_EXIT_ID = 4001; |
14 | 10 | |
15 | 11 | public static final int REQUEST_CODE_SETTINGS = 1000; |
@@ -45,6 +45,7 @@ public class MapMode extends MapActivity { | ||
45 | 45 | private List<Overlay> m_mapOverlays; |
46 | 46 | private SplitPoints m_overlaySplitpoints; |
47 | 47 | private GeoPoint m_prevPoint = null; |
48 | + private long m_startTime = 0; | |
48 | 49 | |
49 | 50 | public class RunningRoute extends Overlay { |
50 | 51 |
@@ -94,10 +95,14 @@ public class MapMode extends MapActivity { | ||
94 | 95 | |
95 | 96 | @Override |
96 | 97 | protected OverlayItem createItem(int idx) { |
97 | - Log.d(this.getClass().getName(), "createItem(): index: " + idx); | |
98 | +// Log.d(this.getClass().getName(), "createItem(): index: " + idx); | |
98 | 99 | return m_splitpoints.get(idx); |
99 | 100 | } |
100 | 101 | |
102 | + public void clearItem() { | |
103 | + m_splitpoints.clear(); | |
104 | + } | |
105 | + | |
101 | 106 | @Override |
102 | 107 | public int size() { |
103 | 108 | return m_splitpoints.size(); |
@@ -123,29 +128,32 @@ public class MapMode extends MapActivity { | ||
123 | 128 | private BroadcastReceiver m_runningRecordReceiver = new BroadcastReceiver() { |
124 | 129 | @Override |
125 | 130 | public void onReceive(Context context, Intent intent) { |
126 | - long recordDate = intent.getLongExtra("RunningRecord", 0); | |
131 | + String action = intent.getAction(); | |
132 | + if (action.equals("NewRunningRecord")) { | |
133 | + long recordDate = intent.getLongExtra("RunningRecord", 0); | |
127 | 134 | |
128 | - Record rec = TokyoRunners.getRecord(recordDate); | |
135 | + Record rec = TokyoRunners.getRecord(recordDate); | |
129 | 136 | |
130 | - if (rec == null) { | |
131 | - ExLog.put("No record: " + recordDate); | |
132 | - return; | |
133 | - } | |
134 | - GeoPoint gp = new GeoPoint(rec.getLatitudeE6(), rec | |
135 | - .getLongitudeE6()); | |
136 | - m_controller.animateTo(gp); | |
137 | - | |
138 | - // Route | |
139 | - if (m_prevPoint != null) { | |
140 | - RunningRoute route = new RunningRoute(m_prevPoint, gp); | |
141 | - m_mapOverlays.add(route); | |
142 | - } | |
143 | - // Split point | |
144 | - if (rec.getName().length() > 0) { | |
145 | - drawSplitPoint(gp, rec.getName(), rec.getDate()); | |
146 | - } | |
137 | + if (rec == null) { | |
138 | + ExLog.put("No record: " + recordDate); | |
139 | + return; | |
140 | + } | |
141 | + | |
142 | + GeoPoint gp = new GeoPoint(rec.getLatitudeE6(), rec | |
143 | + .getLongitudeE6()); | |
144 | + m_controller.animateTo(gp); | |
147 | 145 | |
148 | - m_prevPoint = gp; | |
146 | + // Route | |
147 | + if (m_prevPoint != null) { | |
148 | + RunningRoute route = new RunningRoute(m_prevPoint, gp); | |
149 | + m_mapOverlays.add(route); | |
150 | + } | |
151 | + // Split point | |
152 | + if (rec.getName().length() > 0) { | |
153 | + drawSplitPoint(gp, rec.getName(), rec.getDate()); | |
154 | + } | |
155 | + m_prevPoint = gp; | |
156 | + } | |
149 | 157 | |
150 | 158 | } |
151 | 159 | }; |
@@ -160,10 +168,18 @@ public class MapMode extends MapActivity { | ||
160 | 168 | Log.d(this.getClass().getName(), "onResume()"); |
161 | 169 | super.onResume(); |
162 | 170 | IntentFilter filter = new IntentFilter(); |
163 | - filter.addAction("RunningRecord"); | |
171 | + filter.addAction("NewRunningRecord"); | |
164 | 172 | |
165 | 173 | registerReceiver(m_runningRecordReceiver, filter); |
166 | 174 | |
175 | + // 履歴が読み込まれた場合は再描画 | |
176 | + Record rec = TokyoRunners.getRecord(m_startTime); | |
177 | + if (rec == null) { | |
178 | + MapView mapView = (MapView) findViewById(R.id.mapview); | |
179 | + drawOverlays(mapView); | |
180 | + } | |
181 | + | |
182 | + | |
167 | 183 | } |
168 | 184 | |
169 | 185 | @Override |
@@ -179,34 +195,31 @@ public class MapMode extends MapActivity { | ||
179 | 195 | |
180 | 196 | setContentView(R.layout.map); |
181 | 197 | |
182 | - SharedPreferences prefs = PreferenceManager | |
183 | - .getDefaultSharedPreferences(this); | |
184 | - | |
185 | - MapView m = (MapView) findViewById(R.id.mapview); | |
186 | - m.setBuiltInZoomControls(true); | |
198 | + MapView mapView = (MapView) findViewById(R.id.mapview); | |
199 | + mapView.setBuiltInZoomControls(true); | |
187 | 200 | |
188 | - m_controller = m.getController(); | |
201 | + m_controller = mapView.getController(); | |
189 | 202 | m_controller.setZoom(16); |
190 | 203 | |
191 | - m_mapOverlays = m.getOverlays(); | |
204 | + m_mapOverlays = mapView.getOverlays(); | |
192 | 205 | |
193 | 206 | Drawable runner = getResources().getDrawable(R.drawable.runner); |
194 | 207 | m_overlaySplitpoints = new SplitPoints(runner); |
195 | 208 | |
196 | - MyLocationOverlay myLocationOverlay = new MyLocationOverlay(this, m); | |
209 | + drawOverlays(mapView); | |
210 | + } | |
211 | + | |
212 | + private void drawOverlays(MapView mapView) { | |
213 | + | |
214 | + m_mapOverlays.clear(); | |
215 | + | |
216 | + MyLocationOverlay myLocationOverlay = new MyLocationOverlay(this, mapView); | |
197 | 217 | myLocationOverlay.enableMyLocation(); |
198 | 218 | |
199 | 219 | m_mapOverlays.add(myLocationOverlay); |
200 | 220 | |
201 | - m.setOnLongClickListener(new OnLongClickListener() { | |
202 | - @Override | |
203 | - public boolean onLongClick(View v) { | |
204 | - Log.d(this.getClass().getName(), "onLongClick():"); | |
205 | - finish(); | |
206 | - return false; | |
207 | - } | |
208 | - }); | |
209 | - | |
221 | + m_overlaySplitpoints.clearItem(); | |
222 | + | |
210 | 223 | long recTime = 0; |
211 | 224 | Record rec; |
212 | 225 | while ((rec = TokyoRunners.getNextRecord(recTime)) != null) { |
@@ -224,7 +237,11 @@ public class MapMode extends MapActivity { | ||
224 | 237 | } |
225 | 238 | } |
226 | 239 | recTime = rec.getDate().getTime(); |
240 | + if (m_startTime == 0) { | |
241 | + m_startTime = recTime; | |
242 | + } | |
227 | 243 | } |
244 | + | |
228 | 245 | } |
229 | 246 | |
230 | 247 | private void drawSplitPoint(GeoPoint gp, String pointName, Date recDate) { |
@@ -283,14 +300,6 @@ public class MapMode extends MapActivity { | ||
283 | 300 | } |
284 | 301 | |
285 | 302 | @Override |
286 | - public boolean onPrepareOptionsMenu(Menu menu) { | |
287 | - menu.removeItem(Constants.MENU_SAVE); | |
288 | - menu.removeItem(Constants.MENU_HISTORY); | |
289 | - | |
290 | - return super.onPrepareOptionsMenu(menu); | |
291 | - } | |
292 | - | |
293 | - @Override | |
294 | 303 | public boolean onOptionsItemSelected(MenuItem item) { |
295 | 304 | Intent intent; |
296 | 305 | switch (item.getItemId()) { |
@@ -1,15 +1,21 @@ | ||
1 | 1 | package net.kazhik.android.tokyorunners; |
2 | 2 | |
3 | +import java.io.FileOutputStream; | |
4 | +import java.io.IOException; | |
5 | +import java.io.OutputStreamWriter; | |
3 | 6 | import java.text.ParseException; |
4 | 7 | import java.text.SimpleDateFormat; |
5 | 8 | import java.util.ArrayList; |
6 | 9 | import java.util.Date; |
7 | 10 | import java.util.HashMap; |
11 | +import java.util.Iterator; | |
8 | 12 | |
9 | 13 | import android.app.ListActivity; |
10 | 14 | import android.content.Intent; |
11 | 15 | import android.database.Cursor; |
12 | 16 | import android.os.Bundle; |
17 | +import android.os.Environment; | |
18 | +import android.util.Log; | |
13 | 19 | import android.view.ContextMenu; |
14 | 20 | import android.view.Menu; |
15 | 21 | import android.view.MenuItem; |
@@ -26,6 +32,11 @@ public class RunningHistory extends ListActivity implements OnItemClickListener | ||
26 | 32 | |
27 | 33 | private static final int MENU_DELETE_THIS = Menu.FIRST + 200; |
28 | 34 | private static final int MENU_DELETE_ALL = Menu.FIRST + 201; |
35 | + private static final int MENU_SAVE_GPX = Menu.FIRST + 202; | |
36 | + | |
37 | + private final static String LOGDIR = Environment | |
38 | + .getExternalStorageDirectory().getPath() | |
39 | + + "/tokyorunners/"; | |
29 | 40 | |
30 | 41 | @Override |
31 | 42 | public void onCreate(Bundle savedInstanceState) { |
@@ -40,7 +51,7 @@ public class RunningHistory extends ListActivity implements OnItemClickListener | ||
40 | 51 | String sortOrder = RunningRecordProvider.CURRENT_TIME + " desc"; |
41 | 52 | Cursor cursor = managedQuery(RunningRecordProvider.REC_URI, columns, null, null, sortOrder); |
42 | 53 | |
43 | - if (cursor == null) { | |
54 | + if (cursor == null || cursor.getCount() == 0) { | |
44 | 55 | return; |
45 | 56 | } |
46 | 57 | ArrayList<String> history = new ArrayList<String>(); |
@@ -50,6 +61,8 @@ public class RunningHistory extends ListActivity implements OnItemClickListener | ||
50 | 61 | while (cursor.moveToNext()) { |
51 | 62 | startTime = cursor.getLong(0); |
52 | 63 | distance = (float)cursor.getLong(1); |
64 | +// Log.d(this.getClass().getName(), "startTime:" + startTime + "; distance:" + distance); | |
65 | + | |
53 | 66 | if (startTime == prevStartTime) { |
54 | 67 | // I need "select distinct"! |
55 | 68 | continue; |
@@ -100,35 +113,123 @@ public class RunningHistory extends ListActivity implements OnItemClickListener | ||
100 | 113 | super.onCreateContextMenu(menu, v, menuInfo); |
101 | 114 | menu.add(0, MENU_DELETE_THIS, 0, R.string.contextmenu_deletethis); |
102 | 115 | menu.add(0, MENU_DELETE_ALL, 0, R.string.contextmenu_deleteall); |
116 | + menu.add(0, MENU_SAVE_GPX, 0, R.string.contextmenu_save_gpx); | |
103 | 117 | } |
104 | 118 | |
105 | 119 | public boolean onContextItemSelected(MenuItem item) { |
106 | - AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo(); | |
107 | - ArrayAdapter<String> historyArray = (ArrayAdapter<String>)getListAdapter(); | |
108 | - int position = info.position; | |
120 | + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item | |
121 | + .getMenuInfo(); | |
122 | + ArrayAdapter<String> historyArray = (ArrayAdapter<String>) getListAdapter(); | |
123 | + int position = info.position; | |
124 | + String[] splitStr = historyArray.getItem(position).split(" "); | |
125 | + String dateStr = splitStr[0] + " " + splitStr[1]; | |
126 | + long startTime = 0; | |
127 | + try { | |
128 | + startTime = m_startTimeFormatter.parse(dateStr).getTime(); | |
129 | + startTime = m_startTimeMap.get(startTime); | |
130 | + } catch (ParseException e) { | |
131 | + e.printStackTrace(); | |
132 | + } | |
109 | 133 | switch (item.getItemId()) { |
110 | 134 | case MENU_DELETE_THIS: |
111 | - try { | |
112 | - String[] splitStr = historyArray.getItem(position).split(" "); | |
113 | - String dateStr = splitStr[0] + " " + splitStr[1]; | |
114 | - Date startTime = m_startTimeFormatter.parse(dateStr); | |
115 | - | |
116 | - String selection = RunningRecordProvider.START_TIME + " = ?"; | |
117 | - String[] selectionArgs = {Long.toString(startTime.getTime())}; | |
118 | - | |
119 | - getContentResolver().delete(RunningRecordProvider.REC_URI, selection, selectionArgs); | |
120 | - | |
121 | - historyArray.remove(historyArray.getItem(position)); | |
122 | - } catch (ParseException e) { | |
123 | - e.printStackTrace(); | |
124 | - } | |
125 | - return true; | |
135 | + | |
136 | + String selection = RunningRecordProvider.START_TIME + " = ?"; | |
137 | + String[] selectionArgs = { Long.toString(startTime) }; | |
138 | + | |
139 | + getContentResolver().delete(RunningRecordProvider.REC_URI, | |
140 | + selection, selectionArgs); | |
141 | + | |
142 | + historyArray.remove(historyArray.getItem(position)); | |
143 | + break; | |
126 | 144 | case MENU_DELETE_ALL: |
127 | - getContentResolver().delete(RunningRecordProvider.REC_URI, null, null); | |
145 | + getContentResolver().delete(RunningRecordProvider.REC_URI, null, | |
146 | + null); | |
128 | 147 | historyArray.clear(); |
129 | - return true; | |
148 | + break; | |
149 | + case MENU_SAVE_GPX: | |
150 | + saveRecordAsGpxFile(startTime); | |
151 | + break; | |
130 | 152 | default: |
131 | - return super.onContextItemSelected(item); | |
153 | + break; | |
154 | + } | |
155 | + return super.onContextItemSelected(item); | |
156 | + } | |
157 | + | |
158 | + private void saveRecordAsGpxFile(long startTime) { | |
159 | + String[] columns = { RunningRecordProvider.CURRENT_TIME, | |
160 | + RunningRecordProvider.LATITUDE, | |
161 | + RunningRecordProvider.LONGITUDE, | |
162 | + RunningRecordProvider.POINT_NAME }; | |
163 | + String selection = RunningRecordProvider.START_TIME + " = ?"; | |
164 | + String[] selectionArgs = { Long.toString(startTime) }; | |
165 | + String sortOrder = RunningRecordProvider.CURRENT_TIME + " asc"; | |
166 | + Cursor cursor = managedQuery(RunningRecordProvider.REC_URI, columns, | |
167 | + selection, selectionArgs, sortOrder); | |
168 | + if (cursor == null) { | |
169 | + return; | |
170 | + } | |
171 | + | |
172 | + SimpleDateFormat formatter = new SimpleDateFormat( | |
173 | + "yyyy-MM-dd_HH_mm_ss"); | |
174 | + String gpxFilePath = LOGDIR + formatter.format(new Date(startTime)) + ".xml"; | |
175 | + FileOutputStream gpxFile = null; | |
176 | + OutputStreamWriter stWriter = null; | |
177 | + try { | |
178 | + gpxFile = new FileOutputStream(gpxFilePath); | |
179 | + stWriter = new OutputStreamWriter(gpxFile); | |
180 | + stWriter | |
181 | + .write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
182 | + + "<gpx\n" | |
183 | + + " version=\"1.0\"\n" | |
184 | + + "creator=\"Tokyo Runners\"\n" | |
185 | + + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" | |
186 | + + "xmlns=\"http://www.topografix.com/GPX/1/0\"\n" | |
187 | + + "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n"); | |
188 | + | |
189 | + stWriter.write("<trk>\n" + "<trkseg>\n"); | |
190 | + | |
191 | + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); | |
192 | + SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss"); | |
193 | + | |
194 | + long currentTime = 0; | |
195 | + int latitude = 0; | |
196 | + int longitude = 0; | |
197 | + String pointName = ""; | |
198 | + | |
199 | + while (cursor.moveToNext()) { | |
200 | + currentTime = cursor.getLong(cursor | |
201 | + .getColumnIndex(RunningRecordProvider.CURRENT_TIME)); | |
202 | + latitude = cursor.getInt(cursor | |
203 | + .getColumnIndex(RunningRecordProvider.LATITUDE)); | |
204 | + longitude = cursor.getInt(cursor | |
205 | + .getColumnIndex(RunningRecordProvider.LONGITUDE)); | |
206 | + pointName = cursor.getString(cursor | |
207 | + .getColumnIndex(RunningRecordProvider.POINT_NAME)); | |
208 | + | |
209 | + stWriter.write("<trkpt lat=\"" + (((float)latitude) / 1E6) | |
210 | + + "\" lon=\"" + (((float)longitude) / 1E6) + "\">\n" + "<time>" | |
211 | + + dateFormat.format(currentTime) + "T" | |
212 | + + timeFormat.format(currentTime) + "Z</time>\n" | |
213 | + + "<speed>" + 0 + "</speed>\n" + "<name>" | |
214 | + + pointName + "</name>\n" + "<fix>none</fix>\n" | |
215 | + + "</trkpt>\n"); | |
216 | + | |
217 | + } | |
218 | + | |
219 | + stWriter.write("</trkseg>\n" + "</trk>\n" + "</gpx>\n"); | |
220 | + stWriter.flush(); | |
221 | + | |
222 | + } catch (IOException e) { | |
223 | + } finally { | |
224 | + try { | |
225 | + if (stWriter != null) { | |
226 | + stWriter.close(); | |
227 | + } | |
228 | + if (gpxFile != null) { | |
229 | + gpxFile.close(); | |
230 | + } | |
231 | + } catch (IOException e) { | |
232 | + } | |
132 | 233 | } |
133 | 234 | } |
134 | 235 |
@@ -9,6 +9,7 @@ import java.util.Iterator; | ||
9 | 9 | |
10 | 10 | import android.content.ContentResolver; |
11 | 11 | import android.content.ContentValues; |
12 | +import android.database.Cursor; | |
12 | 13 | import android.location.Location; |
13 | 14 | import android.util.Log; |
14 | 15 |
@@ -18,6 +19,7 @@ public class RunningRecord { | ||
18 | 19 | private Location m_prevLocation = null; |
19 | 20 | private int m_splitInterval = 0; |
20 | 21 | private int m_lastSplit = 0; |
22 | + private long m_startTime = 0; | |
21 | 23 | private String m_distanceUnit = "km"; |
22 | 24 | private ContentResolver m_contentResolver; |
23 | 25 |
@@ -27,26 +29,50 @@ public class RunningRecord { | ||
27 | 29 | public RunningRecord(ContentResolver contentResolver) { |
28 | 30 | m_contentResolver = contentResolver; |
29 | 31 | } |
30 | - public String addRecord(Date date, Location loc, String pointName) { | |
31 | - if (loc != null) { | |
32 | - Log.d(this.getClass().getName(), "Latitude:" + loc.getLatitude() + "; Longitude:" + loc.getLongitude()); | |
33 | - } | |
34 | - | |
32 | + public String addRecord(Date date, Location loc, String pointName, boolean persistent) { | |
33 | + // これまでの走行距離を計算 | |
35 | 34 | if (m_prevLocation != null && loc != null) { |
35 | + float distance = m_prevLocation.distanceTo(loc); | |
36 | + Log.d(this.getClass().getName(), "distance: " + distance); | |
36 | 37 | m_distance += m_prevLocation.distanceTo(loc); |
38 | + } else { | |
39 | + m_startTime = date.getTime(); | |
37 | 40 | } |
41 | + m_prevLocation = loc; | |
38 | 42 | |
43 | + // スプリットポイントを通過した場合 | |
39 | 44 | if (m_splitInterval > 0 && m_distance > m_lastSplit + m_splitInterval && pointName.length() == 0 ) { |
40 | 45 | pointName = getDistanceString() + m_distanceUnit; |
41 | 46 | m_lastSplit += m_splitInterval; |
42 | 47 | } |
43 | 48 | |
44 | - Record newRecord = new Record(date, loc, pointName); | |
49 | + // リストに記録を保持 | |
50 | + Record newRecord = new Record(date, loc, m_distance, pointName); | |
45 | 51 | m_recordList.add(newRecord); |
46 | 52 | |
47 | - m_prevLocation = loc; | |
53 | + // データベースに記録を保存 | |
54 | + if (persistent) { | |
55 | + ContentValues values = new ContentValues(); | |
56 | + values.put(RunningRecordProvider.START_TIME, m_startTime); | |
57 | + values.put(RunningRecordProvider.CURRENT_TIME, date.getTime()); | |
58 | + values.put(RunningRecordProvider.POINT_NAME, pointName); | |
59 | + values.put(RunningRecordProvider.DISTANCE, (int)m_distance); | |
60 | + values.put(RunningRecordProvider.LATITUDE, newRecord.getLatitudeE6()); | |
61 | + values.put(RunningRecordProvider.LONGITUDE, newRecord.getLongitudeE6()); | |
62 | + | |
63 | + try { | |
64 | + m_contentResolver.insert(RunningRecordProvider.REC_URI, values); | |
65 | + } catch (IllegalArgumentException e) { | |
66 | + Log.e(this.getClass().getName(), e.getMessage()); | |
67 | + } | |
68 | + | |
69 | + } | |
48 | 70 | |
49 | 71 | return pointName; |
72 | + | |
73 | + } | |
74 | + public String addRecord(Date date, Location loc, String pointName) { | |
75 | + return addRecord(date, loc, pointName, true); | |
50 | 76 | } |
51 | 77 | public Location getPrevLocation() { |
52 | 78 | return m_prevLocation; |
@@ -57,6 +83,7 @@ public class RunningRecord { | ||
57 | 83 | m_distance = 0; |
58 | 84 | m_lastSplit = 0; |
59 | 85 | m_prevLocation = null; |
86 | + m_startTime = 0; | |
60 | 87 | m_recordList.clear(); |
61 | 88 | } |
62 | 89 |
@@ -92,6 +119,7 @@ public class RunningRecord { | ||
92 | 119 | } |
93 | 120 | |
94 | 121 | public String getDistanceString() { |
122 | + // メートル以下を切り捨ててからキロメートルに変換 | |
95 | 123 | int distance_m = (int)m_distance; |
96 | 124 | return Float.toString((float)distance_m / 1000); |
97 | 125 | } |
@@ -142,22 +170,18 @@ public class RunningRecord { | ||
142 | 170 | |
143 | 171 | } |
144 | 172 | public void save() { |
145 | - long startTime = m_recordList.get(0).getTime(); | |
146 | - Location prevLocation = null; | |
147 | - int distance = 0; | |
148 | 173 | |
174 | + if (saved(m_startTime) == true) { | |
175 | + return; | |
176 | + } | |
177 | + | |
149 | 178 | for (Iterator<Record> it = m_recordList.iterator(); it.hasNext();) { |
150 | 179 | Record rec = (Record)it.next(); |
151 | 180 | ContentValues values = new ContentValues(); |
152 | - values.put(RunningRecordProvider.START_TIME, startTime); | |
181 | + values.put(RunningRecordProvider.START_TIME, m_startTime); | |
153 | 182 | values.put(RunningRecordProvider.CURRENT_TIME, rec.getTime()); |
154 | 183 | values.put(RunningRecordProvider.POINT_NAME, rec.getName()); |
155 | - if (rec.hasLocation()) { | |
156 | - if (prevLocation != null) { | |
157 | - distance += prevLocation.distanceTo(rec.getLocation()); | |
158 | - } | |
159 | - values.put(RunningRecordProvider.DISTANCE, distance); | |
160 | - } | |
184 | + values.put(RunningRecordProvider.DISTANCE, (int)rec.getDistance()); | |
161 | 185 | values.put(RunningRecordProvider.LATITUDE, rec.getLatitudeE6()); |
162 | 186 | values.put(RunningRecordProvider.LONGITUDE, rec.getLongitudeE6()); |
163 | 187 |
@@ -169,4 +193,15 @@ public class RunningRecord { | ||
169 | 193 | } |
170 | 194 | } |
171 | 195 | |
196 | + private boolean saved(long startTime) { | |
197 | + String[] columns = { RunningRecordProvider.CURRENT_TIME }; | |
198 | + String selection = RunningRecordProvider.START_TIME + " = ?"; | |
199 | + String[] selectionArgs = { Long.toString(startTime) }; | |
200 | + Cursor cursor = m_contentResolver.query(RunningRecordProvider.REC_URI, columns, | |
201 | + selection, selectionArgs, null); | |
202 | + | |
203 | + return (cursor != null && cursor.getCount() > 0); | |
204 | + | |
205 | + } | |
206 | + | |
172 | 207 | } |
@@ -71,7 +71,7 @@ public class RunningRecordProvider extends ContentProvider { | ||
71 | 71 | SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); |
72 | 72 | qb.setTables(TABLE_NAME); |
73 | 73 | Cursor c = qb.query(db, projection, selection, selectionArgs, null, |
74 | - null, null); | |
74 | + null, sortOrder); | |
75 | 75 | return c; |
76 | 76 | } |
77 | 77 |
@@ -9,15 +9,12 @@ import android.content.Context; | ||
9 | 9 | import android.content.DialogInterface; |
10 | 10 | import android.content.Intent; |
11 | 11 | import android.content.SharedPreferences; |
12 | -import android.content.pm.ActivityInfo; | |
13 | -import android.content.res.Resources; | |
14 | 12 | import android.database.Cursor; |
15 | 13 | import android.location.Location; |
16 | 14 | import android.location.LocationListener; |
17 | 15 | import android.location.LocationManager; |
18 | 16 | import android.location.LocationProvider; |
19 | 17 | import android.os.Bundle; |
20 | -import android.os.Debug; | |
21 | 18 | import android.os.SystemClock; |
22 | 19 | import android.preference.PreferenceManager; |
23 | 20 | import android.text.format.DateUtils; |
@@ -174,14 +171,17 @@ public class TokyoRunners extends TabActivity implements LocationListener { | ||
174 | 171 | RunningRecordProvider.POINT_NAME }; |
175 | 172 | String selection = RunningRecordProvider.START_TIME + " = ?"; |
176 | 173 | String[] selectionArgs = { Long.toString(startTime) }; |
177 | - String sortOrder = RunningRecordProvider.CURRENT_TIME + " desc"; | |
174 | + String sortOrder = RunningRecordProvider.CURRENT_TIME + " asc"; | |
178 | 175 | Cursor cursor = managedQuery(RunningRecordProvider.REC_URI, columns, |
179 | 176 | selection, selectionArgs, sortOrder); |
180 | 177 | if (cursor == null) { |
181 | 178 | return; |
182 | 179 | } |
180 | + | |
181 | + Log.d(this.getClass().getName(), "row count:" + cursor.getCount()); | |
183 | 182 | |
184 | 183 | reset(); |
184 | + | |
185 | 185 | ListView listLaptime = (ListView) findViewById(R.id.lap_history); |
186 | 186 | ArrayAdapter<String> lapHistory = (ArrayAdapter<String>) listLaptime |
187 | 187 | .getAdapter(); |
@@ -215,7 +215,8 @@ public class TokyoRunners extends TabActivity implements LocationListener { | ||
215 | 215 | loc.setLatitude((double) (latitude / 1E6)); |
216 | 216 | loc.setLongitude((double) (longitude / 1E6)); |
217 | 217 | } |
218 | - m_runningRecord.addRecord(new Date(currentTime), loc, pointName); | |
218 | + m_runningRecord.addRecord(new Date(currentTime), loc, pointName, false); | |
219 | + | |
219 | 220 | if (pointName.length() == 0) { |
220 | 221 | } else if (currentTime != startTime) { |
221 | 222 | StringBuffer strBuff = new StringBuffer(); |
@@ -261,43 +262,31 @@ public class TokyoRunners extends TabActivity implements LocationListener { | ||
261 | 262 | |
262 | 263 | @Override |
263 | 264 | public boolean onCreateOptionsMenu(Menu menu) { |
264 | - menu.add(Menu.NONE, Constants.MENU_SAVE, Menu.NONE, R.string.menu_save) | |
265 | - .setIcon(android.R.drawable.ic_menu_save); | |
266 | 265 | menu.add(Menu.NONE, Constants.MENU_HISTORY, Menu.NONE, |
267 | 266 | R.string.menu_history).setIcon(R.drawable.history2); |
268 | 267 | menu.add(Menu.NONE, Constants.MENU_SETTING, Menu.NONE, |
269 | 268 | R.string.menu_setting).setIcon( |
270 | 269 | android.R.drawable.ic_menu_preferences); |
271 | - | |
272 | 270 | return super.onCreateOptionsMenu(menu); |
273 | 271 | } |
272 | + @Override | |
273 | + public boolean onPrepareOptionsMenu(Menu menu) { | |
274 | + boolean enabled; | |
275 | + if (getTabHost().getCurrentTabTag().equals("stopwatch")) { | |
276 | + enabled = !m_running; | |
277 | + } else { | |
278 | + enabled = false; | |
279 | + } | |
280 | + menu.findItem(Constants.MENU_HISTORY).setEnabled(enabled); | |
281 | + | |
282 | + return super.onPrepareOptionsMenu(menu); | |
283 | + } | |
274 | 284 | |
275 | 285 | @Override |
276 | 286 | public Dialog onCreateDialog(int id) { |
277 | 287 | |
278 | 288 | AlertDialog.Builder builder = new AlertDialog.Builder(this); |
279 | 289 | switch (id) { |
280 | - case Constants.DIALOG_SAVE_ID: | |
281 | - builder.setTitle(R.string.dialog_save_title); | |
282 | - builder.setMessage(R.string.dialog_save_message); | |
283 | - builder.setPositiveButton(R.string.dialog_yes, | |
284 | - new DialogInterface.OnClickListener() { | |
285 | - @Override | |
286 | - public void onClick(DialogInterface dialog, int which) { | |
287 | - saveRecord(); | |
288 | - | |
289 | - } | |
290 | - }); | |
291 | - builder.setNegativeButton(R.string.dialog_no, | |
292 | - new DialogInterface.OnClickListener() { | |
293 | - @Override | |
294 | - public void onClick(DialogInterface dialog, int which) { | |
295 | - dialog.cancel(); | |
296 | - | |
297 | - } | |
298 | - }); | |
299 | - | |
300 | - break; | |
301 | 290 | case Constants.DIALOG_EXIT_ID: |
302 | 291 | builder.setTitle(R.string.dialog_exit_title); |
303 | 292 | builder.setMessage(R.string.dialog_exit_message); |
@@ -331,9 +320,6 @@ public class TokyoRunners extends TabActivity implements LocationListener { | ||
331 | 320 | public boolean onOptionsItemSelected(MenuItem item) { |
332 | 321 | Intent intent; |
333 | 322 | switch (item.getItemId()) { |
334 | - case Constants.MENU_SAVE: | |
335 | - showDialog(Constants.DIALOG_SAVE_ID); | |
336 | - break; | |
337 | 323 | case Constants.MENU_HISTORY: |
338 | 324 | intent = new Intent(this, RunningHistory.class); |
339 | 325 | intent.setAction(Intent.ACTION_VIEW); |
@@ -394,7 +380,7 @@ public class TokyoRunners extends TabActivity implements LocationListener { | ||
394 | 380 | distanceView.setText(m_runningRecord.getDistanceString()); |
395 | 381 | |
396 | 382 | // MapModeに通知 |
397 | - Intent intent = new Intent("RunningRecord"); | |
383 | + Intent intent = new Intent("NewRunningRecord"); | |
398 | 384 | intent.putExtra("RunningRecord", location.getTime()); |
399 | 385 | sendBroadcast(intent); |
400 | 386 |
@@ -467,16 +453,21 @@ public class TokyoRunners extends TabActivity implements LocationListener { | ||
467 | 453 | } |
468 | 454 | |
469 | 455 | private void reset() { |
456 | + m_runningRecord.clearRecord(); | |
457 | + | |
470 | 458 | long elapsedRealTime = SystemClock.elapsedRealtime(); |
471 | 459 | m_elapsedTime.setBase(elapsedRealTime); |
472 | 460 | m_lapTime.setBase(elapsedRealTime); |
473 | 461 | |
462 | + // 距離 | |
463 | + TextView distanceView = (TextView) findViewById(R.id.distance); | |
464 | + distanceView.setText(m_runningRecord.getDistanceString()); | |
465 | + | |
474 | 466 | ListView listLaptime = (ListView) findViewById(R.id.lap_history); |
475 | 467 | ArrayAdapter<String> lapHistory = (ArrayAdapter<String>) listLaptime |
476 | 468 | .getAdapter(); |
477 | 469 | lapHistory.clear(); |
478 | 470 | |
479 | - m_runningRecord.clearRecord(); | |
480 | 471 | } |
481 | 472 | |
482 | 473 | private String calculateSplitAndLap() { |
@@ -521,29 +512,13 @@ public class TokyoRunners extends TabActivity implements LocationListener { | ||
521 | 512 | |
522 | 513 | } |
523 | 514 | |
524 | - private void saveRecord() { | |
525 | - if (m_running) { | |
526 | - return; | |
527 | - } | |
528 | - m_runningRecord.save(); | |
529 | - | |
530 | - } | |
531 | - | |
532 | 515 | @Override |
533 | 516 | public boolean dispatchKeyEvent(KeyEvent event) { |
534 | - Log.d(this.getClass().getName(), "dispatchKeyEvent():" | |
535 | - + event.toString()); | |
536 | - /* | |
537 | - * if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER && | |
538 | - * event.getAction() == KeyEvent.ACTION_DOWN) { if (m_running == true) { | |
539 | - * stop(); } else { start(); } } | |
540 | - */ | |
541 | 517 | return super.dispatchKeyEvent(event); |
542 | 518 | } |
543 | 519 | |
544 | 520 | @Override |
545 | 521 | public boolean onKeyDown(int keyCode, KeyEvent event) { |
546 | - Log.d(this.getClass().getName(), "onKeyDown():" + keyCode); | |
547 | 522 | if (keyCode == KeyEvent.KEYCODE_BACK) { |
548 | 523 | showDialog(Constants.DIALOG_EXIT_ID); |
549 | 524 | return true; |