package net.cbaines.suma; import java.io.IOException; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import org.apache.http.client.ClientProtocolException; import org.json.JSONException; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.util.Log; import android.view.Gravity; import android.view.View; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; public class BusActivity extends ToastHelperActivity implements Preferences { final static String TAG = "BusActivity"; private TextView busIDTextView; private TextView busDestTextView; private TextView busContentMessage; private LinearLayout busActivityContentLayout; /** * The bus this activity is focused on */ private Bus bus; /** * The bus stop this activity is working from */ private BusStop busStop; Runnable refreshData; protected Timetable timetable; private Timetable visibleTimetable; private ListView timetableView; private Context instance; // BusStops and if they are being updated by the handler List busStops; private HashMap tasks = new HashMap(); Handler handler; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.bus_activity); instance = this; String busID; if (getIntent().getDataString().startsWith("http://data")) { String[] uriParts = getIntent().getDataString().split("/"); busID = uriParts[uriParts.length - 1].replace(".html", ""); } else { String[] uriParts = getIntent().getDataString().split("/"); busID = uriParts[uriParts.length - 1]; } String busStopID = getIntent().getExtras().getString("busStopID"); try { final DatabaseHelper helper = getHelper(); List buses = helper.getBusDao().queryForEq(Bus.ID_FIELD_NAME, busID); bus = null; if (buses.size() == 0) { Log.e(TAG, "Bus " + busID + " not found!"); } else if (buses.size() == 1) { bus = buses.get(0); } else if (buses.size() > 1) { Log.e(TAG, "Found more than one bus? " + busID); } helper.getBusRouteDao().refresh(bus.route); busStop = null; if (busStopID != null) { List busStops = helper.getBusStopDao().queryForEq(BusStop.ID_FIELD_NAME, busStopID); if (busStops.size() == 0) { Log.e(TAG, "BusStop " + busStopID + " not found!"); } else if (busStops.size() == 1) { busStop = busStops.get(0); } else if (busStops.size() > 1) { Log.e(TAG, "Found more than one busStop? " + busStopID); } } busIDTextView = (TextView) findViewById(R.id.busActivityBusID); busDestTextView = (TextView) findViewById(R.id.busActivityBusDestination); busContentMessage = (TextView) findViewById(R.id.busActivityMessage); busActivityContentLayout = (LinearLayout) findViewById(R.id.busActivityContentLayout); timetableView = (ListView) findViewById(R.id.busActivityTimes); if (bus.id != null) { Log.i(TAG, "Bus id is not null (" + bus.id + ") setting busIDTextView"); busIDTextView.setText(bus.id + " " + bus.getName()); } else { Log.w(TAG, "Bus id is null?"); // Might not ever happen busIDTextView.setText("Unidentified"); } if (bus.destinationString != null) { Log.i(TAG, "Bus destination string is " + bus.destinationString); busDestTextView .setText(getResources().getString(R.string.bus_activity_destination_label) + bus.destinationString); busDestTextView.setVisibility(View.VISIBLE); } else { Log.i(TAG, "Bus destination string is null"); busDestTextView.setText(getResources().getString(R.string.bus_activity_no_destination_message)); busDestTextView.setVisibility(View.VISIBLE); } busStops = bus.route.getRouteSection(instance, bus.direction); Log.i(TAG, "Got " + busStops.size() + " bus stops for this bus"); if (bus.destination != null) { Log.i(TAG, "Bus destination is " + bus.destination); } else { Log.i(TAG, "Bus destination is null"); } refreshData = new Runnable() { public void run() { for (int num = timetableView.getFirstVisiblePosition(); num < timetableView.getLastVisiblePosition(); num++) { Stop stop = timetable.get(num); GetTimetableStopTask task = tasks.get(busStops.get(num)); if (stop.timeOfFetch == null || (stop.timeOfFetch.getTime() - System.currentTimeMillis()) > 20000) { if (task != null) { if (task.getStatus() == AsyncTask.Status.FINISHED) { task = null; } } if (task == null) { task = new GetTimetableStopTask(); BusStop[] str = { stop.busStop }; task.execute(str); tasks.put(stop.busStop, task); } } } handler.postDelayed(refreshData, 50000); } }; } catch (SQLException e) { e.printStackTrace(); } } public void onResume() { super.onResume(); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); if (sharedPrefs.getBoolean(UNI_LINK_BUS_TIMES, UNI_LINK_BUS_TIMES_ENABLED_BY_DEFAULT) || sharedPrefs.getBoolean(NON_UNI_LINK_BUS_TIMES, NON_UNI_LINK_BUS_TIMES_ENABLED_BY_DEFAULT)) { Log.i(TAG, "Live Times enabled"); timetable = (Timetable) getLastNonConfigurationInstance(); handler = new Handler(); if (timetable == null) { Log.i(TAG, "No Previous timetable"); timetable = new Timetable(); for (int i = 0; i < busStops.size(); i++) { timetable.add(new Stop(bus, busStops.get(i), null, null, false)); } Log.v(TAG, "Finished adding placeholder stops"); } else { Log.i(TAG, "Displaying previous timetable"); } displayTimetable(timetable); handler.postDelayed(refreshData, 500); } else { Log.i(TAG, "Live Times Disabled"); busContentMessage.setText("Live bus times disabled"); busContentMessage.setVisibility(View.VISIBLE); } } public void onPause() { if (handler != null) { // BusTimes are enabled handler.removeCallbacks(refreshData); for (GetTimetableStopTask task : tasks.values()) { if (task != null) { task.cancel(true); } } Log.i(TAG, "Stoping refreshing timetable data"); } super.onPause(); } private class GetTimetableStopTask extends AsyncTask { private String errorMessage; private BusStop busStop; private int position; protected void onPreExecute() { // progBar.setVisibility(View.VISIBLE); } protected Stop doInBackground(BusStop... busStopArray) { busStop = busStopArray[0]; position = busStops.indexOf(busStop); Stop stop = null; try { Log.i(TAG, "Fetching stop for busStop " + position); stop = DataManager.getStop(instance, bus, busStop); if (stop == null) { stop = new Stop(bus, busStop, null, null, false); } Log.i(TAG, "Finished fetching stop for busStop " + position); } catch (SQLException e) { errorMessage = "Error message regarding SQL?"; e.printStackTrace(); } catch (ClientProtocolException e) { errorMessage = "ClientProtocolException!?!"; e.printStackTrace(); } catch (IOException e) { errorMessage = "Error fetching bus times from server, are you connected to the internet?"; e.printStackTrace(); } catch (JSONException e) { errorMessage = "Error parsing bus times"; e.printStackTrace(); } return stop; } protected void onPostExecute(Stop stop) { // Log.i(TAG, "Got timetable"); if (stop == null) { Log.i(TAG, "Its null"); busContentMessage.setText(errorMessage); busContentMessage.setVisibility(View.VISIBLE); } else { synchronized (timetable) { timetable.set(position, stop); displayTimetable(timetable); } } } } private void displayTimetable(Timetable timetable) { visibleTimetable = (Timetable) timetable.clone(); // Log.i(TAG, "Displaying timetable, it contains " + // visibleTimetable.size() + " stops"); if (timetable.size() == 0) { busContentMessage.setText("No Busses"); busContentMessage.setVisibility(View.VISIBLE); busActivityContentLayout.setGravity(Gravity.CENTER); } else { if (visibleTimetable.size() == 0) { busActivityContentLayout.setGravity(Gravity.CENTER); busContentMessage.setText("No Busses (With the current enabled routes)"); busContentMessage.setVisibility(View.VISIBLE); timetableView.setVisibility(View.GONE); } else { timetableView.setVisibility(View.VISIBLE); busContentMessage.setVisibility(View.GONE); BusSpecificTimetableAdapter adapter; if ((adapter = (BusSpecificTimetableAdapter) timetableView.getAdapter()) != null) { adapter.updateTimetable(visibleTimetable); } else { adapter = new BusSpecificTimetableAdapter(this, visibleTimetable); timetableView.setAdapter(adapter); if (busStop != null) { Log.i(TAG, "Moving to position of " + busStop.description + " which is " + busStops.indexOf(busStop)); timetableView.setSelection(busStops.indexOf(busStop)); } } busActivityContentLayout.setGravity(Gravity.TOP); } } } }