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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1487 - (show annotations) (download)
Sat May 28 17:47:01 2011 UTC (12 years, 11 months ago) by torben
File size: 19742 byte(s)
Fix another NPE
1 package dk.thoerup.traininfo;
2
3 import static dk.thoerup.traininfo.R.string.departurelist_fetcharrivals;
4 import static dk.thoerup.traininfo.R.string.departurelist_fetchdepartures;
5 import static dk.thoerup.traininfo.R.string.generic_cancel;
6 import static dk.thoerup.traininfo.R.string.generic_retry;
7
8 import java.text.NumberFormat;
9
10 import android.app.AlertDialog;
11 import android.app.Dialog;
12 import android.app.ListActivity;
13 import android.app.ProgressDialog;
14 import android.content.ActivityNotFoundException;
15 import android.content.DialogInterface;
16 import android.content.Intent;
17 import android.content.SharedPreferences;
18 import android.graphics.Typeface;
19 import android.net.Uri;
20 import android.os.AsyncTask;
21 import android.os.Bundle;
22 import android.preference.PreferenceManager;
23 import android.util.Log;
24 import android.view.Menu;
25 import android.view.MenuItem;
26 import android.view.View;
27 import android.view.View.OnClickListener;
28 import android.widget.Button;
29 import android.widget.ListView;
30 import android.widget.TableLayout;
31 import android.widget.TableRow;
32 import android.widget.TextView;
33 import android.widget.Toast;
34 import dk.thoerup.android.traininfo.common.DepartureBean;
35 import dk.thoerup.android.traininfo.common.DepartureEntry;
36 import dk.thoerup.android.traininfo.common.MetroBean;
37 import dk.thoerup.android.traininfo.common.MetroBean.MetroEntry;
38 import dk.thoerup.android.traininfo.common.StationEntry;
39 import dk.thoerup.traininfo.provider.DepartureProvider;
40 import dk.thoerup.traininfo.provider.MetroProvider;
41 import dk.thoerup.traininfo.provider.ProviderFactory;
42 import dk.thoerup.traininfo.util.MessageBox;
43
44 public class DepartureList extends ListActivity {
45
46 public static final int DLG_PROGRESS = 1;
47 static final int MENU_MAP = 100;
48 static final int MENU_NOTIFICATIONS = 101;
49 static final int MENU_METROMAP = 102;
50 static final int MENU_TOGGLEDETAILS= 103;
51
52
53 DepartureListAdapter adapter;
54 DepartureProvider provider;
55 DepartureBean departures;
56
57 MetroBean metroBean;
58 MetroProvider metro;
59
60 int selectedItemId;
61 //DepartureBean currentDeparture;
62
63 ProgressDialog pgDialog;
64
65 DepartureFetcher fetcher;
66 MetroFetcher metroFetcher;
67
68 StationEntry station;
69
70 String trainType = "REGIONAL";
71
72 boolean arrival = false;
73
74 int commFailCounter = 0;
75
76 @Override
77 protected void onCreate(Bundle savedInstanceState) {
78 super.onCreate(savedInstanceState);
79 setContentView(R.layout.departurelist);
80
81 adapter = new DepartureListAdapter(this);
82 setListAdapter(adapter);
83
84 Intent launchedBy = getIntent();
85
86 station = (StationEntry) launchedBy.getSerializableExtra("stationbean");
87
88 ((TextView) findViewById(R.id.stationName)).setText( station.getName() );
89
90
91 ((TextView) findViewById(R.id.stationAddr)).setText( station.getAddress() );
92
93 final Button departureBtn = (Button) findViewById(R.id.departurebtn);
94 final Button arrivalBtn = (Button) findViewById(R.id.arrivalbtn);
95 final Button metroBtn = (Button) findViewById(R.id.metrobtn);
96 final Button regionalBtn = (Button) findViewById(R.id.regionalbtn);
97 final Button stogBtn = (Button) findViewById(R.id.stogbtn);
98
99 final View metroView = findViewById(R.id.metroonly);
100
101 departureBtn.setOnClickListener( new OnClickListener() {
102 @Override
103 public void onClick(View arg0) {
104 arrivalBtn.setBackgroundResource(R.drawable.custom_button);
105 departureBtn.setBackgroundResource(R.drawable.custom_button_hilight);
106 metroBtn.setBackgroundResource(R.drawable.custom_button);
107
108 getListView().setVisibility( View.VISIBLE );
109 metroView.setVisibility( View.GONE );
110 arrival = false;
111 startDepartureFetcher();
112 }
113 });
114 arrivalBtn.setOnClickListener( new OnClickListener() {
115 @Override
116 public void onClick(View arg0) {
117 arrivalBtn.setBackgroundResource(R.drawable.custom_button_hilight);
118 departureBtn.setBackgroundResource(R.drawable.custom_button);
119 metroBtn.setBackgroundResource(R.drawable.custom_button);
120
121 getListView().setVisibility( View.VISIBLE );
122 metroView.setVisibility( View.GONE );
123 arrival = true;
124 startDepartureFetcher();
125 }
126 });
127
128 regionalBtn.setOnClickListener( new OnClickListener() {
129 @Override
130 public void onClick(View arg0) {
131 regionalBtn.setBackgroundResource(R.drawable.custom_button_hilight);
132 stogBtn.setBackgroundResource(R.drawable.custom_button);
133 metroBtn.setBackgroundResource(R.drawable.custom_button);
134
135 departureBtn.setVisibility( View.VISIBLE );
136 arrivalBtn.setVisibility( View.VISIBLE );
137
138 getListView().setVisibility( View.VISIBLE );
139 metroView.setVisibility( View.GONE );
140 trainType = "REGIONAL";
141 startDepartureFetcher();
142 }
143 });
144 stogBtn.setOnClickListener( new OnClickListener() {
145 @Override
146 public void onClick(View arg0) {
147 regionalBtn.setBackgroundResource(R.drawable.custom_button);
148 stogBtn.setBackgroundResource(R.drawable.custom_button_hilight);
149 metroBtn.setBackgroundResource(R.drawable.custom_button);
150
151
152 departureBtn.setVisibility( View.VISIBLE );
153 arrivalBtn.setVisibility( View.VISIBLE );
154
155 getListView().setVisibility( View.VISIBLE );
156 metroView.setVisibility( View.GONE );
157 trainType = "STOG";
158 startDepartureFetcher();
159 }
160 });
161
162
163
164 metroBtn.setOnClickListener( new OnClickListener() {
165 @Override
166 public void onClick(View v) {
167 regionalBtn.setBackgroundResource(R.drawable.custom_button);
168 stogBtn.setBackgroundResource(R.drawable.custom_button);
169 metroBtn.setBackgroundResource(R.drawable.custom_button_hilight);
170
171 departureBtn.setVisibility( View.GONE );
172 arrivalBtn.setVisibility( View.GONE );
173
174 getListView().setVisibility( View.GONE );
175 metroView.setVisibility( View.VISIBLE );
176 startMetroFetcher();
177 }
178 });
179
180
181
182
183 // findViewById(R.id.header).setOnClickListener( mapLauncher );
184
185 int distance = station.getCalcdist();
186 if (distance != 0) {
187 NumberFormat format = NumberFormat.getNumberInstance();
188 format.setMaximumFractionDigits(1);
189 format.setMinimumFractionDigits(1);
190
191 ((TextView) findViewById(R.id.stationDistance)).setText( format.format((double)distance/1000.0) + " km." );
192 } else {
193 ((TextView) findViewById(R.id.stationDistance)).setVisibility(View.GONE);
194 }
195
196 ProviderFactory.purgeOldEntries(); //cleanup before fetching more data
197
198 Log.e("Station", station.toCSV() );
199
200
201
202 if (station.isMetro() == false) {
203 metroBtn.setVisibility( View.GONE );
204 }
205
206 metro = ProviderFactory.getMetroProvider();
207
208 if (station.isRegional() == false ) {
209 regionalBtn.setVisibility(View.GONE);
210 }
211
212 if (station.isStrain() == false ) {
213 stogBtn.setVisibility(View.GONE);
214 }
215
216 if (station.isRegional() == true && station.isStrain() == false ) {
217 if ( station.isMetro() == false )
218 regionalBtn.setVisibility(View.GONE);
219 trainType = "REGIONAL";
220 }
221
222 if (station.isRegional() == false && station.isStrain() == true) {
223 if (station.isMetro() == false)
224 stogBtn.setVisibility(View.GONE);
225
226 stogBtn.setBackgroundResource(R.drawable.custom_button_hilight);
227 trainType = "STOG";
228
229 }
230 //Both enabled - use preferred from preferences
231 if (station.isRegional() == true && station.isStrain() == true ) {
232 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
233 trainType = prefs.getString("traintype", "REGIONAL"); //default value is gps
234
235 if (trainType.equals("STOG") ) {
236 stogBtn.setBackgroundResource(R.drawable.custom_button_hilight);
237 regionalBtn.setBackgroundResource(R.drawable.custom_button);
238 }
239 }
240
241
242 if (station.isRegional() == false && station.isStrain() == false) {
243 getListView().setVisibility( View.GONE );
244 metroView.setVisibility( View.VISIBLE );
245
246 departureBtn.setVisibility( View.GONE );
247 arrivalBtn.setVisibility(View.GONE);
248 metroBtn.setVisibility( View.GONE );
249
250
251
252 if (savedInstanceState == null) {
253 startMetroFetcher();
254 } else {
255 metroBean = (MetroBean) savedInstanceState.getSerializable("metro");
256 loadMetroData();
257 }
258
259 } else {
260 provider = ProviderFactory.getDepartureProvider();
261
262 if (savedInstanceState == null) {
263 startDepartureFetcher();
264 } else {
265 departures = (DepartureBean) savedInstanceState.getSerializable("departures");
266
267 if ( (departures != null) && (departures.entries != null) ) {
268 adapter.setDepartures(departures.entries);
269 }
270 selectedItemId = savedInstanceState.getInt("selectedItemId");
271
272 if ( hasNotifications() ) {
273 findViewById(R.id.notifIcon).setVisibility(View.VISIBLE);
274 }
275
276 }
277 }
278 }
279
280
281
282 boolean hasNotifications() {
283 return (departures != null && departures.notifications.size() > 0);
284 }
285
286 @Override
287 public void onSaveInstanceState(Bundle outState)
288 {
289 if (pgDialog != null && pgDialog.isShowing())
290 dismissDialog(DLG_PROGRESS);
291
292 outState.putInt("selectedItemId", selectedItemId);
293
294 outState.putSerializable("departures", departures);
295 outState.putSerializable("metro", metroBean);
296 }
297
298
299
300 @Override
301 protected void onDestroy() {
302 super.onDestroy();
303
304 if (fetcher != null) {
305 fetcher.cancel(true);
306 }
307
308 if (metroFetcher != null) {
309 metroFetcher.cancel(true);
310 }
311 }
312
313 @Override
314 protected void onListItemClick(ListView l, View v, int position, long id) {
315 super.onListItemClick(l, v, position, id);
316
317 //how can this happen ??
318 if (departures == null || departures.entries == null || departures.entries.size() == 0) {
319 Toast.makeText(this, "No departures in list ?!?", Toast.LENGTH_LONG).show(); //TODO: translate
320 return;
321 }
322
323 selectedItemId = position;
324
325 DepartureEntry dep = departures.entries.get(selectedItemId);
326
327 Intent intent = new Intent(this, TimetableList.class);
328 intent.putExtra("departure", dep);
329
330 startActivity(intent);
331
332 }
333
334
335 @Override
336 protected void onPrepareDialog(int id, Dialog dialog) {
337 super.onPrepareDialog(id, dialog);
338
339 switch (id) {
340 case DLG_PROGRESS:
341 pgDialog = (ProgressDialog) dialog;
342 int messageId = arrival == false ? departurelist_fetchdepartures : departurelist_fetcharrivals;
343 pgDialog.setMessage( getString(messageId) );
344 break;
345 }
346 }
347
348 @Override
349 protected Dialog onCreateDialog(int id) {
350 switch (id) {
351 case DLG_PROGRESS:
352
353 ProgressDialog dlg = new ProgressDialog(this);
354 dlg.setCancelable(true);
355 return dlg;
356 default:
357 return super.onCreateDialog(id);
358 }
359 }
360
361
362
363 @Override
364 public boolean onPrepareOptionsMenu(Menu menu) {
365 super.onPrepareOptionsMenu(menu);
366
367 MenuItem item = menu.findItem( MENU_NOTIFICATIONS );
368 boolean notifEnabled = hasNotifications();
369 item.setEnabled(notifEnabled);
370
371 return true;
372 }
373
374 @Override
375 public boolean onCreateOptionsMenu(Menu menu) {
376 MenuItem item;
377
378
379 item = menu.add(0, MENU_TOGGLEDETAILS, 0, getString(R.string.departurelist_toggledetails));
380 item.setIcon(android.R.drawable.ic_menu_view);
381
382 item = menu.add(0, MENU_MAP, 0, getString(R.string.departurelist_showonmap) );
383 item.setIcon(android.R.drawable.ic_menu_mapmode);
384
385 item = menu.add(0, MENU_NOTIFICATIONS, 0, getString(R.string.departurelist_notifications) );
386 item.setIcon(android.R.drawable.ic_menu_info_details);
387
388 boolean notifEnabled = hasNotifications();
389 item.setEnabled(notifEnabled);
390
391 if (station.isMetro()) {
392 item = menu.add(0, MENU_METROMAP, 0, "Metro" ); //TODO:translate!?!
393 item.setIcon(android.R.drawable.ic_menu_mapmode);
394 }
395
396 return true;
397 }
398
399 @Override
400 public boolean onOptionsItemSelected(MenuItem item) {
401 boolean res = true;
402 switch(item.getItemId()) {
403 case MENU_MAP:
404 Uri uri = Uri.parse("geo:" + station.getLatitude() + "," + station.getLongitude() + "?z=16");
405
406 try {
407 startActivity( new Intent(Intent.ACTION_VIEW, uri));
408 } catch (ActivityNotFoundException anfe) {
409 Toast.makeText(this, "Could not launch google maps", Toast.LENGTH_LONG).show();
410 }
411
412 break;
413 case MENU_NOTIFICATIONS:
414 Intent i = new Intent(this,dk.thoerup.traininfo.NotificationList.class);
415 i.putExtra(NotificationList.EXTRA_NOTIFICATIONS, departures.notifications);
416 startActivity(i);
417 break;
418 case MENU_METROMAP:
419 Intent metroMap = new Intent(this,dk.thoerup.traininfo.MetroMap.class);
420 startActivity(metroMap);
421 break;
422 case MENU_TOGGLEDETAILS:
423 adapter.toggleShowDetails();
424 break;
425 default:
426 res = super.onOptionsItemSelected(item);
427 }
428 return res;
429 }
430
431 void startDepartureFetcher() {
432 showDialog(DLG_PROGRESS);
433 fetcher = new DepartureFetcher();
434 fetcher.execute(station.getId());
435 }
436
437 void startMetroFetcher() {
438 showDialog(DLG_PROGRESS);
439 metroFetcher = new MetroFetcher();
440 metroFetcher.execute(station.getId());
441 }
442
443 class DialogDismisser implements View.OnClickListener {
444
445 Dialog dlg;
446 public DialogDismisser(Dialog d) {
447 dlg = d;
448 }
449
450 @Override
451 public void onClick(View v) {
452 if (dlg.isShowing())
453 dlg.dismiss();
454 }
455 }
456
457 /*View.OnClickListener mapLauncher = new View.OnClickListener() {
458 @Override
459 public void onClick(View v) {
460 Uri uri = Uri.parse("geo:" + station.getLatitude() + "," + station.getLongitude());
461 startActivity( new Intent(Intent.ACTION_VIEW, uri));
462 }
463 };*/
464
465
466
467 class DepartureFetcher extends AsyncTask<Integer, Void, Void> {
468
469 @Override
470 protected void onPostExecute(Void result) {
471 super.onPostExecute(result);
472
473
474 pgDialog.dismiss();
475
476 if (departures != null && departures.errorCode == null) {
477 commFailCounter = 0;
478 DepartureList.this.getListView().setVisibility(View.GONE); //Experimental, inspired by http://osdir.com/ml/Android-Developers/2010-04/msg01198.html
479 adapter.setDepartures(departures.entries);
480 DepartureList.this.getListView().setVisibility(View.VISIBLE);
481
482
483 // handle notification icon.
484 View notifIcon = findViewById(R.id.notifIcon);
485 if ( hasNotifications() ) {
486 notifIcon.setVisibility(View.VISIBLE);
487 notifIcon.setClickable(true);
488 notifIcon.setOnClickListener( new View.OnClickListener() {
489 @Override
490 public void onClick(View v) {
491 Intent i = new Intent(DepartureList.this, dk.thoerup.traininfo.NotificationList.class);
492 i.putExtra(NotificationList.EXTRA_NOTIFICATIONS, departures.notifications);
493 startActivity(i);
494 }
495 });
496 } else {
497 notifIcon.setVisibility(View.INVISIBLE);
498 }
499
500 if (departures.entries.size() == 0) {
501 int msgId = (arrival==false) ? R.string.departurelist_nodepartures : R.string.departurelist_noarrivals;
502 MessageBox.showMessage(DepartureList.this, getString(msgId), false);
503 }
504 } else { // communication or parse error
505 commFailCounter++;
506 AlertDialog.Builder builder = new AlertDialog.Builder(DepartureList.this);
507
508 if (departures != null && departures.errorCode != null ) { //got an error xml back
509 commFailCounter = 10;
510 builder.setMessage( getString(R.string.no_backend) );
511 } else {
512 builder.setMessage( getString(R.string.departurelist_fetcherror) );
513 }
514 builder.setCancelable(true);
515
516 if (commFailCounter < 3) {
517 builder.setPositiveButton(getString(generic_retry), new DialogInterface.OnClickListener() {
518 public void onClick(DialogInterface dialog, int id) {
519 dialog.dismiss();
520 startDepartureFetcher();
521
522 }
523 });
524 }
525 builder.setNegativeButton(getString(generic_cancel), new DialogInterface.OnClickListener() {
526 public void onClick(DialogInterface dialog, int id) {
527 dialog.dismiss();
528 DepartureList.this.finish();
529 }
530 });
531
532 try { //TODO: is this still necessary after the 0.9.4.1 fix ?
533 builder.show();
534 } catch (android.view.WindowManager.BadTokenException e) {
535 Log.i("DepartureList", "BadTokenException"); // this can happen if the user switched away from this activity, while doInBackground was running
536 }
537 }
538 }
539
540 @Override
541 protected Void doInBackground(Integer... params) {
542 departures = provider.lookupDepartures(params[0], DepartureList.this.arrival, trainType);
543 return null;
544 }
545
546 }
547
548 public void loadMetroData() {
549 ((TextView) findViewById(R.id.operations)).setText( metroBean.operationInfo );
550 ((TextView) findViewById(R.id.plan)).setText( metroBean.plan );
551
552
553 TableLayout table = (TableLayout) findViewById(R.id.metrotable);
554 table.removeAllViews();
555
556 TableRow head = new TableRow(this);
557
558 TextView h1 = new TextView(this);
559 h1.setText("Metro");
560 h1.setTextSize(16);
561 h1.setTypeface( Typeface.defaultFromStyle(Typeface.BOLD));
562
563
564 TableRow.LayoutParams params = new TableRow.LayoutParams();
565 params.span = 2;
566 head.addView(h1, params);
567
568
569
570 TextView h2 = new TextView(this);
571 h2.setTextSize(16);
572 h2.setTypeface( Typeface.defaultFromStyle(Typeface.BOLD));
573 h2.setText("Om minutter");
574
575 params = new TableRow.LayoutParams();
576 params.weight = 2;
577 head.addView(h2,params);
578
579
580
581 table.addView(head);
582
583 for (MetroEntry entry : metroBean.entries) {
584 TableRow row = new TableRow(this);
585
586 Log.e("Test", "" + entry.destination);
587
588 TextView v1 = new TextView(this);
589 v1.setTextSize(16);
590 v1.setText( entry.metro );
591 row.addView(v1);
592
593 TextView v2 = new TextView(this);
594 v2.setTextSize(16);
595 v2.setText( entry.destination );
596 row.addView(v2);
597
598 TextView v3 = new TextView(this);
599 v3.setTextSize(16);
600 v3.setText( entry.minutes );
601 row.addView(v3);
602
603 table.addView(row);
604
605 }
606 findViewById(R.id.rootView).requestLayout();
607 }
608
609 class MetroFetcher extends AsyncTask<Integer, Void, Void> {
610
611 @Override
612 protected void onPostExecute(Void result) {
613 super.onPostExecute(result);
614
615
616
617 pgDialog.dismiss();
618
619 if (metroBean != null) {
620 loadMetroData();
621 } else { // communication or parse error
622 commFailCounter++;
623 AlertDialog.Builder builder = new AlertDialog.Builder(DepartureList.this);
624 builder.setMessage("Error finding metro data");
625 builder.setCancelable(true);
626 if (commFailCounter < 3) {
627 builder.setPositiveButton(getString(generic_retry), new DialogInterface.OnClickListener() {
628 public void onClick(DialogInterface dialog, int id) {
629 dialog.dismiss();
630 startMetroFetcher();
631
632 }
633 });
634 }
635 builder.setNegativeButton(getString(generic_cancel), new DialogInterface.OnClickListener() {
636 public void onClick(DialogInterface dialog, int id) {
637 dialog.dismiss();
638 DepartureList.this.finish(); //TODO: should we really close the activity ??
639 }
640 });
641
642 try { //TODO: is this still necessary after the 0.9.4.1 fix ?
643 builder.show();
644 } catch (android.view.WindowManager.BadTokenException e) {
645 Log.i("DepartureList", "BadTokenException"); // this can happen if the user switched away from this activity, while doInBackground was running
646 }
647 }
648 }
649
650 @Override
651 protected Void doInBackground(Integer... params) {
652 metroBean = metro.lookupMetroInfo(params[0]);
653 return null;
654 }
655
656 }
657
658 }

  ViewVC Help
Powered by ViewVC 1.1.20