/* * Southampton University Map App * Copyright (C) 2011 Christopher Baines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.cbaines.suma; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.apache.http.client.ClientProtocolException; import org.json.JSONException; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; 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.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnLongClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.stmt.PreparedQuery; import com.j256.ormlite.stmt.QueryBuilder; public class BusStopActivity extends ToastHelperActivity implements OnCheckedChangeListener, Preferences, OnItemClickListener, OnLongClickListener { final static String TAG = "BusTimeActivity"; private ListView busTimeList; private TextView busName; private TextView busID; private CheckBox busFavourite; private TextView busStopMessage; private ProgressBar progBar; private LinearLayout busTimeContentLayout; protected Timetable timetable; private Timetable visibleTimetable; private BusStop busStop; private GetTimetableTask timetableTask; private Context instance; private Handler mHandler; private Runnable refreshData; private CheckBox U1RouteRadioButton; private CheckBox U1NRouteRadioButton; private CheckBox U2RouteRadioButton; private CheckBox U6RouteRadioButton; private CheckBox U9RouteRadioButton; private static final int POI_DIALOG_ID = 0; private POIDialog busStopDialog; private HashSet routes = new HashSet(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.bus_stop_activity); Log.i(TAG, "getIntent().getDataString() " + getIntent().getDataString()); String busStopID; if (getIntent().getDataString().startsWith("http://data")) { String[] uriParts = getIntent().getDataString().split("/"); busStopID = uriParts[uriParts.length - 1].replace(".html", ""); } else { String[] uriParts = getIntent().getDataString().split("/"); busStopID = uriParts[uriParts.length - 1]; } final DatabaseHelper helper = getHelper(); SharedPreferences favouritesPreferences = getSharedPreferences(FAVOURITES_PREFERENCES, 0); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); instance = this; U1RouteRadioButton = (CheckBox) findViewById(R.id.radio_u1); U1NRouteRadioButton = (CheckBox) findViewById(R.id.radio_u1n); U2RouteRadioButton = (CheckBox) findViewById(R.id.radio_u2); U6RouteRadioButton = (CheckBox) findViewById(R.id.radio_u6); U9RouteRadioButton = (CheckBox) findViewById(R.id.radio_u9); U1RouteRadioButton.setOnCheckedChangeListener(this); U1RouteRadioButton.setOnLongClickListener(this); U1NRouteRadioButton.setOnCheckedChangeListener(this); U1NRouteRadioButton.setOnLongClickListener(this); U2RouteRadioButton.setOnCheckedChangeListener(this); U2RouteRadioButton.setOnLongClickListener(this); U6RouteRadioButton.setOnCheckedChangeListener(this); U6RouteRadioButton.setOnLongClickListener(this); U9RouteRadioButton.setOnCheckedChangeListener(this); U9RouteRadioButton.setOnLongClickListener(this); try { Dao busStopDao = helper.getBusStopDao(); busStop = busStopDao.queryForId(busStopID); Dao busRouteDao = helper.getBusRouteDao(); Dao routeStopsDao = helper.getRouteStopsDao(); for (BusRoute route : busRouteDao) { QueryBuilder queryBuilder = routeStopsDao.queryBuilder(); queryBuilder.where().eq(RouteStop.ROUTE_ID_FIELD_NAME, route.id).and() .eq(RouteStop.STOP_ID_FIELD_NAME, busStopID); queryBuilder.setCountOf(true); PreparedQuery preparedQuery = queryBuilder.prepare(); long count = routeStopsDao.countOf(preparedQuery); if (route.code.equals("U1")) { if (count != 0) { U1RouteRadioButton.setVisibility(View.VISIBLE); routes.add(route); } else { U1RouteRadioButton.setVisibility(View.GONE); } } else if (route.code.equals("U1N")) { if (count != 0) { U1NRouteRadioButton.setVisibility(View.VISIBLE); routes.add(route); } else { U1NRouteRadioButton.setVisibility(View.GONE); } } else if (route.code.equals("U2")) { if (count != 0) { U2RouteRadioButton.setVisibility(View.VISIBLE); routes.add(route); } else { U2RouteRadioButton.setVisibility(View.GONE); } } else if (route.code.equals("U6")) { if (count != 0) { U6RouteRadioButton.setVisibility(View.VISIBLE); routes.add(route); } else { U6RouteRadioButton.setVisibility(View.GONE); } } else if (route.code.equals("U9")) { if (count != 0) { U9RouteRadioButton.setVisibility(View.VISIBLE); routes.add(route); } else { U9RouteRadioButton.setVisibility(View.GONE); } } } busFavourite = (CheckBox) findViewById(R.id.favouriteCheckBox); busFavourite.setChecked(favouritesPreferences.getBoolean(busStop.id, false)); busFavourite.setOnCheckedChangeListener(this); } catch (SQLException e) { e.printStackTrace(); } busName = (TextView) findViewById(R.id.busStopName); busID = (TextView) findViewById(R.id.busStopID); if (prefs.getBoolean(SHOW_IDENTIFIERS, SHOW_IDENTIFIERS_ENABLED_BY_DEFAULT)) { busID.setText(busStopID); busID.setVisibility(View.VISIBLE); } else { busID.setVisibility(View.GONE); } busStopMessage = (TextView) findViewById(R.id.busStopMessage); busStopMessage.setVisibility(View.GONE); progBar = (ProgressBar) findViewById(R.id.busStopLoadBar); progBar.setVisibility(View.GONE); busTimeList = (ListView) findViewById(R.id.busStopTimes); busTimeContentLayout = (LinearLayout) findViewById(R.id.busTimeContentLayout); Log.i(TAG, "Got busstop id " + busStopID); busName.setText(busStop.description); } 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(); refreshData = new Runnable() { public void run() { timetableTask = new GetTimetableTask(); timetableTask.execute(busStop.id); mHandler.postDelayed(refreshData, 20000); } }; mHandler = new Handler(); if (timetable == null) { Log.i(TAG, "No Previous timetable"); mHandler.post(refreshData); } else { Log.i(TAG, "Displaying previous timetable"); displayTimetable(timetable); if (System.currentTimeMillis() - timetable.fetchTime.getTime() > 20000) { mHandler.post(refreshData); } } } else { Log.i(TAG, "Live Times Disabled"); progBar.setVisibility(View.GONE); busStopMessage.setText("Live bus times disabled"); busStopMessage.setVisibility(View.VISIBLE); } } public void onPause() { if (mHandler != null) { // BusTimes are enabled mHandler.removeCallbacks(refreshData); if (timetableTask != null) // Could happen if the handler has not // created the timetableTask yet timetableTask.cancel(true); Log.i(TAG, "Stoping refreshing timetable data"); } super.onPause(); } public void finish() { setResult(RESULT_OK, getIntent()); super.finish(); } public void onCheckedChanged(CompoundButton button, boolean checked) { if (button.equals(busFavourite)) { SharedPreferences favouritesPreferences = getSharedPreferences(FAVOURITES_PREFERENCES, 0); if (checked) { favouritesPreferences.edit().putBoolean(busStop.id, true).commit(); } else { favouritesPreferences.edit().remove(busStop.id).commit(); } } else { Log.i(TAG, "Route radio button made " + checked); if (timetable != null) { // If there is a timetable to display displayTimetable(timetable); } } } @Override public Object onRetainNonConfigurationInstance() { return timetable; } private class GetTimetableTask extends AsyncTask { String errorMessage; protected void onPreExecute() { progBar.setVisibility(View.VISIBLE); } protected Timetable doInBackground(String... activity) { Timetable newTimetable = null; try { final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(instance); newTimetable = DataManager.getTimetable(instance, busStop.id, sharedPrefs.getBoolean( MapActivity.UNI_LINK_BUS_TIMES, MapActivity.UNI_LINK_BUS_TIMES_ENABLED_BY_DEFAULT), sharedPrefs .getBoolean(MapActivity.NON_UNI_LINK_BUS_TIMES, MapActivity.NON_UNI_LINK_BUS_TIMES_ENABLED_BY_DEFAULT)); } 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(); } catch (Exception e) { Log.e(TAG, "Exception in new timetable " + e.getMessage(), e.getCause()); e.printStackTrace(); } return newTimetable; } protected void onPostExecute(Timetable newTimetable) { Log.i(TAG, "Got timetable for " + busStop.id); if (newTimetable == null) { Log.i(TAG, "Its null"); progBar.setVisibility(View.GONE); busStopMessage.setText(errorMessage); busStopMessage.setVisibility(View.VISIBLE); } else { progBar.setVisibility(View.GONE); busStopMessage.setVisibility(View.GONE); timetable = newTimetable; displayTimetable(timetable); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.bus_stop_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection if (item.getItemId() == R.id.menu_previous_stop || item.getItemId() == R.id.menu_next_stop) { Log.v(TAG, "Got a request for the stop movement"); Log.v(TAG, routes.size() + " routes avalible from this stop"); ArrayList busStops = new ArrayList(); for (BusRoute route : routes) { try { Set tmpStops; if (item.getItemId() == R.id.menu_next_stop) { tmpStops = route.moveInRoute(this, getHelper().getBusStopDao().queryForId(busStop.id), 1); } else { tmpStops = route.moveInRoute(this, getHelper().getBusStopDao().queryForId(busStop.id), -1); } for (BusStop busStop : tmpStops) { if (!busStops.contains(busStop)) { busStops.add(busStop); } } } catch (SQLException e) { e.printStackTrace(); } } Log.i(TAG, "stops " + busStops); if (busStops.size() == 1) { BusStop nextBusStop = (BusStop) busStops.iterator().next(); Uri uri = Uri.parse("http://id.southampton.ac.uk/bus-stop/" + nextBusStop.id); Log.i(TAG, "Starting a activity for " + uri + " path " + uri.getPath()); Intent busStopIntent = new Intent(Intent.ACTION_VIEW, uri); startActivity(busStopIntent); } else { showDialog(POI_DIALOG_ID); if (busStopDialog == null) { Log.e(TAG, "Very wierd, just tried to launch the favourite's dialog, but its null?"); return false; } busStopDialog.setMessage(""); busStopDialog.setItems(busStops); busStopDialog.setTitle("Choose Bus Stop"); Log.i(TAG, "Showing dialog"); } } else if (item.getItemId() == R.id.menu_refresh_stop) { if (mHandler != null) { // BusTimes are enabled mHandler.removeCallbacks(refreshData); timetableTask.cancel(true); Log.i(TAG, "Stoping refreshing timetable data"); mHandler.post(refreshData); } else { // TODO: Toast here... } } else { Log.e(TAG, "No known menu option selected"); return super.onOptionsItemSelected(item); } return true; } private void displayTimetable(Timetable timetable) { visibleTimetable = (Timetable) timetable.clone(); Log.i(TAG, "It contains " + visibleTimetable.size() + " stops"); if (timetable.size() == 0) { busStopMessage.setText("No Busses"); busStopMessage.setVisibility(View.VISIBLE); busTimeContentLayout.setGravity(Gravity.CENTER); } else { for (Iterator stopIter = visibleTimetable.iterator(); stopIter.hasNext();) { Stop stop = stopIter.next(); Log.i(TAG, "Begin filtering, looking at " + stop + " with route " + stop.bus.route.code); if (stop.bus.route.code.equals("U1")) { if (!U1RouteRadioButton.isChecked()) { stopIter.remove(); } } else if (stop.bus.route.code.equals("U1N")) { if (!U1NRouteRadioButton.isChecked()) { stopIter.remove(); } } else if (stop.bus.route.code.equals("U2")) { if (!U2RouteRadioButton.isChecked()) { stopIter.remove(); } } else if (stop.bus.route.code.equals("U6")) { if (!U6RouteRadioButton.isChecked()) { stopIter.remove(); } } else if (stop.bus.route.code.equals("U9")) { if (!U9RouteRadioButton.isChecked()) { stopIter.remove(); } } } if (visibleTimetable.size() == 0) { busTimeContentLayout.setGravity(Gravity.CENTER); busStopMessage.setText("No Busses (With the current enabled routes)"); busStopMessage.setVisibility(View.VISIBLE); busTimeList.setVisibility(View.GONE); } else { busTimeList.setVisibility(View.VISIBLE); busStopMessage.setVisibility(View.GONE); BusStopSpecificTimetableAdapter adapter; if ((adapter = (BusStopSpecificTimetableAdapter) busTimeList.getAdapter()) != null) { adapter.updateTimetable(visibleTimetable); } else { adapter = new BusStopSpecificTimetableAdapter(this, visibleTimetable); busTimeList.setAdapter(adapter); } busTimeContentLayout.setGravity(Gravity.TOP); } } } @Override protected Dialog onCreateDialog(int id) { switch (id) { case POI_DIALOG_ID: busStopDialog = new POIDialog(instance); busStopDialog.setOnItemClickListener(this); return busStopDialog; } return null; } public void onItemClick(AdapterView parent, View view, int position, long id) { Log.i(TAG, "OnItemClick pos " + position + " id " + id); String busStopID = busStopDialog.adapter.getItemStringId(position); Log.i(TAG, "Bus " + busStopID + " selected"); Uri uri = Uri.parse("http://id.southampton.ac.uk/bus-stop/" + busStopID); Log.i(TAG, "Starting a activity for " + uri + " path " + uri.getPath()); Intent busStopIntent = new Intent(Intent.ACTION_VIEW, uri); startActivity(busStopIntent); } public boolean onLongClick(View v) { Uri uri = null; if (v.equals(U1RouteRadioButton)) { uri = Uri.parse("http://id.southampton.ac.uk/bus-route/326"); } else if (v.equals(U1NRouteRadioButton)) { uri = Uri.parse("http://id.southampton.ac.uk/bus-route/468"); } else if (v.equals(U2RouteRadioButton)) { uri = Uri.parse("http://id.southampton.ac.uk/bus-route/329"); } else if (v.equals(U6RouteRadioButton)) { uri = Uri.parse("http://id.southampton.ac.uk/bus-route/327"); } else if (v.equals(U9RouteRadioButton)) { uri = Uri.parse("http://id.southampton.ac.uk/bus-route/354"); } if (uri != null) { Log.i(TAG, "Starting a activity for " + uri + " path " + uri.getPath()); Intent busStopIntent = new Intent(Intent.ACTION_VIEW, uri); startActivity(busStopIntent); } return false; } }