/[projects]/android/TrainInfo/src/dk/thoerup/traininfo/StationList.java
ViewVC logotype

Contents of /android/TrainInfo/src/dk/thoerup/traininfo/StationList.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 919 - (show annotations) (download)
Sat Jun 26 11:06:12 2010 UTC (13 years, 10 months ago) by torben
File size: 17438 byte(s)
More shutdown if destroyed
1 package dk.thoerup.traininfo;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6
7 import android.app.Activity;
8 import android.app.AlertDialog;
9 import android.app.Dialog;
10 import android.app.ListActivity;
11 import android.app.ProgressDialog;
12 import android.content.DialogInterface;
13 import android.content.Intent;
14 import android.content.SharedPreferences;
15 import android.content.SharedPreferences.Editor;
16 import android.location.Location;
17 import android.os.AsyncTask;
18 import android.os.Bundle;
19 import android.os.Handler;
20 import android.os.Message;
21
22 import android.util.Log;
23 import android.view.ContextMenu;
24 import android.view.LayoutInflater;
25 import android.view.Menu;
26 import android.view.MenuItem;
27 import android.view.View;
28 import android.view.ContextMenu.ContextMenuInfo;
29 import android.view.View.OnCreateContextMenuListener;
30 import android.widget.AdapterView;
31 import android.widget.EditText;
32 import android.widget.ListView;
33 import android.widget.Toast;
34 import dk.thoerup.traininfo.provider.ProviderFactory;
35 import dk.thoerup.traininfo.provider.StationProvider;
36 import dk.thoerup.traininfo.stationmap.GeoPair;
37 import dk.thoerup.traininfo.stationmap.StationMapView;
38 import dk.thoerup.traininfo.util.IntSet;
39 import dk.thoerup.traininfo.util.MessageBox;
40
41 import static dk.thoerup.traininfo.R.string.*;
42
43 public class StationList extends ListActivity {
44 public static final int GOTLOCATION = 1001;
45 public static final int GOTSTATIONLIST = 1002;
46 public static final int NOPROVIDER = 1003;
47 public static final int LOCATIONFIXTIMEOUT = 1004;
48
49 public static final int OPTIONS_MAP = 2003;
50 public static final int OPTIONS_GPSINFO = 2004;
51
52
53
54
55 public static final int DLG_PROGRESS = 3001;
56 public static final int DLG_STATIONNAME = 3002;
57
58 static enum LookupMethod {
59 ByLocation,
60 ByName,
61 ByList,
62 MethodNone
63 }
64
65
66 String dialogMessage = "";
67 ProgressDialog dialog;
68 LocationLookup locationLookup = null;
69 FindStationsTask findStationsTask;
70 StationsFetchedHandler stationsFetched = new StationsFetchedHandler();
71
72 GeoPair location = new GeoPair();
73
74 boolean isLaunchedforShortcut;
75 boolean isRunning = false;
76 List<StationBean> stations = new ArrayList<StationBean>();
77
78 StationProvider stationProvider = ProviderFactory.getStationProvider();
79
80 StationListAdapter adapter = null;
81
82 FavoritesMenu contextMenu = new FavoritesMenu();
83 IntSet favorites = new IntSet();
84
85 WelcomeScreen.ListType listType;
86 SharedPreferences prefs;
87
88 ///////////////////////////////////////////////////////////////////////////////////////////
89 //Activity call backs
90
91 @SuppressWarnings("unchecked")
92 @Override
93 public void onCreate(Bundle savedInstanceState) {
94 super.onCreate(savedInstanceState);
95 setContentView(R.layout.stationlist);
96
97
98 adapter = new StationListAdapter(this);
99 setListAdapter(adapter);
100
101 ListView lv = getListView();
102 lv.setOnCreateContextMenuListener(contextMenu);
103
104 locationLookup = new LocationLookup(this, stationsFetched);
105
106
107 prefs = getSharedPreferences("TrainStation", 0);
108 String favoriteString = prefs.getString("favorites", "");
109 if (! favoriteString.equals("") ) {
110 favorites.fromString(favoriteString);
111 }
112
113 listType = (WelcomeScreen.ListType) getIntent().getSerializableExtra("type");
114 setTitle();
115
116 isLaunchedforShortcut = getIntent().getBooleanExtra("shortcut", false);
117
118 if (savedInstanceState == null) {
119
120
121 switch (listType) {
122 case ListNearest:
123 startLookup();
124 break;
125 case ListSearch:
126 this.showDialogSafe(DLG_STATIONNAME);
127 break;
128 case ListFavorites:
129 startFavoriteLookup();
130 break;
131 default:
132 // Not possible !?!
133 }
134
135 } else {
136 stations = (ArrayList<StationBean>) savedInstanceState.getSerializable("stations");
137 adapter.setStations(stations);
138 location = (GeoPair) savedInstanceState.getSerializable("location");
139 }
140
141 }
142
143
144 @Override
145 protected void onDestroy() {
146 super.onDestroy();
147
148 if (findStationsTask != null) {
149 findStationsTask.cancel(true);
150 }
151 if (locationLookup != null) {
152 locationLookup.stopSearch();
153 }
154 isRunning = false;
155 }
156
157
158 protected void setTitle() {
159 String dialogTitle = getResources().getString(app_name);
160 switch (listType) {
161 case ListNearest:
162 dialogTitle += " - " + getString(stationlist_nearbystations);
163 break;
164 case ListSearch:
165 dialogTitle += " - " + getString(stationlist_search);
166 break;
167 case ListFavorites:
168 dialogTitle += " - " + getString(stationlist_favorites);
169 break;
170 default:
171 dialogTitle = "";//not possible
172 }
173
174 setTitle(dialogTitle);
175
176 }
177
178
179 /* these 3 dialogs helper functions are very rude and ugly hack
180 * to remove these auto-reported exceptions
181 * - android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@436aaef8 is not valid; is your activity running?
182 * - java.lang.IllegalArgumentException: View not attached to window manager
183 */
184
185 public void showDialogSafe(int id) {
186 try {
187 showDialog(id);
188 } catch (Exception e) {
189 Log.e("StationList", "showDialog failed", e);
190 }
191 }
192
193 public void dismissDialogSafe(int id) {
194 try {
195 dismissDialog(id);
196 } catch (Exception e) {
197 Log.e("StationList", "dismissDialog failed", e);
198 }
199 }
200 public void dismissDialogSafe(Dialog dlg) {
201 try {
202 dlg.dismiss();
203 } catch (Exception e) {
204 Log.e("StationList", "dismissDialog failed", e);
205 }
206 }
207
208 public void builderShowSafe(AlertDialog.Builder builder) {
209 try {
210 builder.show();
211 } catch (Exception e) {
212 Log.e("StationList", "builder.show() failed", e);
213 }
214
215 }
216 /* EOF rude and ugly dialog hack */
217
218
219
220 @Override
221 public void onSaveInstanceState(Bundle outState)
222 {
223 if (dialog != null && dialog.isShowing())
224 dialog.dismiss();
225 outState.putSerializable("stations", (ArrayList<StationBean>) stations);
226 outState.putSerializable("location", location);
227
228 }
229
230
231
232 @Override
233 public boolean onCreateOptionsMenu(Menu menu) {
234 MenuItem item;
235
236 item = menu.add(0, OPTIONS_MAP, 0, getString(stationlist_stationmap));
237 item.setIcon(android.R.drawable.ic_menu_mapmode);
238
239 item = menu.add(0, OPTIONS_GPSINFO, 0, getString(stationlist_gpsinfo));
240 item.setIcon(android.R.drawable.ic_menu_mapmode);
241
242 return true;
243 }
244
245 @Override
246 public boolean onOptionsItemSelected(MenuItem item) {
247 boolean retval = true;
248
249 //TODO: Cleanup
250 switch (item.getItemId()) {
251 case OPTIONS_MAP:
252
253 Intent intent = new Intent(this,StationMapView.class);
254
255 ArrayList<GeoPair> stationPoints = new ArrayList<GeoPair>();
256 for (StationBean st : stations ) {
257 stationPoints.add( new GeoPair(st.getLatitude(), st.getLongitude(), st.getName()) );
258 }
259
260 intent.putExtra("stations", stationPoints);
261
262 startActivity(intent);
263 break;
264 case OPTIONS_GPSINFO:
265 Location loc = locationLookup.getLocation();
266 StringBuffer message = new StringBuffer();
267 message.append( getString(stationlist_locationinfo) ).append(":\n");
268 if (loc != null) {
269 message.append( getString(stationlist_obtainedby) ).append( loc.getProvider() ).append("\n");
270 message.append( getString(stationlist_accuracy) ).append( (int)loc.getAccuracy()).append("m\n");
271 message.append( getString(stationlist_latitude) ).append( (float)loc.getLatitude()).append("\n");
272 message.append( getString(stationlist_longitude) ).append( (float)loc.getLongitude() ).append("\n");
273 } else {
274 message.append( getString(stationlist_nolocation) );
275 }
276
277 MessageBox.showMessage(this, message.toString(), false);
278 break;
279 default:
280 retval = super.onOptionsItemSelected(item);
281 }
282
283 return retval;
284 }
285
286
287
288 @Override
289 public boolean onContextItemSelected(MenuItem item) {
290 contextMenu.onContextItemSelected(item);
291 return true;
292
293
294 }
295
296 public void showMessageAndClose(String message) {
297 AlertDialog.Builder builder = new AlertDialog.Builder(this);
298 builder.setMessage(message)
299 .setCancelable(false)
300 .setPositiveButton("OK", new DialogInterface.OnClickListener() {
301 public void onClick(DialogInterface dialog, int id) {
302 dialog.dismiss();
303 StationList.this.finish();
304 }
305 })
306 .show();
307 }
308
309
310
311
312 @Override
313 protected Dialog onCreateDialog(int id) {
314 switch (id) {
315 case DLG_PROGRESS:
316 ProgressDialog dlg = new ProgressDialog(this);
317 dlg.setMessage( getString(stationlist_waitforlocation) );
318 dlg.setCancelable(false);
319 return dlg;
320 case DLG_STATIONNAME:
321 LayoutInflater factory = LayoutInflater.from(this);
322 final View rootView = factory.inflate(R.layout.textinput, null);
323
324
325 AlertDialog.Builder builder = new AlertDialog.Builder(this);
326
327 builder.setTitle( getString(stationlist_stationsearch) );
328 builder.setView(rootView);
329 builder.setCancelable(true);
330 builder.setPositiveButton( getString(generic_search), new DialogInterface.OnClickListener() {
331 public void onClick(DialogInterface dialog, int which) {
332 EditText et = (EditText) rootView.findViewById(R.id.EditText);
333 dialog.dismiss();
334 String search = et.getText().toString().trim();
335 if (search.length() >= 2) {
336 startNameSearch(search);
337 } else {
338 showMessageAndClose( getString(stationlist_twocharmin) );
339 }
340 }
341 });
342 builder.setNegativeButton(getString(generic_cancel), new DialogInterface.OnClickListener() {
343 public void onClick(DialogInterface dialog, int which) {
344 dialog.dismiss();
345 StationList.this.finish(); // Close this Activity
346 }
347 });
348 return builder.create();
349
350 default:
351 return super.onCreateDialog(id);
352 }
353
354 }
355
356
357 @Override
358 protected void onPrepareDialog(int id, Dialog dialog) {
359 super.onPrepareDialog(id, dialog);
360 switch (id) {
361 case DLG_PROGRESS:
362 this.dialog = (ProgressDialog) dialog;
363 if (!dialogMessage.equals("")) {
364 this.dialog.setMessage(dialogMessage);
365 dialogMessage = "";
366 }
367 break;
368 }
369 }
370
371 @Override
372 protected void onListItemClick(ListView l, View v, int position, long id) {
373 super.onListItemClick(l, v, position, id);
374
375 StationBean station = stations.get(position);
376
377 if (isLaunchedforShortcut == true) {
378 Intent i = new Intent();
379 i.putExtra("station", station);
380 setResult(Activity.RESULT_OK, i);
381 finish();
382 } else {
383 Intent intent = new Intent(this, DepartureList.class);
384 intent.putExtra("stationbean", station);
385 startActivity(intent);
386 }
387 }
388
389 /////////////////////////////////////////////////////////////
390 //
391
392 public void startLookup() {
393 isRunning = true;
394 dialogMessage = getString( stationlist_waitforlocation );
395 showDialogSafe(DLG_PROGRESS);
396
397 locationLookup.locateStations();
398 stationsFetched.sendEmptyMessageDelayed(LOCATIONFIXTIMEOUT, 20000);
399 }
400
401 void startNameSearch(String name) {
402 dialogMessage = getString( stationlist_findbyname );
403 showDialogSafe(DLG_PROGRESS);
404
405 findStationsTask = new FindStationsTask();
406 findStationsTask.searchByName(name);
407 findStationsTask.execute();
408
409 }
410
411 public void startFavoriteLookup() {
412
413 if (favorites.size() > 0) {
414 dialogMessage = getString( stationlist_loadfavorites );
415 showDialogSafe(DLG_PROGRESS);
416
417 findStationsTask = new FindStationsTask();
418 findStationsTask.searchByIds( favorites.toString() );
419 findStationsTask.execute();
420 } else {
421 showMessageAndClose( getString( stationlist_nofavorites ) );
422 }
423 }
424
425
426
427 void startLocatorTask()
428 {
429 dialogMessage = getString( stationlist_findingnearby );
430 showDialogSafe(DLG_PROGRESS);
431
432 findStationsTask = new FindStationsTask();
433 findStationsTask.searchByLocation( locationLookup.getLocation() );
434 findStationsTask.execute();
435 }
436
437
438 ////////////////////////////////////////////////////////////////////////////
439 // Inner classes
440
441 class StationsFetchedHandler extends Handler {
442 @Override
443 public void handleMessage(Message msg) {
444
445 switch (msg.what) {
446 case GOTLOCATION:
447 dismissDialogSafe(DLG_PROGRESS);
448
449 startLocatorTask();
450 location = GeoPair.fromLocation( locationLookup.getLocation() );
451
452 break;
453
454 case NOPROVIDER:
455 dismissDialogSafe(DLG_PROGRESS);
456 MessageBox.showMessage(StationList.this, getString(stationlist_nolocationprovider), true );
457 //StationList.this.finish();
458 break;
459 case LOCATIONFIXTIMEOUT:
460 if (isRunning) {
461 locationLookup.stopSearch();
462 if (locationLookup.hasLocation()) {
463 stationsFetched.sendEmptyMessage( GOTLOCATION );
464 } else {
465 dismissDialogSafe(DLG_PROGRESS);
466
467 AlertDialog.Builder builder = new AlertDialog.Builder(StationList.this);
468 builder.setMessage( getString( stationlist_gpstimeout) );
469 builder.setCancelable(true);
470 builder.setPositiveButton(getString(generic_retry), new DialogInterface.OnClickListener() {
471 public void onClick(DialogInterface dialog, int id) {
472 dialog.dismiss();
473 startLookup();
474
475 }
476 });
477 builder.setNegativeButton( getString(generic_cancel), new DialogInterface.OnClickListener() {
478 public void onClick(DialogInterface dialog, int id) {
479 dialog.dismiss();
480 }
481 });
482 builderShowSafe(builder); // builder.show()
483
484 }
485 }
486 break;
487 }
488 isRunning = false;
489 }
490 };
491
492
493 class FindStationsTask extends AsyncTask<Void,Void,Void> {
494
495 LookupMethod method = LookupMethod.MethodNone;
496 boolean success;
497 String name;
498 Location loc;
499 String ids;
500
501 public void searchByName(String n) {
502
503 method = LookupMethod.ByName;
504 name = n;
505 }
506
507 public void searchByLocation(Location l) {
508 method = LookupMethod.ByLocation;
509 loc = l;
510 }
511
512 public void searchByIds(String id) {
513
514 method = LookupMethod.ByList;
515 ids = id;
516 }
517
518 @Override
519 protected void onPreExecute() {
520
521 if (method.equals(LookupMethod.MethodNone))
522 throw new RuntimeException("Method not set");
523 super.onPreExecute();
524 }
525
526 @Override
527 protected Void doInBackground(Void... params) {
528
529 switch (method) {
530 case ByLocation:
531 success = stationProvider.lookupStations(loc);
532 break;
533 case ByName:
534 success = stationProvider.lookupStationsByName(name);
535 break;
536 case ByList:
537 success = stationProvider.lookupStationsByIds(ids);
538 break;
539 default:
540 success = false; // not possible
541 }
542
543
544 return null;
545 }
546
547 @Override
548 protected void onPostExecute(Void result) {
549 super.onPostExecute(result);
550 dismissDialogSafe(dialog);
551
552
553 if (success) {
554 if (stationProvider.getStations().size() == 0) {
555 showMessageAndClose(getString(stationlist_nostations));
556 }
557 stations = stationProvider.getStations();
558
559 StationList.this.getListView().invalidateViews();
560 adapter.setStations( stations );
561
562
563 } else { //communication or parse errors
564 AlertDialog.Builder builder = new AlertDialog.Builder(StationList.this);
565 builder.setMessage(getString(stationlist_fetcherror));
566 builder.setCancelable(true);
567 builder.setPositiveButton(getString(generic_retry), new DialogInterface.OnClickListener() {
568 public void onClick(DialogInterface dialog, int id) {
569 dialog.dismiss();
570
571 Runnable runner = null;
572 switch (method) {
573 case ByLocation:
574 runner = new Runnable() {
575 @Override
576 public void run() {
577 startLocatorTask();
578 }
579 };
580 break;
581 case ByName:
582 runner = new Runnable() {
583 @Override
584 public void run() {
585 startNameSearch( FindStationsTask.this.name );
586 }
587 };
588 break;
589 case ByList:
590 runner = new Runnable() {
591 @Override
592 public void run() {
593 startFavoriteLookup();
594 }
595 };
596 break;
597 }
598
599 stationsFetched.post( runner );
600 }
601 });
602 builder.setNegativeButton(getString(generic_cancel), new DialogInterface.OnClickListener() {
603 public void onClick(DialogInterface dialog, int id) {
604 dialog.dismiss();
605 StationList.this.finish();
606 }
607 });
608
609 builderShowSafe(builder); // builder.show()
610 }
611 }
612 }
613
614
615 class FavoritesMenu implements OnCreateContextMenuListener {
616 private final static int FAVORITES_ADD = 9001;
617 private final static int FAVORITES_REMOVE = 9002;
618
619 private int selectedPosition;
620
621
622 @Override
623 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
624
625 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
626 selectedPosition = info.position;
627 int stationID = stations.get(selectedPosition).getId();
628
629 if (!favorites.contains(stationID)) {
630 menu.add(0, FAVORITES_ADD, 0, getString(stationlist_addfavorite) );
631 } else {
632 menu.add(0, FAVORITES_REMOVE, 0, getString(stationlist_removefavorite) );
633 }
634
635 }
636
637 public void onContextItemSelected(MenuItem item) {
638 StationBean sb = stations.get(selectedPosition);
639
640 int stationID = sb.getId();
641 if (item.getItemId() == FAVORITES_ADD) {
642 favorites.add(stationID);
643 Toast.makeText(StationList.this, getString(stationlist_stationadded), Toast.LENGTH_SHORT).show();
644 } else {
645
646 favorites.remove(stationID);
647 Toast.makeText(StationList.this, getString(stationlist_stationremoved), Toast.LENGTH_SHORT).show();
648
649
650 if (listType.equals( WelcomeScreen.ListType.ListFavorites) ) {
651 stations.remove(selectedPosition);
652 adapter.notifyDataSetChanged();
653 }
654 }
655 Editor ed = prefs.edit();
656 ed.putString("favorites", favorites.toString());
657 ed.commit();
658 }
659 }
660 }

  ViewVC Help
Powered by ViewVC 1.1.20