Death to tabs! Long live spaces!

This commit is contained in:
Doug Keen 2015-08-11 18:56:23 -07:00
parent 9285836e61
commit 00faa9ec76
66 changed files with 5526 additions and 5546 deletions

View File

@ -3,7 +3,7 @@
package="com.dougkeen.bart" package="com.dougkeen.bart"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="31" android:versionCode="31"
android:versionName="2.2.4" > android:versionName="2.2.4">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
@ -17,11 +17,11 @@
android:name=".BartRunnerApplication_" android:name=".BartRunnerApplication_"
android:icon="@drawable/icon" android:icon="@drawable/icon"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme" > android:theme="@style/AppTheme">
<activity <activity
android:name=".activities.RoutesListActivity_" android:name=".activities.RoutesListActivity_"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name" > android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -46,7 +46,7 @@
</activity> </activity>
<activity <activity
android:name=".activities.ViewDeparturesActivity" android:name=".activities.ViewDeparturesActivity"
android:label="@string/departures" > android:label="@string/departures">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -58,8 +58,7 @@
</activity> </activity>
<activity <activity
android:name=".activities.ViewMapActivity" android:name=".activities.ViewMapActivity"
android:label="@string/system_map" > android:label="@string/system_map"></activity>
</activity>
<service <service
android:name=".services.BoardedDepartureService" android:name=".services.BoardedDepartureService"
@ -70,7 +69,7 @@
<receiver <receiver
android:name=".receivers.AlarmBroadcastReceiver" android:name=".receivers.AlarmBroadcastReceiver"
android:exported="false" > android:exported="false">
<intent-filter> <intent-filter>
<action android:name="com.dougkeen.action.ALARM" /> <action android:name="com.dougkeen.action.ALARM" />

View File

@ -27,199 +27,199 @@ import com.googlecode.androidannotations.annotations.EApplication;
@EApplication @EApplication
public class BartRunnerApplication extends Application { public class BartRunnerApplication extends Application {
private static final int FIVE_MINUTES = 5 * 60 * 1000; private static final int FIVE_MINUTES = 5 * 60 * 1000;
private static final String CACHE_FILE_NAME = "lastBoardedDeparture"; private static final String CACHE_FILE_NAME = "lastBoardedDeparture";
private Departure mBoardedDeparture; private Departure mBoardedDeparture;
private boolean mPlayAlarmRingtone; private boolean mPlayAlarmRingtone;
private boolean mAlarmSounding; private boolean mAlarmSounding;
private MediaPlayer mAlarmMediaPlayer; private MediaPlayer mAlarmMediaPlayer;
private static Context context; private static Context context;
@Bean @Bean
FavoritesPersistence favoritesPersistenceContext; FavoritesPersistence favoritesPersistenceContext;
private List<StationPair> favorites; private List<StationPair> favorites;
public void saveFavorites() { public void saveFavorites() {
if (favorites != null) { if (favorites != null) {
favoritesPersistenceContext.persist(favorites); favoritesPersistenceContext.persist(favorites);
} }
} }
public List<StationPair> getFavorites() { public List<StationPair> getFavorites() {
if (favorites == null) { if (favorites == null) {
favorites = favoritesPersistenceContext.restore(); favorites = favoritesPersistenceContext.restore();
if (favorites.isEmpty()) { if (favorites.isEmpty()) {
// Upgrade database, in case favorites are still in there // Upgrade database, in case favorites are still in there
new DatabaseHelper(this).getReadableDatabase().close(); new DatabaseHelper(this).getReadableDatabase().close();
favorites = favoritesPersistenceContext.restore(); favorites = favoritesPersistenceContext.restore();
} }
} }
return favorites; return favorites;
} }
public void setFavorites(List<StationPair> favorites) { public void setFavorites(List<StationPair> favorites) {
this.favorites = favorites; this.favorites = favorites;
} }
public StationPair getFavorite(Station origin, Station destination) { public StationPair getFavorite(Station origin, Station destination) {
for (StationPair favorite : getFavorites()) { for (StationPair favorite : getFavorites()) {
if (origin.equals(favorite.getOrigin()) if (origin.equals(favorite.getOrigin())
&& destination.equals(favorite.getDestination())) { && destination.equals(favorite.getDestination())) {
return favorite; return favorite;
} }
} }
return null; return null;
} }
public void addFavorite(StationPair favorite) { public void addFavorite(StationPair favorite) {
getFavorites().add(favorite); getFavorites().add(favorite);
saveFavorites(); saveFavorites();
} }
public void removeFavorite(StationPair favorite) { public void removeFavorite(StationPair favorite) {
getFavorites().remove(favorite); getFavorites().remove(favorite);
saveFavorites(); saveFavorites();
} }
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
context = getApplicationContext(); context = getApplicationContext();
} }
public static Context getAppContext() { public static Context getAppContext() {
return context; return context;
} }
public boolean shouldPlayAlarmRingtone() { public boolean shouldPlayAlarmRingtone() {
return mPlayAlarmRingtone; return mPlayAlarmRingtone;
} }
public void setPlayAlarmRingtone(boolean playAlarmRingtone) { public void setPlayAlarmRingtone(boolean playAlarmRingtone) {
this.mPlayAlarmRingtone = playAlarmRingtone; this.mPlayAlarmRingtone = playAlarmRingtone;
} }
public Departure getBoardedDeparture() { public Departure getBoardedDeparture() {
return getBoardedDeparture(false); return getBoardedDeparture(false);
} }
public Departure getBoardedDeparture(boolean useOldCache) { public Departure getBoardedDeparture(boolean useOldCache) {
if (mBoardedDeparture == null) { if (mBoardedDeparture == null) {
// see if there's a saved one // see if there's a saved one
File cachedDepartureFile = new File(getCacheDir(), CACHE_FILE_NAME); File cachedDepartureFile = new File(getCacheDir(), CACHE_FILE_NAME);
if (cachedDepartureFile.exists()) { if (cachedDepartureFile.exists()) {
InputStream inputStream = null; InputStream inputStream = null;
try { try {
inputStream = new FileInputStream(cachedDepartureFile); inputStream = new FileInputStream(cachedDepartureFile);
final byte[] byteArray = IOUtils.toByteArray(inputStream); final byte[] byteArray = IOUtils.toByteArray(inputStream);
final Parcel parcel = Parcel.obtain(); final Parcel parcel = Parcel.obtain();
parcel.unmarshall(byteArray, 0, byteArray.length); parcel.unmarshall(byteArray, 0, byteArray.length);
parcel.setDataPosition(0); parcel.setDataPosition(0);
Departure lastBoardedDeparture = Departure.CREATOR Departure lastBoardedDeparture = Departure.CREATOR
.createFromParcel(parcel); .createFromParcel(parcel);
parcel.recycle(); parcel.recycle();
/* /*
* Ooptionally check if the cached one is relatively recent. * Ooptionally check if the cached one is relatively recent.
* If so, restore that to the application context * If so, restore that to the application context
*/ */
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (useOldCache if (useOldCache
|| lastBoardedDeparture.getEstimatedArrivalTime() >= now || lastBoardedDeparture.getEstimatedArrivalTime() >= now
- FIVE_MINUTES - FIVE_MINUTES
|| lastBoardedDeparture.getMeanEstimate() >= now || lastBoardedDeparture.getMeanEstimate() >= now
- 2 * FIVE_MINUTES) { - 2 * FIVE_MINUTES) {
mBoardedDeparture = lastBoardedDeparture; mBoardedDeparture = lastBoardedDeparture;
} }
} catch (Exception e) { } catch (Exception e) {
Log.w(Constants.TAG, Log.w(Constants.TAG,
"Couldn't read or unmarshal lastBoardedDeparture file", "Couldn't read or unmarshal lastBoardedDeparture file",
e); e);
try { try {
cachedDepartureFile.delete(); cachedDepartureFile.delete();
} catch (SecurityException anotherException) { } catch (SecurityException anotherException) {
Log.w(Constants.TAG, Log.w(Constants.TAG,
"Couldn't delete lastBoardedDeparture file", "Couldn't delete lastBoardedDeparture file",
anotherException); anotherException);
} }
} finally { } finally {
IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(inputStream);
} }
} }
} }
if (mBoardedDeparture != null && mBoardedDeparture.hasExpired()) { if (mBoardedDeparture != null && mBoardedDeparture.hasExpired()) {
setBoardedDeparture(null); setBoardedDeparture(null);
} }
return mBoardedDeparture; return mBoardedDeparture;
} }
public void setBoardedDeparture(Departure boardedDeparture) { public void setBoardedDeparture(Departure boardedDeparture) {
if (!ObjectUtils.equals(boardedDeparture, mBoardedDeparture) if (!ObjectUtils.equals(boardedDeparture, mBoardedDeparture)
|| ObjectUtils.compare(mBoardedDeparture, boardedDeparture) != 0) { || ObjectUtils.compare(mBoardedDeparture, boardedDeparture) != 0) {
if (this.mBoardedDeparture != null) { if (this.mBoardedDeparture != null) {
this.mBoardedDeparture.getAlarmLeadTimeMinutesObservable() this.mBoardedDeparture.getAlarmLeadTimeMinutesObservable()
.unregisterAllObservers(); .unregisterAllObservers();
this.mBoardedDeparture.getAlarmPendingObservable() this.mBoardedDeparture.getAlarmPendingObservable()
.unregisterAllObservers(); .unregisterAllObservers();
// Cancel any pending alarms for the current departure // Cancel any pending alarms for the current departure
if (this.mBoardedDeparture.isAlarmPending()) { if (this.mBoardedDeparture.isAlarmPending()) {
this.mBoardedDeparture this.mBoardedDeparture
.cancelAlarm( .cancelAlarm(
this, this,
(AlarmManager) getSystemService(Context.ALARM_SERVICE)); (AlarmManager) getSystemService(Context.ALARM_SERVICE));
} }
} }
this.mBoardedDeparture = boardedDeparture; this.mBoardedDeparture = boardedDeparture;
File cachedDepartureFile = new File(getCacheDir(), CACHE_FILE_NAME); File cachedDepartureFile = new File(getCacheDir(), CACHE_FILE_NAME);
if (mBoardedDeparture == null) { if (mBoardedDeparture == null) {
try { try {
cachedDepartureFile.delete(); cachedDepartureFile.delete();
} catch (SecurityException anotherException) { } catch (SecurityException anotherException) {
Log.w(Constants.TAG, Log.w(Constants.TAG,
"Couldn't delete lastBoardedDeparture file", "Couldn't delete lastBoardedDeparture file",
anotherException); anotherException);
} }
} else { } else {
FileOutputStream fileOutputStream = null; FileOutputStream fileOutputStream = null;
try { try {
fileOutputStream = new FileOutputStream(cachedDepartureFile); fileOutputStream = new FileOutputStream(cachedDepartureFile);
Parcel parcel = Parcel.obtain(); Parcel parcel = Parcel.obtain();
mBoardedDeparture.writeToParcel(parcel, 0); mBoardedDeparture.writeToParcel(parcel, 0);
fileOutputStream.write(parcel.marshall()); fileOutputStream.write(parcel.marshall());
} catch (Exception e) { } catch (Exception e) {
Log.w(Constants.TAG, Log.w(Constants.TAG,
"Couldn't write last boarded departure cache file", "Couldn't write last boarded departure cache file",
e); e);
} finally { } finally {
IOUtils.closeQuietly(fileOutputStream); IOUtils.closeQuietly(fileOutputStream);
} }
} }
} }
} }
public boolean isAlarmSounding() { public boolean isAlarmSounding() {
return mAlarmSounding; return mAlarmSounding;
} }
public void setAlarmSounding(boolean alarmSounding) { public void setAlarmSounding(boolean alarmSounding) {
this.mAlarmSounding = alarmSounding; this.mAlarmSounding = alarmSounding;
} }
public MediaPlayer getAlarmMediaPlayer() { public MediaPlayer getAlarmMediaPlayer() {
return mAlarmMediaPlayer; return mAlarmMediaPlayer;
} }
public void setAlarmMediaPlayer(MediaPlayer alarmMediaPlayer) { public void setAlarmMediaPlayer(MediaPlayer alarmMediaPlayer) {
this.mAlarmMediaPlayer = alarmMediaPlayer; this.mAlarmMediaPlayer = alarmMediaPlayer;
} }
} }

View File

@ -21,132 +21,132 @@ import com.dougkeen.bart.model.Station;
public abstract class AbstractRouteSelectionFragment extends DialogFragment { public abstract class AbstractRouteSelectionFragment extends DialogFragment {
private static final String KEY_LAST_SELECTED_DESTINATION = "lastSelectedDestination"; private static final String KEY_LAST_SELECTED_DESTINATION = "lastSelectedDestination";
private static final String KEY_LAST_SELECTED_ORIGIN = "lastSelectedOrigin"; private static final String KEY_LAST_SELECTED_ORIGIN = "lastSelectedOrigin";
protected String mTitle; protected String mTitle;
public AbstractRouteSelectionFragment(String title) { public AbstractRouteSelectionFragment(String title) {
super(); super();
mTitle = title; mTitle = title;
} }
@Override @Override
public void setArguments(Bundle args) { public void setArguments(Bundle args) {
super.setArguments(args); super.setArguments(args);
if (args.containsKey("title")) if (args.containsKey("title"))
mTitle = args.getString("title"); mTitle = args.getString("title");
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setShowsDialog(true); setShowsDialog(true);
} }
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
SharedPreferences preferences = getActivity().getPreferences( SharedPreferences preferences = getActivity().getPreferences(
Context.MODE_PRIVATE); Context.MODE_PRIVATE);
final int lastSelectedOriginPosition = preferences.getInt( final int lastSelectedOriginPosition = preferences.getInt(
KEY_LAST_SELECTED_ORIGIN, 0); KEY_LAST_SELECTED_ORIGIN, 0);
final int lastSelectedDestinationPosition = preferences.getInt( final int lastSelectedDestinationPosition = preferences.getInt(
KEY_LAST_SELECTED_DESTINATION, 1); KEY_LAST_SELECTED_DESTINATION, 1);
final Dialog dialog = getDialog(); final Dialog dialog = getDialog();
final FragmentActivity activity = getActivity(); final FragmentActivity activity = getActivity();
ArrayAdapter<Station> originSpinnerAdapter = new ArrayAdapter<Station>( ArrayAdapter<Station> originSpinnerAdapter = new ArrayAdapter<Station>(
activity, R.layout.simple_spinner_item, activity, R.layout.simple_spinner_item,
Station.getStationList()); Station.getStationList());
originSpinnerAdapter originSpinnerAdapter
.setDropDownViewResource(R.layout.simple_spinner_dropdown_item); .setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
final Spinner originSpinner = (Spinner) dialog final Spinner originSpinner = (Spinner) dialog
.findViewById(R.id.origin_spinner); .findViewById(R.id.origin_spinner);
originSpinner.setAdapter(originSpinnerAdapter); originSpinner.setAdapter(originSpinnerAdapter);
originSpinner.setSelection(lastSelectedOriginPosition); originSpinner.setSelection(lastSelectedOriginPosition);
ArrayAdapter<Station> destinationSpinnerAdapter = new ArrayAdapter<Station>( ArrayAdapter<Station> destinationSpinnerAdapter = new ArrayAdapter<Station>(
activity, R.layout.simple_spinner_item, activity, R.layout.simple_spinner_item,
Station.getStationList()); Station.getStationList());
destinationSpinnerAdapter destinationSpinnerAdapter
.setDropDownViewResource(R.layout.simple_spinner_dropdown_item); .setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
final Spinner destinationSpinner = (Spinner) dialog final Spinner destinationSpinner = (Spinner) dialog
.findViewById(R.id.destination_spinner); .findViewById(R.id.destination_spinner);
destinationSpinner.setAdapter(destinationSpinnerAdapter); destinationSpinner.setAdapter(destinationSpinnerAdapter);
destinationSpinner.setSelection(lastSelectedDestinationPosition); destinationSpinner.setSelection(lastSelectedDestinationPosition);
} }
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final FragmentActivity activity = getActivity(); final FragmentActivity activity = getActivity();
final View dialogView = LayoutInflater.inflate(activity, final View dialogView = LayoutInflater.inflate(activity,
R.layout.route_form); R.layout.route_form);
return new AlertDialog.Builder(activity) return new AlertDialog.Builder(activity)
.setTitle(mTitle) .setTitle(mTitle)
.setCancelable(true) .setCancelable(true)
.setView(dialogView) .setView(dialogView)
.setPositiveButton(R.string.ok, .setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, public void onClick(DialogInterface dialog,
int which) { int which) {
handleOkClick(); handleOkClick();
} }
}) })
.setNegativeButton(R.string.cancel, .setNegativeButton(R.string.cancel,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, public void onClick(DialogInterface dialog,
int whichButton) { int whichButton) {
dialog.cancel(); dialog.cancel();
} }
}).create(); }).create();
} }
protected void handleOkClick() { protected void handleOkClick() {
final Dialog dialog = getDialog(); final Dialog dialog = getDialog();
final Spinner originSpinner = (Spinner) dialog final Spinner originSpinner = (Spinner) dialog
.findViewById(R.id.origin_spinner); .findViewById(R.id.origin_spinner);
final Spinner destinationSpinner = (Spinner) dialog final Spinner destinationSpinner = (Spinner) dialog
.findViewById(R.id.destination_spinner); .findViewById(R.id.destination_spinner);
Station origin = (Station) originSpinner.getSelectedItem(); Station origin = (Station) originSpinner.getSelectedItem();
Station destination = (Station) destinationSpinner.getSelectedItem(); Station destination = (Station) destinationSpinner.getSelectedItem();
if (origin == null) { if (origin == null) {
Toast.makeText(dialog.getContext(), Toast.makeText(dialog.getContext(),
com.dougkeen.bart.R.string.error_null_origin, com.dougkeen.bart.R.string.error_null_origin,
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
return; return;
} }
if (destination == null) { if (destination == null) {
Toast.makeText(dialog.getContext(), Toast.makeText(dialog.getContext(),
com.dougkeen.bart.R.string.error_null_destination, com.dougkeen.bart.R.string.error_null_destination,
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
return; return;
} }
if (origin.equals(destination)) { if (origin.equals(destination)) {
Toast.makeText( Toast.makeText(
dialog.getContext(), dialog.getContext(),
com.dougkeen.bart.R.string.error_matching_origin_and_destination, com.dougkeen.bart.R.string.error_matching_origin_and_destination,
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
return; return;
} }
final Editor prefsEditor = getActivity().getPreferences( final Editor prefsEditor = getActivity().getPreferences(
Context.MODE_PRIVATE).edit(); Context.MODE_PRIVATE).edit();
prefsEditor.putInt(KEY_LAST_SELECTED_ORIGIN, prefsEditor.putInt(KEY_LAST_SELECTED_ORIGIN,
originSpinner.getSelectedItemPosition()); originSpinner.getSelectedItemPosition());
prefsEditor.putInt(KEY_LAST_SELECTED_DESTINATION, prefsEditor.putInt(KEY_LAST_SELECTED_DESTINATION,
destinationSpinner.getSelectedItemPosition()); destinationSpinner.getSelectedItemPosition());
prefsEditor.commit(); prefsEditor.commit();
onOkButtonClick(origin, destination); onOkButtonClick(origin, destination);
} }
abstract protected void onOkButtonClick(Station origin, Station destination); abstract protected void onOkButtonClick(Station origin, Station destination);
} }

View File

@ -9,29 +9,29 @@ import com.dougkeen.bart.model.Station;
import com.dougkeen.bart.model.StationPair; import com.dougkeen.bart.model.StationPair;
public class AddRouteDialogFragment extends AbstractRouteSelectionFragment { public class AddRouteDialogFragment extends AbstractRouteSelectionFragment {
public AddRouteDialogFragment() { public AddRouteDialogFragment() {
super(BartRunnerApplication.getAppContext().getString( super(BartRunnerApplication.getAppContext().getString(
R.string.add_route)); R.string.add_route));
} }
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
final View checkbox = getDialog().findViewById(R.id.return_checkbox); final View checkbox = getDialog().findViewById(R.id.return_checkbox);
checkbox.setVisibility(View.VISIBLE); checkbox.setVisibility(View.VISIBLE);
} }
@Override @Override
protected void onOkButtonClick(Station origin, Station destination) { protected void onOkButtonClick(Station origin, Station destination) {
RoutesListActivity activity = (RoutesListActivity) getActivity(); RoutesListActivity activity = (RoutesListActivity) getActivity();
activity.addFavorite(new StationPair(origin, destination)); activity.addFavorite(new StationPair(origin, destination));
if (((CheckBox) getDialog().findViewById(R.id.return_checkbox)) if (((CheckBox) getDialog().findViewById(R.id.return_checkbox))
.isChecked()) { .isChecked()) {
activity.addFavorite(new StationPair(destination, origin)); activity.addFavorite(new StationPair(destination, origin));
} }
dismiss(); dismiss();
} }
} }

View File

@ -10,16 +10,16 @@ import com.dougkeen.bart.model.StationPair;
public class QuickRouteDialogFragment extends AbstractRouteSelectionFragment { public class QuickRouteDialogFragment extends AbstractRouteSelectionFragment {
public QuickRouteDialogFragment() { public QuickRouteDialogFragment() {
super(BartRunnerApplication.getAppContext().getString( super(BartRunnerApplication.getAppContext().getString(
R.string.quick_departure_lookup)); R.string.quick_departure_lookup));
} }
@Override @Override
protected void onOkButtonClick(Station origin, Station destination) { protected void onOkButtonClick(Station origin, Station destination) {
Intent intent = new Intent(getActivity(), ViewDeparturesActivity.class); Intent intent = new Intent(getActivity(), ViewDeparturesActivity.class);
intent.putExtra(Constants.STATION_PAIR_EXTRA, new StationPair(origin, intent.putExtra(Constants.STATION_PAIR_EXTRA, new StationPair(origin,
destination)); destination));
startActivity(intent); startActivity(intent);
} }
} }

View File

@ -50,398 +50,400 @@ import com.mobeta.android.dslv.DragSortListView;
@EActivity(R.layout.main) @EActivity(R.layout.main)
public class RoutesListActivity extends Activity implements TickSubscriber { public class RoutesListActivity extends Activity implements TickSubscriber {
private static final String NO_DELAYS_REPORTED = "No delays reported"; private static final String NO_DELAYS_REPORTED = "No delays reported";
private static final TimeZone PACIFIC_TIME = TimeZone private static final TimeZone PACIFIC_TIME = TimeZone
.getTimeZone("America/Los_Angeles"); .getTimeZone("America/Los_Angeles");
private static final String TAG = "RoutesListActivity"; private static final String TAG = "RoutesListActivity";
@InstanceState @InstanceState
StationPair mCurrentlySelectedStationPair; StationPair mCurrentlySelectedStationPair;
@InstanceState @InstanceState
String mCurrentAlerts; String mCurrentAlerts;
private ActionMode mActionMode; private ActionMode mActionMode;
private FavoritesArrayAdapter mRoutesAdapter; private FavoritesArrayAdapter mRoutesAdapter;
@App @App
BartRunnerApplication app; BartRunnerApplication app;
@RestService @RestService
AlertsClient alertsClient; AlertsClient alertsClient;
@RestService @RestService
ElevatorClient elevatorClient; ElevatorClient elevatorClient;
@ViewById(android.R.id.list) @ViewById(android.R.id.list)
DragSortListView listView; DragSortListView listView;
@ViewById(R.id.quickLookupButton) @ViewById(R.id.quickLookupButton)
Button quickLookupButton; Button quickLookupButton;
@ViewById(R.id.alertMessages) @ViewById(R.id.alertMessages)
TextView alertMessages; TextView alertMessages;
@Click(R.id.quickLookupButton) @Click(R.id.quickLookupButton)
void quickLookupButtonClick() { void quickLookupButtonClick() {
DialogFragment dialog = new QuickRouteDialogFragment(); DialogFragment dialog = new QuickRouteDialogFragment();
dialog.show(getSupportFragmentManager().beginTransaction()); dialog.show(getSupportFragmentManager().beginTransaction());
} }
@ItemClick(android.R.id.list) @ItemClick(android.R.id.list)
void listItemClicked(StationPair item) { void listItemClicked(StationPair item) {
Intent intent = new Intent(RoutesListActivity.this, Intent intent = new Intent(RoutesListActivity.this,
ViewDeparturesActivity.class); ViewDeparturesActivity.class);
intent.putExtra(Constants.STATION_PAIR_EXTRA, item); intent.putExtra(Constants.STATION_PAIR_EXTRA, item);
startActivity(intent); startActivity(intent);
} }
@ItemLongClick(android.R.id.list) @ItemLongClick(android.R.id.list)
void listItemLongClick(StationPair item) { void listItemLongClick(StationPair item) {
if (mActionMode != null) { if (mActionMode != null) {
mActionMode.finish(); mActionMode.finish();
} }
mCurrentlySelectedStationPair = item; mCurrentlySelectedStationPair = item;
startContextualActionMode(); startContextualActionMode();
} }
private DragSortListView.DropListener onDrop = new DragSortListView.DropListener() { private DragSortListView.DropListener onDrop = new DragSortListView.DropListener() {
@Override @Override
public void drop(int from, int to) { public void drop(int from, int to) {
if (from == to) if (from == to)
return; return;
StationPair item = mRoutesAdapter.getItem(from); StationPair item = mRoutesAdapter.getItem(from);
mRoutesAdapter.move(item, to); mRoutesAdapter.move(item, to);
mRoutesAdapter.notifyDataSetChanged(); mRoutesAdapter.notifyDataSetChanged();
} }
}; };
private DragSortListView.RemoveListener onRemove = new DragSortListView.RemoveListener() { private DragSortListView.RemoveListener onRemove = new DragSortListView.RemoveListener() {
@Override @Override
public void remove(int which) { public void remove(int which) {
mRoutesAdapter.remove(mRoutesAdapter.getItem(which)); mRoutesAdapter.remove(mRoutesAdapter.getItem(which));
mRoutesAdapter.notifyDataSetChanged(); mRoutesAdapter.notifyDataSetChanged();
} }
}; };
@AfterViews @AfterViews
void afterViews() { void afterViews() {
setTitle(R.string.favorite_routes); setTitle(R.string.favorite_routes);
mRoutesAdapter = new FavoritesArrayAdapter(this, mRoutesAdapter = new FavoritesArrayAdapter(this,
R.layout.favorite_listing, app.getFavorites()); R.layout.favorite_listing, app.getFavorites());
setListAdapter(mRoutesAdapter); setListAdapter(mRoutesAdapter);
listView.setEmptyView(findViewById(android.R.id.empty)); listView.setEmptyView(findViewById(android.R.id.empty));
listView.setDropListener(onDrop); listView.setDropListener(onDrop);
listView.setRemoveListener(onRemove); listView.setRemoveListener(onRemove);
if (mCurrentAlerts != null) { if (mCurrentAlerts != null) {
showAlertMessage(mCurrentAlerts); showAlertMessage(mCurrentAlerts);
} }
startEtdListeners(); startEtdListeners();
refreshFares(); refreshFares();
} }
/** Called when the activity is first created. */ /**
@Override * Called when the activity is first created.
public void onCreate(Bundle savedInstanceState) { */
super.onCreate(savedInstanceState); @Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) { super.onCreate(savedInstanceState);
if (savedInstanceState.getBoolean("hasActionMode")) {
startContextualActionMode(); if (savedInstanceState != null) {
} if (savedInstanceState.getBoolean("hasActionMode")) {
} startContextualActionMode();
}
Ticker.getInstance().addSubscriber(this, getApplicationContext()); }
}
Ticker.getInstance().addSubscriber(this, getApplicationContext());
private AdapterView<ListAdapter> getListView() { }
return listView;
} private AdapterView<ListAdapter> getListView() {
return listView;
protected FavoritesArrayAdapter getListAdapter() { }
return mRoutesAdapter;
} protected FavoritesArrayAdapter getListAdapter() {
return mRoutesAdapter;
protected void setListAdapter(FavoritesArrayAdapter adapter) { }
mRoutesAdapter = adapter;
getListView().setAdapter(mRoutesAdapter); protected void setListAdapter(FavoritesArrayAdapter adapter) {
} mRoutesAdapter = adapter;
getListView().setAdapter(mRoutesAdapter);
void addFavorite(StationPair pair) { }
mRoutesAdapter.add(pair);
} void addFavorite(StationPair pair) {
mRoutesAdapter.add(pair);
private void refreshFares() { }
for (int i = getListAdapter().getCount() - 1; i >= 0; i--) {
final StationPair stationPair = getListAdapter().getItem(i); private void refreshFares() {
for (int i = getListAdapter().getCount() - 1; i >= 0; i--) {
Calendar now = Calendar.getInstance(); final StationPair stationPair = getListAdapter().getItem(i);
Calendar lastUpdate = Calendar.getInstance();
lastUpdate.setTimeInMillis(stationPair.getFareLastUpdated()); Calendar now = Calendar.getInstance();
Calendar lastUpdate = Calendar.getInstance();
now.setTimeZone(PACIFIC_TIME); lastUpdate.setTimeInMillis(stationPair.getFareLastUpdated());
lastUpdate.setTimeZone(PACIFIC_TIME);
now.setTimeZone(PACIFIC_TIME);
// Update every day lastUpdate.setTimeZone(PACIFIC_TIME);
if (now.get(Calendar.DAY_OF_YEAR) != lastUpdate
.get(Calendar.DAY_OF_YEAR) // Update every day
|| now.get(Calendar.YEAR) != lastUpdate.get(Calendar.YEAR)) { if (now.get(Calendar.DAY_OF_YEAR) != lastUpdate
GetRouteFareTask fareTask = new GetRouteFareTask() { .get(Calendar.DAY_OF_YEAR)
@Override || now.get(Calendar.YEAR) != lastUpdate.get(Calendar.YEAR)) {
public void onResult(String fare) { GetRouteFareTask fareTask = new GetRouteFareTask() {
stationPair.setFare(fare); @Override
stationPair.setFareLastUpdated(System public void onResult(String fare) {
.currentTimeMillis()); stationPair.setFare(fare);
getListAdapter().notifyDataSetChanged(); stationPair.setFareLastUpdated(System
} .currentTimeMillis());
getListAdapter().notifyDataSetChanged();
@Override }
public void onError(Exception exception) {
// Ignore... we can do this later @Override
} public void onError(Exception exception) {
}; // Ignore... we can do this later
fareTask.execute(new GetRouteFareTask.Params(stationPair }
.getOrigin(), stationPair.getDestination())); };
} fareTask.execute(new GetRouteFareTask.Params(stationPair
} .getOrigin(), stationPair.getDestination()));
} }
}
@Override }
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); @Override
outState.putBoolean("hasActionMode", mActionMode != null); protected void onSaveInstanceState(Bundle outState) {
} super.onSaveInstanceState(outState);
outState.putBoolean("hasActionMode", mActionMode != null);
@Override }
protected void onResume() {
super.onResume(); @Override
Ticker.getInstance().startTicking(this); protected void onResume() {
startEtdListeners(); super.onResume();
} Ticker.getInstance().startTicking(this);
startEtdListeners();
private void startEtdListeners() { }
if (mRoutesAdapter != null && !mRoutesAdapter.isEmpty()
&& !mRoutesAdapter.areEtdListenersActive()) { private void startEtdListeners() {
mRoutesAdapter.setUpEtdListeners(); if (mRoutesAdapter != null && !mRoutesAdapter.isEmpty()
} && !mRoutesAdapter.areEtdListenersActive()) {
} mRoutesAdapter.setUpEtdListeners();
}
@Override }
protected void onPause() {
super.onPause(); @Override
if (mRoutesAdapter != null && mRoutesAdapter.areEtdListenersActive()) { protected void onPause() {
mRoutesAdapter.clearEtdListeners(); super.onPause();
} if (mRoutesAdapter != null && mRoutesAdapter.areEtdListenersActive()) {
} mRoutesAdapter.clearEtdListeners();
}
@Override }
protected void onStop() {
super.onStop(); @Override
Ticker.getInstance().stopTicking(this); protected void onStop() {
app.saveFavorites(); super.onStop();
Ticker.getInstance().stopTicking(this);
} app.saveFavorites();
@Override }
protected void onDestroy() {
super.onDestroy(); @Override
if (mRoutesAdapter != null) { protected void onDestroy() {
mRoutesAdapter.close(); super.onDestroy();
} if (mRoutesAdapter != null) {
} mRoutesAdapter.close();
}
@Override }
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus); @Override
if (hasFocus) { public void onWindowFocusChanged(boolean hasFocus) {
Ticker.getInstance().startTicking(this); super.onWindowFocusChanged(hasFocus);
} if (hasFocus) {
} Ticker.getInstance().startTicking(this);
}
public boolean onCreateOptionsMenu(Menu menu) { }
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.routes_list_menu, menu); public boolean onCreateOptionsMenu(Menu menu) {
return super.onCreateOptionsMenu(menu); MenuInflater inflater = getSupportMenuInflater();
} inflater.inflate(R.menu.routes_list_menu, menu);
return super.onCreateOptionsMenu(menu);
private MenuItem elevatorMenuItem; }
private View origElevatorActionView;
private MenuItem elevatorMenuItem;
public boolean onOptionsItemSelected(MenuItem item) { private View origElevatorActionView;
int itemId = item.getItemId();
if (itemId == R.id.add_favorite_menu_button) { public boolean onOptionsItemSelected(MenuItem item) {
new AddRouteDialogFragment().show(getSupportFragmentManager() int itemId = item.getItemId();
.beginTransaction()); if (itemId == R.id.add_favorite_menu_button) {
return true; new AddRouteDialogFragment().show(getSupportFragmentManager()
} else if (itemId == R.id.view_system_map_button) { .beginTransaction());
startActivity(new Intent(this, ViewMapActivity.class)); return true;
return true; } else if (itemId == R.id.view_system_map_button) {
} else if (itemId == R.id.elevator_button) { startActivity(new Intent(this, ViewMapActivity.class));
elevatorMenuItem = item; return true;
fetchElevatorInfo(); } else if (itemId == R.id.elevator_button) {
origElevatorActionView = elevatorMenuItem.getActionView(); elevatorMenuItem = item;
elevatorMenuItem.setActionView(R.layout.progress_spinner); fetchElevatorInfo();
return true; origElevatorActionView = elevatorMenuItem.getActionView();
} else { elevatorMenuItem.setActionView(R.layout.progress_spinner);
return super.onOptionsItemSelected(item); return true;
} } else {
} return super.onOptionsItemSelected(item);
}
@Background }
void fetchAlerts() {
Log.d(TAG, "Fetching alerts"); @Background
AlertList alertList = alertsClient.getAlerts(); void fetchAlerts() {
if (alertList.hasAlerts()) { Log.d(TAG, "Fetching alerts");
StringBuilder alertText = new StringBuilder(); AlertList alertList = alertsClient.getAlerts();
boolean firstAlert = true; if (alertList.hasAlerts()) {
for (Alert alert : alertList.getAlerts()) { StringBuilder alertText = new StringBuilder();
if (!firstAlert) { boolean firstAlert = true;
alertText.append("\n\n"); for (Alert alert : alertList.getAlerts()) {
} if (!firstAlert) {
alertText.append(alert.getPostedTime()).append("\n"); alertText.append("\n\n");
alertText.append(alert.getDescription()); }
firstAlert = false; alertText.append(alert.getPostedTime()).append("\n");
} alertText.append(alert.getDescription());
showAlertMessage(alertText.toString()); firstAlert = false;
} else if (alertList.areNoDelaysReported()) { }
showAlertMessage(NO_DELAYS_REPORTED); showAlertMessage(alertText.toString());
} else { } else if (alertList.areNoDelaysReported()) {
hideAlertMessage(); showAlertMessage(NO_DELAYS_REPORTED);
} } else {
} hideAlertMessage();
}
@UiThread }
void hideAlertMessage() {
mCurrentAlerts = null; @UiThread
alertMessages.setVisibility(View.GONE); void hideAlertMessage() {
} mCurrentAlerts = null;
alertMessages.setVisibility(View.GONE);
@UiThread }
void showAlertMessage(String messageText) {
if (messageText == null) { @UiThread
hideAlertMessage(); void showAlertMessage(String messageText) {
return; if (messageText == null) {
} else if (messageText == NO_DELAYS_REPORTED) { hideAlertMessage();
alertMessages.setCompoundDrawablesWithIntrinsicBounds( return;
R.drawable.ic_allgood, 0, 0, 0); } else if (messageText == NO_DELAYS_REPORTED) {
} else { alertMessages.setCompoundDrawablesWithIntrinsicBounds(
alertMessages.setCompoundDrawablesWithIntrinsicBounds( R.drawable.ic_allgood, 0, 0, 0);
R.drawable.ic_warn, 0, 0, 0); } else {
} alertMessages.setCompoundDrawablesWithIntrinsicBounds(
mCurrentAlerts = messageText; R.drawable.ic_warn, 0, 0, 0);
alertMessages.setText(messageText); }
alertMessages.setVisibility(View.VISIBLE); mCurrentAlerts = messageText;
} alertMessages.setText(messageText);
alertMessages.setVisibility(View.VISIBLE);
@Background }
void fetchElevatorInfo() {
String elevatorMessage = elevatorClient.getElevatorMessage(); @Background
if (elevatorMessage != null) { void fetchElevatorInfo() {
showElevatorMessage(elevatorMessage); String elevatorMessage = elevatorClient.getElevatorMessage();
} if (elevatorMessage != null) {
resetElevatorMenuGraphic(); showElevatorMessage(elevatorMessage);
} }
resetElevatorMenuGraphic();
@UiThread }
void resetElevatorMenuGraphic() {
ActivityCompat.invalidateOptionsMenu(this); @UiThread
elevatorMenuItem.setActionView(origElevatorActionView); void resetElevatorMenuGraphic() {
} ActivityCompat.invalidateOptionsMenu(this);
elevatorMenuItem.setActionView(origElevatorActionView);
@UiThread }
void showElevatorMessage(String message) {
Builder builder = new AlertDialog.Builder(this); @UiThread
builder.setMessage(message); void showElevatorMessage(String message) {
builder.setTitle("Elevator status"); Builder builder = new AlertDialog.Builder(this);
builder.show(); builder.setMessage(message);
} builder.setTitle("Elevator status");
builder.show();
private void startContextualActionMode() { }
mActionMode = startActionMode(new RouteActionMode());
mActionMode.setTitle(mCurrentlySelectedStationPair.getOrigin().name); private void startContextualActionMode() {
mActionMode.setSubtitle("to " mActionMode = startActionMode(new RouteActionMode());
+ mCurrentlySelectedStationPair.getDestination().name); mActionMode.setTitle(mCurrentlySelectedStationPair.getOrigin().name);
} mActionMode.setSubtitle("to "
+ mCurrentlySelectedStationPair.getDestination().name);
private final class RouteActionMode implements ActionMode.Callback { }
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) { private final class RouteActionMode implements ActionMode.Callback {
mode.getMenuInflater().inflate(R.menu.route_context_menu, menu); @Override
return true; public boolean onCreateActionMode(ActionMode mode, Menu menu) {
} mode.getMenuInflater().inflate(R.menu.route_context_menu, menu);
return true;
@Override }
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false; @Override
} public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
@Override }
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (item.getItemId() == R.id.view) { @Override
Intent intent = new Intent(RoutesListActivity.this, public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
ViewDeparturesActivity.class); if (item.getItemId() == R.id.view) {
intent.putExtra(Constants.STATION_PAIR_EXTRA, Intent intent = new Intent(RoutesListActivity.this,
mCurrentlySelectedStationPair); ViewDeparturesActivity.class);
startActivity(intent); intent.putExtra(Constants.STATION_PAIR_EXTRA,
mode.finish(); mCurrentlySelectedStationPair);
return true; startActivity(intent);
} else if (item.getItemId() == R.id.delete) { mode.finish();
final AlertDialog.Builder builder = new AlertDialog.Builder( return true;
RoutesListActivity.this); } else if (item.getItemId() == R.id.delete) {
builder.setCancelable(false); final AlertDialog.Builder builder = new AlertDialog.Builder(
builder.setMessage("Are you sure you want to delete this route?"); RoutesListActivity.this);
builder.setPositiveButton(R.string.yes, builder.setCancelable(false);
new DialogInterface.OnClickListener() { builder.setMessage("Are you sure you want to delete this route?");
public void onClick(DialogInterface dialog, builder.setPositiveButton(R.string.yes,
int which) { new DialogInterface.OnClickListener() {
getListAdapter().remove( public void onClick(DialogInterface dialog,
mCurrentlySelectedStationPair); int which) {
mCurrentlySelectedStationPair = null; getListAdapter().remove(
mActionMode.finish(); mCurrentlySelectedStationPair);
dialog.dismiss(); mCurrentlySelectedStationPair = null;
} mActionMode.finish();
}); dialog.dismiss();
builder.setNegativeButton(R.string.cancel, }
new DialogInterface.OnClickListener() { });
public void onClick(DialogInterface dialog, builder.setNegativeButton(R.string.cancel,
int which) { new DialogInterface.OnClickListener() {
dialog.cancel(); public void onClick(DialogInterface dialog,
} int which) {
}); dialog.cancel();
builder.show(); }
return false; });
} builder.show();
return false;
return false; }
}
return false;
@Override }
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null; @Override
} public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
} }
@Override }
public int getTickInterval() {
return 90; @Override
} public int getTickInterval() {
return 90;
@Override }
public void onTick(long mTickCount) {
fetchAlerts(); @Override
} public void onTick(long mTickCount) {
fetchAlerts();
}
} }

View File

@ -20,99 +20,99 @@ import com.dougkeen.bart.model.Departure;
public class TrainAlarmDialogFragment extends DialogFragment { public class TrainAlarmDialogFragment extends DialogFragment {
private static final String KEY_LAST_ALARM_LEAD_TIME = "lastAlarmLeadTime"; private static final String KEY_LAST_ALARM_LEAD_TIME = "lastAlarmLeadTime";
public TrainAlarmDialogFragment() { public TrainAlarmDialogFragment() {
super(); super();
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setShowsDialog(true); setShowsDialog(true);
} }
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
setUpNumberPickerValues(getDialog()); setUpNumberPickerValues(getDialog());
} }
private void setUpNumberPickerValues(Dialog dialog) { private void setUpNumberPickerValues(Dialog dialog) {
SharedPreferences preferences = getActivity().getPreferences( SharedPreferences preferences = getActivity().getPreferences(
Context.MODE_PRIVATE); Context.MODE_PRIVATE);
int lastAlarmLeadTime = preferences.getInt(KEY_LAST_ALARM_LEAD_TIME, 5); int lastAlarmLeadTime = preferences.getInt(KEY_LAST_ALARM_LEAD_TIME, 5);
NumberPicker numberPicker = (NumberPicker) dialog NumberPicker numberPicker = (NumberPicker) dialog
.findViewById(R.id.numberPicker); .findViewById(R.id.numberPicker);
BartRunnerApplication application = (BartRunnerApplication) getActivity() BartRunnerApplication application = (BartRunnerApplication) getActivity()
.getApplication(); .getApplication();
final Departure boardedDeparture = application.getBoardedDeparture(); final Departure boardedDeparture = application.getBoardedDeparture();
final int maxValue = boardedDeparture.getMeanSecondsLeft() / 60; final int maxValue = boardedDeparture.getMeanSecondsLeft() / 60;
String[] displayedValues = new String[maxValue]; String[] displayedValues = new String[maxValue];
for (int i = 1; i <= maxValue; i++) { for (int i = 1; i <= maxValue; i++) {
displayedValues[i - 1] = String.valueOf(i); displayedValues[i - 1] = String.valueOf(i);
} }
numberPicker.setMinValue(1); numberPicker.setMinValue(1);
numberPicker.setMaxValue(maxValue); numberPicker.setMaxValue(maxValue);
numberPicker.setDisplayedValues(displayedValues); numberPicker.setDisplayedValues(displayedValues);
if (boardedDeparture.isAlarmPending()) { if (boardedDeparture.isAlarmPending()) {
numberPicker.setValue(boardedDeparture.getAlarmLeadTimeMinutes()); numberPicker.setValue(boardedDeparture.getAlarmLeadTimeMinutes());
} else if (maxValue >= lastAlarmLeadTime) { } else if (maxValue >= lastAlarmLeadTime) {
numberPicker.setValue(lastAlarmLeadTime); numberPicker.setValue(lastAlarmLeadTime);
} else if (maxValue >= 5) { } else if (maxValue >= 5) {
numberPicker.setValue(5); numberPicker.setValue(5);
} else if (maxValue >= 3) { } else if (maxValue >= 3) {
numberPicker.setValue(3); numberPicker.setValue(3);
} else { } else {
numberPicker.setValue(1); numberPicker.setValue(1);
} }
} }
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final FragmentActivity activity = getActivity(); final FragmentActivity activity = getActivity();
final View dialogView = LayoutInflater.inflate(activity, final View dialogView = LayoutInflater.inflate(activity,
R.layout.train_alarm_dialog); R.layout.train_alarm_dialog);
return new AlertDialog.Builder(activity) return new AlertDialog.Builder(activity)
.setTitle(R.string.set_up_departure_alarm) .setTitle(R.string.set_up_departure_alarm)
.setCancelable(true) .setCancelable(true)
.setView(dialogView) .setView(dialogView)
.setPositiveButton(R.string.ok, .setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, public void onClick(DialogInterface dialog,
int which) { int which) {
NumberPicker numberPicker = (NumberPicker) getDialog() NumberPicker numberPicker = (NumberPicker) getDialog()
.findViewById(R.id.numberPicker); .findViewById(R.id.numberPicker);
final int alarmLeadTime = numberPicker final int alarmLeadTime = numberPicker
.getValue(); .getValue();
// Save most recent selection // Save most recent selection
Editor editor = getActivity().getPreferences( Editor editor = getActivity().getPreferences(
Context.MODE_PRIVATE).edit(); Context.MODE_PRIVATE).edit();
editor.putInt(KEY_LAST_ALARM_LEAD_TIME, editor.putInt(KEY_LAST_ALARM_LEAD_TIME,
alarmLeadTime); alarmLeadTime);
editor.commit(); editor.commit();
((BartRunnerApplication) getActivity() ((BartRunnerApplication) getActivity()
.getApplication()) .getApplication())
.getBoardedDeparture().setUpAlarm( .getBoardedDeparture().setUpAlarm(
alarmLeadTime); alarmLeadTime);
} }
}) })
.setNegativeButton(R.string.cancel, .setNegativeButton(R.string.cancel,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, public void onClick(DialogInterface dialog,
int whichButton) { int whichButton) {
dialog.cancel(); dialog.cancel();
} }
}).create(); }).create();
} }
} }

View File

@ -12,36 +12,36 @@ import com.dougkeen.bart.R;
public class ViewMapActivity extends Activity { public class ViewMapActivity extends Activity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
WebView webview = new WebView(this); WebView webview = new WebView(this);
setContentView(webview); setContentView(webview);
webview.getSettings().setBuiltInZoomControls(true); webview.getSettings().setBuiltInZoomControls(true);
webview.getSettings().setSupportZoom(true); webview.getSettings().setSupportZoom(true);
webview.loadUrl("file:///android_res/drawable/map.png"); webview.loadUrl("file:///android_res/drawable/map.png");
getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater(); MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.system_map_menu, menu); inflater.inflate(R.menu.system_map_menu, menu);
return true; return true;
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) { if (item.getItemId() == android.R.id.home) {
finish(); finish();
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
} }

View File

@ -7,51 +7,51 @@ import android.widget.TextView;
import com.dougkeen.bart.model.TextProvider; import com.dougkeen.bart.model.TextProvider;
public class CountdownTextView extends TextView implements public class CountdownTextView extends TextView implements
Ticker.TickSubscriber { Ticker.TickSubscriber {
private TextProvider mTextProvider; private TextProvider mTextProvider;
private int mTickInterval; private int mTickInterval;
public CountdownTextView(Context context) { public CountdownTextView(Context context) {
super(context); super(context);
} }
public CountdownTextView(Context context, AttributeSet attrs, int defStyle) { public CountdownTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
setInstanceVarsFromAttrs(attrs); setInstanceVarsFromAttrs(attrs);
} }
public CountdownTextView(Context context, AttributeSet attrs) { public CountdownTextView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
setInstanceVarsFromAttrs(attrs); setInstanceVarsFromAttrs(attrs);
} }
private void setInstanceVarsFromAttrs(AttributeSet attrs) { private void setInstanceVarsFromAttrs(AttributeSet attrs) {
int tickInterval = attrs.getAttributeIntValue( int tickInterval = attrs.getAttributeIntValue(
"http://schemas.android.com/apk/res/com.dougkeen.bart", "http://schemas.android.com/apk/res/com.dougkeen.bart",
"tickInterval", 0); "tickInterval", 0);
if (tickInterval > 0) { if (tickInterval > 0) {
setTickInterval(tickInterval); setTickInterval(tickInterval);
} }
} }
public void setTextProvider(TextProvider provider) { public void setTextProvider(TextProvider provider) {
mTextProvider = provider; mTextProvider = provider;
Ticker.getInstance().addSubscriber(this, getContext()); Ticker.getInstance().addSubscriber(this, getContext());
} }
@Override @Override
public int getTickInterval() { public int getTickInterval() {
return mTickInterval; return mTickInterval;
} }
public void setTickInterval(int tickInterval) { public void setTickInterval(int tickInterval) {
this.mTickInterval = tickInterval; this.mTickInterval = tickInterval;
} }
@Override @Override
public void onTick(long tickNumber) { public void onTick(long tickNumber) {
setText(mTextProvider.getText(tickNumber)); setText(mTextProvider.getText(tickNumber));
} }
} }

View File

@ -8,35 +8,35 @@ import android.widget.RelativeLayout;
import com.dougkeen.bart.R; import com.dougkeen.bart.R;
public class DepartureListItemLayout extends RelativeLayout implements public class DepartureListItemLayout extends RelativeLayout implements
Checkable { Checkable {
public DepartureListItemLayout(Context context) { public DepartureListItemLayout(Context context) {
super(context); super(context);
LayoutInflater.from(context).inflate(R.layout.departure_listing, this, LayoutInflater.from(context).inflate(R.layout.departure_listing, this,
true); true);
} }
private boolean mChecked; private boolean mChecked;
@Override @Override
public boolean isChecked() { public boolean isChecked() {
return mChecked; return mChecked;
} }
@Override @Override
public void setChecked(boolean checked) { public void setChecked(boolean checked) {
mChecked = checked; mChecked = checked;
if (isChecked()) { if (isChecked()) {
setBackgroundDrawable(getContext().getResources().getDrawable( setBackgroundDrawable(getContext().getResources().getDrawable(
R.color.blue_selection)); R.color.blue_selection));
} else { } else {
setBackgroundDrawable(getContext().getResources().getDrawable( setBackgroundDrawable(getContext().getResources().getDrawable(
android.R.color.transparent)); android.R.color.transparent));
} }
} }
@Override @Override
public void toggle() { public void toggle() {
setChecked(!isChecked()); setChecked(!isChecked());
} }
} }

View File

@ -22,6 +22,7 @@ package com.dougkeen.bart.controls;
import static com.nineoldandroids.view.ViewHelper.setAlpha; import static com.nineoldandroids.view.ViewHelper.setAlpha;
import static com.nineoldandroids.view.ViewHelper.setTranslationX; import static com.nineoldandroids.view.ViewHelper.setTranslationX;
import static com.nineoldandroids.view.ViewPropertyAnimator.animate; import static com.nineoldandroids.view.ViewPropertyAnimator.animate;
import android.util.Log; import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.VelocityTracker; import android.view.VelocityTracker;
@ -40,7 +41,7 @@ import com.nineoldandroids.animation.ValueAnimator;
* callback). Also, a {@link android.view.View.OnTouchListener} that makes any * callback). Also, a {@link android.view.View.OnTouchListener} that makes any
* {@link View} dismissable when the user swipes (drags her finger) horizontally * {@link View} dismissable when the user swipes (drags her finger) horizontally
* across the view. * across the view.
* * <p>
* <p> * <p>
* <em>For {@link android.widget.ListView} list items that don't manage their own touch events * <em>For {@link android.widget.ListView} list items that don't manage their own touch events
* (i.e. you're using * (i.e. you're using
@ -48,11 +49,11 @@ import com.nineoldandroids.animation.ValueAnimator;
* or an equivalent listener on {@link android.app.ListActivity} or * or an equivalent listener on {@link android.app.ListActivity} or
* {@link android.app.ListFragment}, use {@link SwipeDismissListViewTouchListener} instead.</em> * {@link android.app.ListFragment}, use {@link SwipeDismissListViewTouchListener} instead.</em>
* </p> * </p>
* * <p>
* <p> * <p>
* Example usage: * Example usage:
* </p> * </p>
* * <p>
* <pre> * <pre>
* view.setOnTouchListener(new SwipeDismisser(view, null, // Optional * view.setOnTouchListener(new SwipeDismisser(view, null, // Optional
* // token/cookie * // token/cookie
@ -60,256 +61,251 @@ import com.nineoldandroids.animation.ValueAnimator;
* new SwipeDismisser.OnDismissCallback() { * new SwipeDismisser.OnDismissCallback() {
* public void onDismiss(View view, Object token) { * public void onDismiss(View view, Object token) {
* parent.removeView(view); * parent.removeView(view);
* } * }
* })); * }));
* </pre> * </pre>
* *
* @see SwipeDismissListViewTouchListener * @see SwipeDismissListViewTouchListener
*/ */
public class SwipeHelper implements View.OnTouchListener { public class SwipeHelper implements View.OnTouchListener {
// Cached ViewConfiguration and system-wide constant values // Cached ViewConfiguration and system-wide constant values
private int mSlop; private int mSlop;
private int mMinFlingVelocity; private int mMinFlingVelocity;
private int mMaxFlingVelocity; private int mMaxFlingVelocity;
private long mAnimationTime; private long mAnimationTime;
// Fixed properties // Fixed properties
private View mView; private View mView;
private OnDismissCallback mCallback; private OnDismissCallback mCallback;
private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
// Transient properties // Transient properties
private float mDownX; private float mDownX;
private boolean mSwiping; private boolean mSwiping;
private Object mToken; private Object mToken;
private VelocityTracker mVelocityTracker; private VelocityTracker mVelocityTracker;
private float mTranslationX; private float mTranslationX;
/** /**
* The callback interface used by {@link SwipeHelper} to inform its client * The callback interface used by {@link SwipeHelper} to inform its client
* about a successful dismissal of the view for which it was created. * about a successful dismissal of the view for which it was created.
*/ */
public interface OnDismissCallback { public interface OnDismissCallback {
/** /**
* Called when the user has indicated they she would like to dismiss the * Called when the user has indicated they she would like to dismiss the
* view. * view.
* *
* @param view * @param view The originating {@link View} to be dismissed.
* The originating {@link View} to be dismissed. * @param token The optional token passed to this object's constructor.
* @param token */
* The optional token passed to this object's constructor. void onDismiss(View view, Object token);
*/ }
void onDismiss(View view, Object token);
}
/** /**
* Constructs a new swipe-to-dismiss touch listener for the given view. * Constructs a new swipe-to-dismiss touch listener for the given view.
* *
* @param view * @param view The view to make dismissable.
* The view to make dismissable. * @param token An optional token/cookie object to be passed through to the
* @param token * callback.
* An optional token/cookie object to be passed through to the * @param callback The callback to trigger when the user has indicated that she
* callback. * would like to dismiss this view.
* @param callback */
* The callback to trigger when the user has indicated that she public SwipeHelper(View view, Object token, OnDismissCallback callback) {
* would like to dismiss this view. ViewConfiguration vc = ViewConfiguration.get(view.getContext());
*/ mSlop = vc.getScaledTouchSlop();
public SwipeHelper(View view, Object token, OnDismissCallback callback) { mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
ViewConfiguration vc = ViewConfiguration.get(view.getContext()); mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
mSlop = vc.getScaledTouchSlop(); mAnimationTime = view.getContext().getResources()
mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); .getInteger(android.R.integer.config_shortAnimTime);
mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); mView = view;
mAnimationTime = view.getContext().getResources() mToken = token;
.getInteger(android.R.integer.config_shortAnimTime); mCallback = callback;
mView = view; }
mToken = token;
mCallback = callback;
}
@Override @Override
public boolean onTouch(View view, MotionEvent motionEvent) { public boolean onTouch(View view, MotionEvent motionEvent) {
Log.v(Constants.TAG, "onTouch()"); Log.v(Constants.TAG, "onTouch()");
// offset because the view is translated during swipe // offset because the view is translated during swipe
motionEvent.offsetLocation(mTranslationX, 0); motionEvent.offsetLocation(mTranslationX, 0);
if (mViewWidth < 2) { if (mViewWidth < 2) {
mViewWidth = mView.getWidth(); mViewWidth = mView.getWidth();
} }
switch (motionEvent.getActionMasked()) { switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN: { case MotionEvent.ACTION_DOWN: {
// TODO: ensure this is a finger, and set a flag // TODO: ensure this is a finger, and set a flag
mDownX = motionEvent.getRawX(); mDownX = motionEvent.getRawX();
mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(motionEvent); mVelocityTracker.addMovement(motionEvent);
view.onTouchEvent(motionEvent); view.onTouchEvent(motionEvent);
return false; return false;
} }
case MotionEvent.ACTION_UP: { case MotionEvent.ACTION_UP: {
if (mVelocityTracker == null) { if (mVelocityTracker == null) {
break; break;
} }
float deltaX = motionEvent.getRawX() - mDownX; float deltaX = motionEvent.getRawX() - mDownX;
mVelocityTracker.addMovement(motionEvent); mVelocityTracker.addMovement(motionEvent);
mVelocityTracker.computeCurrentVelocity(1000); mVelocityTracker.computeCurrentVelocity(1000);
float velocityX = Math.abs(mVelocityTracker.getXVelocity()); float velocityX = Math.abs(mVelocityTracker.getXVelocity());
float velocityY = Math.abs(mVelocityTracker.getYVelocity()); float velocityY = Math.abs(mVelocityTracker.getYVelocity());
boolean dismiss = false; boolean dismiss = false;
boolean dismissRight = false; boolean dismissRight = false;
if (Math.abs(deltaX) > mViewWidth / 2) { if (Math.abs(deltaX) > mViewWidth / 2) {
dismiss = true; dismiss = true;
dismissRight = deltaX > 0; dismissRight = deltaX > 0;
} else if (mMinFlingVelocity <= velocityX } else if (mMinFlingVelocity <= velocityX
&& velocityX <= mMaxFlingVelocity && velocityY < velocityX) { && velocityX <= mMaxFlingVelocity && velocityY < velocityX) {
dismiss = true; dismiss = true;
dismissRight = mVelocityTracker.getXVelocity() > 0; dismissRight = mVelocityTracker.getXVelocity() > 0;
} }
if (dismiss) { if (dismiss) {
// dismiss // dismiss
dismissWithAnimation(dismissRight); dismissWithAnimation(dismissRight);
} else { } else {
// cancel // cancel
animate(mView).translationX(0).alpha(1) animate(mView).translationX(0).alpha(1)
.setDuration(mAnimationTime).setListener(null); .setDuration(mAnimationTime).setListener(null);
} }
mVelocityTracker = null; mVelocityTracker = null;
mTranslationX = 0; mTranslationX = 0;
mDownX = 0; mDownX = 0;
mSwiping = false; mSwiping = false;
break; break;
} }
case MotionEvent.ACTION_MOVE: { case MotionEvent.ACTION_MOVE: {
if (mVelocityTracker == null) { if (mVelocityTracker == null) {
break; break;
} }
mVelocityTracker.addMovement(motionEvent); mVelocityTracker.addMovement(motionEvent);
float deltaX = motionEvent.getRawX() - mDownX; float deltaX = motionEvent.getRawX() - mDownX;
if (Math.abs(deltaX) > mSlop) { if (Math.abs(deltaX) > mSlop) {
mSwiping = true; mSwiping = true;
mView.getParent().requestDisallowInterceptTouchEvent(true); mView.getParent().requestDisallowInterceptTouchEvent(true);
// Cancel listview's touch // Cancel listview's touch
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent); MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
cancelEvent cancelEvent
.setAction(MotionEvent.ACTION_CANCEL .setAction(MotionEvent.ACTION_CANCEL
| (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); | (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
mView.onTouchEvent(cancelEvent); mView.onTouchEvent(cancelEvent);
} }
if (mSwiping) { if (mSwiping) {
mTranslationX = deltaX; mTranslationX = deltaX;
setTranslationX(mView, deltaX); setTranslationX(mView, deltaX);
// TODO: use an ease-out interpolator or such // TODO: use an ease-out interpolator or such
setAlpha( setAlpha(
mView, mView,
Math.max( Math.max(
0f, 0f,
Math.min(1f, 1f - 2f * Math.abs(deltaX) Math.min(1f, 1f - 2f * Math.abs(deltaX)
/ mViewWidth))); / mViewWidth)));
return true; return true;
} }
break; break;
} }
} }
return false; return false;
} }
public void dismissWithAnimation(boolean dismissRight) { public void dismissWithAnimation(boolean dismissRight) {
animate(mView).translationX(dismissRight ? mViewWidth : -mViewWidth) animate(mView).translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0).setDuration(mAnimationTime) .alpha(0).setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() { .setListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
performDismiss(); performDismiss();
} }
}); });
} }
private void performDismiss() { private void performDismiss() {
// Animate the dismissed view to zero-height and then fire the dismiss // Animate the dismissed view to zero-height and then fire the dismiss
// callback. // callback.
// This triggers layout on each animation frame; in the future we may // This triggers layout on each animation frame; in the future we may
// want to do something // want to do something
// smarter and more performant. // smarter and more performant.
final ViewGroup.LayoutParams lp = mView.getLayoutParams(); final ViewGroup.LayoutParams lp = mView.getLayoutParams();
final int originalHeight = mView.getHeight(); final int originalHeight = mView.getHeight();
ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1) ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1)
.setDuration(mAnimationTime); .setDuration(mAnimationTime);
animator.addListener(new AnimatorListenerAdapter() { animator.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
mCallback.onDismiss(mView, mToken); mCallback.onDismiss(mView, mToken);
// Reset view presentation // Reset view presentation
/* /*
* Alpha stays at 0, otherwise Android 2.x leaves weird * Alpha stays at 0, otherwise Android 2.x leaves weird
* artifacts * artifacts
*/ */
// setAlpha(mView, 1f); // setAlpha(mView, 1f);
setTranslationX(mView, 0); setTranslationX(mView, 0);
lp.height = originalHeight; lp.height = originalHeight;
mView.setLayoutParams(lp); mView.setLayoutParams(lp);
} }
}); });
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override @Override
public void onAnimationUpdate(ValueAnimator valueAnimator) { public void onAnimationUpdate(ValueAnimator valueAnimator) {
lp.height = (Integer) valueAnimator.getAnimatedValue(); lp.height = (Integer) valueAnimator.getAnimatedValue();
mView.setLayoutParams(lp); mView.setLayoutParams(lp);
} }
}); });
animator.start(); animator.start();
} }
public void showWithAnimation() { public void showWithAnimation() {
final int measureSpec = MeasureSpec.makeMeasureSpec( final int measureSpec = MeasureSpec.makeMeasureSpec(
ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY); ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY);
mView.measure(measureSpec, measureSpec); mView.measure(measureSpec, measureSpec);
mViewWidth = mView.getMeasuredWidth(); mViewWidth = mView.getMeasuredWidth();
final int viewHeight = mView.getMeasuredHeight(); final int viewHeight = mView.getMeasuredHeight();
setAlpha(mView, 0f); setAlpha(mView, 0f);
final ViewGroup.LayoutParams lp = mView.getLayoutParams(); final ViewGroup.LayoutParams lp = mView.getLayoutParams();
lp.width = mViewWidth; lp.width = mViewWidth;
setTranslationX(mView, mViewWidth); setTranslationX(mView, mViewWidth);
// Grow space // Grow space
ValueAnimator animator = ValueAnimator.ofInt(1, viewHeight) ValueAnimator animator = ValueAnimator.ofInt(1, viewHeight)
.setDuration(mAnimationTime); .setDuration(mAnimationTime);
animator.addListener(new AnimatorListenerAdapter() { animator.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
// Reset view presentation // Reset view presentation
// mView.requestLayout(); // mView.requestLayout();
// Swipe view into space that opened up // Swipe view into space that opened up
animate(mView).translationX(0).alpha(1) animate(mView).translationX(0).alpha(1)
.setDuration(mAnimationTime) .setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() { .setListener(new AnimatorListenerAdapter() {
}); });
} }
}); });
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override @Override
public void onAnimationUpdate(ValueAnimator valueAnimator) { public void onAnimationUpdate(ValueAnimator valueAnimator) {
lp.height = (Integer) valueAnimator.getAnimatedValue(); lp.height = (Integer) valueAnimator.getAnimatedValue();
mView.setLayoutParams(lp); mView.setLayoutParams(lp);
} }
}); });
animator.start(); animator.start();
} }
} }

View File

@ -7,108 +7,108 @@ import android.content.Context;
import android.os.Handler; import android.os.Handler;
public class Ticker { public class Ticker {
public static interface TickSubscriber { public interface TickSubscriber {
int getTickInterval(); int getTickInterval();
void onTick(long mTickCount); void onTick(long mTickCount);
} }
private static Ticker sInstance; private static Ticker sInstance;
private WeakHashMap<TickSubscriber, Object> mSubscribers; private WeakHashMap<TickSubscriber, Object> mSubscribers;
private WeakHashMap<Context, Object> mTickerHosts; private WeakHashMap<Context, Object> mTickerHosts;
private TickerEngine mEngine; private TickerEngine mEngine;
private static class TickerEngine implements Runnable { private static class TickerEngine implements Runnable {
private static final int TICK_INTERVAL_MILLIS = 1000; private static final int TICK_INTERVAL_MILLIS = 1000;
private Ticker publisher; private Ticker publisher;
private Handler mHandler; private Handler mHandler;
private boolean mPendingRequest = false; private boolean mPendingRequest = false;
private boolean mForceStop = false; private boolean mForceStop = false;
private long mTickCount = 0; private long mTickCount = 0;
public TickerEngine(Ticker publisher) { public TickerEngine(Ticker publisher) {
this.publisher = publisher; this.publisher = publisher;
this.mHandler = new Handler(); this.mHandler = new Handler();
} }
@Override @Override
public void run() { public void run() {
mPendingRequest = false; mPendingRequest = false;
if (mForceStop) { if (mForceStop) {
mForceStop = false; mForceStop = false;
return; return;
} }
long startTimeNanos = System.nanoTime(); long startTimeNanos = System.nanoTime();
Iterator<TickSubscriber> iterator = publisher.mSubscribers.keySet() Iterator<TickSubscriber> iterator = publisher.mSubscribers.keySet()
.iterator(); .iterator();
boolean stillHasListeners = false; boolean stillHasListeners = false;
while (iterator.hasNext()) { while (iterator.hasNext()) {
TickSubscriber subscriber = iterator.next(); TickSubscriber subscriber = iterator.next();
if (subscriber == null) { if (subscriber == null) {
continue; continue;
} }
stillHasListeners = true; stillHasListeners = true;
if (subscriber.getTickInterval() > 0 if (subscriber.getTickInterval() > 0
&& mTickCount % subscriber.getTickInterval() == 0) && mTickCount % subscriber.getTickInterval() == 0)
subscriber.onTick(mTickCount); subscriber.onTick(mTickCount);
} }
long endTimeNanos = System.nanoTime(); long endTimeNanos = System.nanoTime();
if (stillHasListeners && !mPendingRequest) { if (stillHasListeners && !mPendingRequest) {
mHandler.postDelayed(this, TICK_INTERVAL_MILLIS mHandler.postDelayed(this, TICK_INTERVAL_MILLIS
- ((endTimeNanos - startTimeNanos) / 1000000)); - ((endTimeNanos - startTimeNanos) / 1000000));
mPendingRequest = true; mPendingRequest = true;
mTickCount++; mTickCount++;
} else { } else {
mPendingRequest = false; mPendingRequest = false;
} }
} }
public boolean isOn() { public boolean isOn() {
return mPendingRequest; return mPendingRequest;
} }
public void stop() { public void stop() {
mForceStop = true; mForceStop = true;
} }
}; }
public synchronized static Ticker getInstance() { public synchronized static Ticker getInstance() {
if (sInstance == null) { if (sInstance == null) {
sInstance = new Ticker(); sInstance = new Ticker();
} }
return sInstance; return sInstance;
} }
public void addSubscriber(TickSubscriber subscriber, Context host) { public void addSubscriber(TickSubscriber subscriber, Context host) {
if (!mSubscribers.containsKey(subscriber) && subscriber != null) { if (!mSubscribers.containsKey(subscriber) && subscriber != null) {
mSubscribers.put(subscriber, null); mSubscribers.put(subscriber, null);
startTicking(host); startTicking(host);
} }
} }
private Ticker() { private Ticker() {
mSubscribers = new WeakHashMap<TickSubscriber, Object>(); mSubscribers = new WeakHashMap<TickSubscriber, Object>();
mTickerHosts = new WeakHashMap<Context, Object>(); mTickerHosts = new WeakHashMap<Context, Object>();
mEngine = new TickerEngine(this); mEngine = new TickerEngine(this);
} }
public void startTicking(Context host) { public void startTicking(Context host) {
mTickerHosts.put(host, true); mTickerHosts.put(host, true);
if (!mEngine.isOn()) if (!mEngine.isOn())
mEngine.run(); mEngine.run();
} }
public void stopTicking(Context host) { public void stopTicking(Context host) {
mTickerHosts.remove(host); mTickerHosts.remove(host);
if (mEngine.isOn() && mTickerHosts.isEmpty()) if (mEngine.isOn() && mTickerHosts.isEmpty())
mEngine.stop(); mEngine.stop();
} }
} }

View File

@ -9,59 +9,59 @@ import android.widget.TextSwitcher;
import com.dougkeen.bart.model.TextProvider; import com.dougkeen.bart.model.TextProvider;
public class TimedTextSwitcher extends TextSwitcher implements public class TimedTextSwitcher extends TextSwitcher implements
Ticker.TickSubscriber { Ticker.TickSubscriber {
public TimedTextSwitcher(Context context, AttributeSet attrs) { public TimedTextSwitcher(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
setInstanceVarsFromAttrs(attrs); setInstanceVarsFromAttrs(attrs);
} }
public TimedTextSwitcher(Context context) { public TimedTextSwitcher(Context context) {
super(context); super(context);
} }
private void setInstanceVarsFromAttrs(AttributeSet attrs) { private void setInstanceVarsFromAttrs(AttributeSet attrs) {
int tickInterval = attrs.getAttributeIntValue( int tickInterval = attrs.getAttributeIntValue(
"http://schemas.android.com/apk/res/com.dougkeen.bart", "http://schemas.android.com/apk/res/com.dougkeen.bart",
"tickInterval", 0); "tickInterval", 0);
if (tickInterval > 0) { if (tickInterval > 0) {
setTickInterval(tickInterval); setTickInterval(tickInterval);
} }
} }
private int mTickInterval; private int mTickInterval;
private TextProvider mTextProvider; private TextProvider mTextProvider;
@Override @Override
public int getTickInterval() { public int getTickInterval() {
return mTickInterval; return mTickInterval;
} }
public void setTickInterval(int tickInterval) { public void setTickInterval(int tickInterval) {
this.mTickInterval = tickInterval; this.mTickInterval = tickInterval;
} }
public void setTextProvider(TextProvider textProvider) { public void setTextProvider(TextProvider textProvider) {
mTextProvider = textProvider; mTextProvider = textProvider;
Ticker.getInstance().addSubscriber(this, getContext()); Ticker.getInstance().addSubscriber(this, getContext());
} }
private CharSequence mLastText; private CharSequence mLastText;
@Override @Override
public void setCurrentText(CharSequence text) { public void setCurrentText(CharSequence text) {
mLastText = text; mLastText = text;
super.setCurrentText(text); super.setCurrentText(text);
} }
@Override @Override
public void onTick(long tickNumber) { public void onTick(long tickNumber) {
String text = mTextProvider.getText(tickNumber); String text = mTextProvider.getText(tickNumber);
if (StringUtils.isNotBlank(text) if (StringUtils.isNotBlank(text)
&& !StringUtils.equalsIgnoreCase(text, mLastText)) { && !StringUtils.equalsIgnoreCase(text, mLastText)) {
mLastText = text; mLastText = text;
setText(text); setText(text);
} }
} }
} }

View File

@ -20,167 +20,167 @@ import com.dougkeen.util.Observer;
public class YourTrainLayout extends RelativeLayout implements Checkable { public class YourTrainLayout extends RelativeLayout implements Checkable {
public YourTrainLayout(Context context) { public YourTrainLayout(Context context) {
super(context); super(context);
assignLayout(context); assignLayout(context);
} }
public YourTrainLayout(Context context, AttributeSet attrs, int defStyle) { public YourTrainLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
assignLayout(context); assignLayout(context);
} }
public YourTrainLayout(Context context, AttributeSet attrs) { public YourTrainLayout(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
assignLayout(context); assignLayout(context);
} }
public void assignLayout(Context context) { public void assignLayout(Context context) {
LayoutInflater.from(context).inflate(R.layout.your_train, this, true); LayoutInflater.from(context).inflate(R.layout.your_train, this, true);
} }
private boolean mChecked; private boolean mChecked;
private Departure mDeparture; private Departure mDeparture;
private final Observer<Integer> mAlarmLeadObserver = new Observer<Integer>() { private final Observer<Integer> mAlarmLeadObserver = new Observer<Integer>() {
@Override @Override
public void onUpdate(Integer newValue) { public void onUpdate(Integer newValue) {
final Activity context = (Activity) getContext(); final Activity context = (Activity) getContext();
if (context != null) { if (context != null) {
context.runOnUiThread(mUpdateAlarmIndicatorRunnable); context.runOnUiThread(mUpdateAlarmIndicatorRunnable);
} }
} }
}; };
private final Observer<Boolean> mAlarmPendingObserver = new Observer<Boolean>() { private final Observer<Boolean> mAlarmPendingObserver = new Observer<Boolean>() {
@Override @Override
public void onUpdate(Boolean newValue) { public void onUpdate(Boolean newValue) {
final Activity context = (Activity) getContext(); final Activity context = (Activity) getContext();
if (context != null) { if (context != null) {
context.runOnUiThread(mUpdateAlarmIndicatorRunnable); context.runOnUiThread(mUpdateAlarmIndicatorRunnable);
} }
} }
}; };
@Override @Override
public boolean isChecked() { public boolean isChecked() {
return mChecked; return mChecked;
} }
@Override @Override
public void setChecked(boolean checked) { public void setChecked(boolean checked) {
mChecked = checked; mChecked = checked;
setBackground(); setBackground();
} }
private void setBackground() { private void setBackground() {
if (isChecked()) { if (isChecked()) {
setBackgroundDrawable(getContext().getResources().getDrawable( setBackgroundDrawable(getContext().getResources().getDrawable(
R.color.blue_selection)); R.color.blue_selection));
} else { } else {
setBackgroundDrawable(getContext().getResources().getDrawable( setBackgroundDrawable(getContext().getResources().getDrawable(
R.color.gray)); R.color.gray));
} }
} }
@Override @Override
public void toggle() { public void toggle() {
setChecked(!isChecked()); setChecked(!isChecked());
} }
public void updateFromBoardedDeparture() { public void updateFromBoardedDeparture() {
final Departure boardedDeparture = ((BartRunnerApplication) ((Activity) getContext()) final Departure boardedDeparture = ((BartRunnerApplication) ((Activity) getContext())
.getApplication()).getBoardedDeparture(); .getApplication()).getBoardedDeparture();
if (boardedDeparture == null) if (boardedDeparture == null)
return; return;
if (!boardedDeparture.equals(mDeparture)) { if (!boardedDeparture.equals(mDeparture)) {
if (mDeparture != null) { if (mDeparture != null) {
mDeparture.getAlarmLeadTimeMinutesObservable() mDeparture.getAlarmLeadTimeMinutesObservable()
.unregisterObserver(mAlarmLeadObserver); .unregisterObserver(mAlarmLeadObserver);
mDeparture.getAlarmPendingObservable().unregisterObserver( mDeparture.getAlarmPendingObservable().unregisterObserver(
mAlarmPendingObserver); mAlarmPendingObserver);
} }
boardedDeparture.getAlarmLeadTimeMinutesObservable() boardedDeparture.getAlarmLeadTimeMinutesObservable()
.registerObserver(mAlarmLeadObserver); .registerObserver(mAlarmLeadObserver);
boardedDeparture.getAlarmPendingObservable().registerObserver( boardedDeparture.getAlarmPendingObservable().registerObserver(
mAlarmPendingObserver); mAlarmPendingObserver);
} }
mDeparture = boardedDeparture; mDeparture = boardedDeparture;
((TextView) findViewById(R.id.yourTrainDestinationText)) ((TextView) findViewById(R.id.yourTrainDestinationText))
.setText(boardedDeparture.getTrainDestination().toString()); .setText(boardedDeparture.getTrainDestination().toString());
((TextView) findViewById(R.id.yourTrainTrainLengthText)) ((TextView) findViewById(R.id.yourTrainTrainLengthText))
.setText(boardedDeparture.getTrainLengthAndPlatform()); .setText(boardedDeparture.getTrainLengthAndPlatform());
ImageView colorBar = (ImageView) findViewById(R.id.yourTrainDestinationColorBar); ImageView colorBar = (ImageView) findViewById(R.id.yourTrainDestinationColorBar);
((GradientDrawable) colorBar.getDrawable()).setColor(Color ((GradientDrawable) colorBar.getDrawable()).setColor(Color
.parseColor(boardedDeparture.getTrainDestinationColor())); .parseColor(boardedDeparture.getTrainDestinationColor()));
ImageView bikeIcon = (ImageView) findViewById(R.id.yourTrainBikeIcon); ImageView bikeIcon = (ImageView) findViewById(R.id.yourTrainBikeIcon);
if (boardedDeparture.isBikeAllowed()) { if (boardedDeparture.isBikeAllowed()) {
bikeIcon.setImageDrawable(getResources().getDrawable( bikeIcon.setImageDrawable(getResources().getDrawable(
R.drawable.bike)); R.drawable.bike));
} else { } else {
bikeIcon.setImageDrawable(getResources().getDrawable( bikeIcon.setImageDrawable(getResources().getDrawable(
R.drawable.nobike)); R.drawable.nobike));
} }
if (boardedDeparture.getRequiresTransfer()) { if (boardedDeparture.getRequiresTransfer()) {
((ImageView) findViewById(R.id.yourTrainXferIcon)) findViewById(R.id.yourTrainXferIcon)
.setVisibility(View.VISIBLE); .setVisibility(View.VISIBLE);
} else { } else {
((ImageView) findViewById(R.id.yourTrainXferIcon)) findViewById(R.id.yourTrainXferIcon)
.setVisibility(View.INVISIBLE); .setVisibility(View.INVISIBLE);
} }
updateAlarmIndicator(); updateAlarmIndicator();
CountdownTextView departureCountdown = (CountdownTextView) findViewById(R.id.yourTrainDepartureCountdown); CountdownTextView departureCountdown = (CountdownTextView) findViewById(R.id.yourTrainDepartureCountdown);
CountdownTextView arrivalCountdown = (CountdownTextView) findViewById(R.id.yourTrainArrivalCountdown); CountdownTextView arrivalCountdown = (CountdownTextView) findViewById(R.id.yourTrainArrivalCountdown);
final TextProvider textProvider = new TextProvider() { final TextProvider textProvider = new TextProvider() {
@Override @Override
public String getText(long tickNumber) { public String getText(long tickNumber) {
if (boardedDeparture.hasDeparted()) { if (boardedDeparture.hasDeparted()) {
return boardedDeparture.getCountdownText(); return boardedDeparture.getCountdownText();
} else { } else {
return "Leaves in " + boardedDeparture.getCountdownText() return "Leaves in " + boardedDeparture.getCountdownText()
+ " " + boardedDeparture.getUncertaintyText(); + " " + boardedDeparture.getUncertaintyText();
} }
} }
}; };
departureCountdown.setText(textProvider.getText(0)); departureCountdown.setText(textProvider.getText(0));
departureCountdown.setTextProvider(textProvider); departureCountdown.setTextProvider(textProvider);
arrivalCountdown.setText(boardedDeparture arrivalCountdown.setText(boardedDeparture
.getEstimatedArrivalMinutesLeftText(getContext())); .getEstimatedArrivalMinutesLeftText(getContext()));
arrivalCountdown.setTextProvider(new TextProvider() { arrivalCountdown.setTextProvider(new TextProvider() {
@Override @Override
public String getText(long tickNumber) { public String getText(long tickNumber) {
return boardedDeparture return boardedDeparture
.getEstimatedArrivalMinutesLeftText(getContext()); .getEstimatedArrivalMinutesLeftText(getContext());
} }
}); });
setBackground(); setBackground();
} }
private void updateAlarmIndicator() { private void updateAlarmIndicator() {
if (!mDeparture.isAlarmPending()) { if (!mDeparture.isAlarmPending()) {
findViewById(R.id.alarmText).setVisibility(GONE); findViewById(R.id.alarmText).setVisibility(GONE);
} else { } else {
findViewById(R.id.alarmText).setVisibility(VISIBLE); findViewById(R.id.alarmText).setVisibility(VISIBLE);
((TextView) findViewById(R.id.alarmText)).setText(String ((TextView) findViewById(R.id.alarmText)).setText(String
.valueOf(mDeparture.getAlarmLeadTimeMinutes())); .valueOf(mDeparture.getAlarmLeadTimeMinutes()));
} }
} }
private final Runnable mUpdateAlarmIndicatorRunnable = new Runnable() { private final Runnable mUpdateAlarmIndicatorRunnable = new Runnable() {
@Override @Override
public void run() { public void run() {
updateAlarmIndicator(); updateAlarmIndicator();
} }
}; };
} }

View File

@ -3,25 +3,25 @@ package com.dougkeen.bart.data;
import android.database.Cursor; import android.database.Cursor;
public final class CursorUtils { public final class CursorUtils {
private CursorUtils() { private CursorUtils() {
// Static only class // Static only class
} }
public static final void closeCursorQuietly(Cursor cursor) { public static final void closeCursorQuietly(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) { if (cursor != null && !cursor.isClosed()) {
cursor.close(); cursor.close();
} }
} }
public static final String getString(Cursor cursor, RoutesColumns column) { public static final String getString(Cursor cursor, RoutesColumns column) {
return cursor.getString(cursor.getColumnIndex(column.string)); return cursor.getString(cursor.getColumnIndex(column.string));
} }
public static final Long getLong(Cursor cursor, RoutesColumns column) { public static final Long getLong(Cursor cursor, RoutesColumns column) {
return cursor.getLong(cursor.getColumnIndex(column.string)); return cursor.getLong(cursor.getColumnIndex(column.string));
} }
public static final Integer getInteger(Cursor cursor, RoutesColumns column) { public static final Integer getInteger(Cursor cursor, RoutesColumns column) {
return cursor.getInt(cursor.getColumnIndex(column.string)); return cursor.getInt(cursor.getColumnIndex(column.string));
} }
} }

View File

@ -13,57 +13,57 @@ import com.dougkeen.bart.model.StationPair;
public class DatabaseHelper extends SQLiteOpenHelper { public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "bart.dougkeen.db"; private static final String DATABASE_NAME = "bart.dougkeen.db";
private static final int DATABASE_VERSION = 6; private static final int DATABASE_VERSION = 6;
public static final String FAVORITES_TABLE_NAME = "Favorites"; public static final String FAVORITES_TABLE_NAME = "Favorites";
private BartRunnerApplication app; private BartRunnerApplication app;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
app = (BartRunnerApplication) context.getApplicationContext();
}
@Override public DatabaseHelper(Context context) {
public void onCreate(SQLiteDatabase db) { super(context, DATABASE_NAME, null, DATABASE_VERSION);
} app = (BartRunnerApplication) context.getApplicationContext();
}
private void createFavoritesTable(SQLiteDatabase db) { @Override
db.execSQL("CREATE TABLE IF NOT EXISTS " + FAVORITES_TABLE_NAME + " (" public void onCreate(SQLiteDatabase db) {
+ RoutesColumns._ID.getColumnDef() + " PRIMARY KEY, " }
+ RoutesColumns.FROM_STATION.getColumnDef() + ", "
+ RoutesColumns.TO_STATION.getColumnDef() + ", "
+ RoutesColumns.FARE.getColumnDef() + ", "
+ RoutesColumns.FARE_LAST_UPDATED.getColumnDef() + ", "
+ RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.getColumnDef() + ", "
+ RoutesColumns.AVERAGE_TRIP_LENGTH.getColumnDef() + ");");
}
@Override private void createFavoritesTable(SQLiteDatabase db) {
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("CREATE TABLE IF NOT EXISTS " + FAVORITES_TABLE_NAME + " ("
db.beginTransaction(); + RoutesColumns._ID.getColumnDef() + " PRIMARY KEY, "
try { + RoutesColumns.FROM_STATION.getColumnDef() + ", "
createFavoritesTable(db); + RoutesColumns.TO_STATION.getColumnDef() + ", "
+ RoutesColumns.FARE.getColumnDef() + ", "
+ RoutesColumns.FARE_LAST_UPDATED.getColumnDef() + ", "
+ RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.getColumnDef() + ", "
+ RoutesColumns.AVERAGE_TRIP_LENGTH.getColumnDef() + ");");
}
Cursor query = db.query(FAVORITES_TABLE_NAME, RoutesColumns.all(), @Override
null, null, null, null, null); public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.beginTransaction();
try {
createFavoritesTable(db);
List<StationPair> favorites = new ArrayList<StationPair>(); Cursor query = db.query(FAVORITES_TABLE_NAME, RoutesColumns.all(),
null, null, null, null, null);
while (query.moveToNext()) { List<StationPair> favorites = new ArrayList<StationPair>();
favorites.add(StationPair.createFromCursor(query));
}
query.close(); while (query.moveToNext()) {
favorites.add(StationPair.createFromCursor(query));
}
new FavoritesPersistence(app).persist(favorites); query.close();
db.execSQL("DROP TABLE " + FAVORITES_TABLE_NAME); new FavoritesPersistence(app).persist(favorites);
db.setTransactionSuccessful(); db.execSQL("DROP TABLE " + FAVORITES_TABLE_NAME);
} finally {
db.endTransaction(); db.setTransactionSuccessful();
} } finally {
} db.endTransaction();
}
}
} }

View File

@ -28,181 +28,181 @@ import com.dougkeen.bart.model.TextProvider;
public class DepartureArrayAdapter extends ArrayAdapter<Departure> { public class DepartureArrayAdapter extends ArrayAdapter<Departure> {
private Drawable noBikeDrawable; private Drawable noBikeDrawable;
private Drawable bikeDrawable; private Drawable bikeDrawable;
public DepartureArrayAdapter(Context context, int textViewResourceId, public DepartureArrayAdapter(Context context, int textViewResourceId,
Departure[] objects) { Departure[] objects) {
super(context, textViewResourceId, objects); super(context, textViewResourceId, objects);
assignBikeDrawables(); assignBikeDrawables();
} }
private void assignBikeDrawables() { private void assignBikeDrawables() {
noBikeDrawable = getContext().getResources().getDrawable( noBikeDrawable = getContext().getResources().getDrawable(
R.drawable.nobike); R.drawable.nobike);
bikeDrawable = getContext().getResources().getDrawable(R.drawable.bike); bikeDrawable = getContext().getResources().getDrawable(R.drawable.bike);
} }
public DepartureArrayAdapter(Context context, int resource, public DepartureArrayAdapter(Context context, int resource,
int textViewResourceId, Departure[] objects) { int textViewResourceId, Departure[] objects) {
super(context, resource, textViewResourceId, objects); super(context, resource, textViewResourceId, objects);
assignBikeDrawables(); assignBikeDrawables();
} }
public DepartureArrayAdapter(Context context, int resource, public DepartureArrayAdapter(Context context, int resource,
int textViewResourceId, List<Departure> objects) { int textViewResourceId, List<Departure> objects) {
super(context, resource, textViewResourceId, objects); super(context, resource, textViewResourceId, objects);
assignBikeDrawables(); assignBikeDrawables();
} }
public DepartureArrayAdapter(Context context, int resource, public DepartureArrayAdapter(Context context, int resource,
int textViewResourceId) { int textViewResourceId) {
super(context, resource, textViewResourceId); super(context, resource, textViewResourceId);
assignBikeDrawables(); assignBikeDrawables();
} }
public DepartureArrayAdapter(Context context, int textViewResourceId, public DepartureArrayAdapter(Context context, int textViewResourceId,
List<Departure> objects) { List<Departure> objects) {
super(context, textViewResourceId, objects); super(context, textViewResourceId, objects);
assignBikeDrawables(); assignBikeDrawables();
} }
public DepartureArrayAdapter(Context context, int textViewResourceId) { public DepartureArrayAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId); super(context, textViewResourceId);
assignBikeDrawables(); assignBikeDrawables();
} }
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
View view; View view;
if (convertView != null if (convertView != null
&& convertView instanceof DepartureListItemLayout) { && convertView instanceof DepartureListItemLayout) {
view = convertView; view = convertView;
} else { } else {
view = new DepartureListItemLayout(getContext()); view = new DepartureListItemLayout(getContext());
} }
final Departure departure = getItem(position); final Departure departure = getItem(position);
((Checkable) view).setChecked(departure.isSelected()); ((Checkable) view).setChecked(departure.isSelected());
((TextView) view.findViewById(R.id.destinationText)).setText(departure ((TextView) view.findViewById(R.id.destinationText)).setText(departure
.getTrainDestination().toString()); .getTrainDestination().toString());
final String arrivesAtDestinationPrefix = getContext().getString( final String arrivesAtDestinationPrefix = getContext().getString(
R.string.arrives_at_destination); R.string.arrives_at_destination);
final String estimatedArrivalTimeText = departure final String estimatedArrivalTimeText = departure
.getEstimatedArrivalTimeText(getContext(), false); .getEstimatedArrivalTimeText(getContext(), false);
TextView estimatedArrival = (TextView) view TextView estimatedArrival = (TextView) view
.findViewById(R.id.estimatedArrival); .findViewById(R.id.estimatedArrival);
if (estimatedArrival != null) { if (estimatedArrival != null) {
((TextView) view.findViewById(R.id.trainLengthText)) ((TextView) view.findViewById(R.id.trainLengthText))
.setText(departure.getTrainLengthAndPlatform()); .setText(departure.getTrainLengthAndPlatform());
estimatedArrival.setText(arrivesAtDestinationPrefix estimatedArrival.setText(arrivesAtDestinationPrefix
+ estimatedArrivalTimeText); + estimatedArrivalTimeText);
} else { } else {
TimedTextSwitcher textSwitcher = (TimedTextSwitcher) view TimedTextSwitcher textSwitcher = (TimedTextSwitcher) view
.findViewById(R.id.trainLengthText); .findViewById(R.id.trainLengthText);
initTextSwitcher(textSwitcher, initTextSwitcher(textSwitcher,
R.layout.train_length_arrival_textview); R.layout.train_length_arrival_textview);
if (!StringUtils.isBlank(estimatedArrivalTimeText)) { if (!StringUtils.isBlank(estimatedArrivalTimeText)) {
textSwitcher.setCurrentText(arrivesAtDestinationPrefix textSwitcher.setCurrentText(arrivesAtDestinationPrefix
+ estimatedArrivalTimeText); + estimatedArrivalTimeText);
} else { } else {
textSwitcher.setCurrentText(departure.getTrainLengthAndPlatform()); textSwitcher.setCurrentText(departure.getTrainLengthAndPlatform());
} }
textSwitcher.setTextProvider(new TextProvider() { textSwitcher.setTextProvider(new TextProvider() {
@Override @Override
public String getText(long tickNumber) { public String getText(long tickNumber) {
if (tickNumber % 4 == 0) { if (tickNumber % 4 == 0) {
return departure.getTrainLengthAndPlatform(); return departure.getTrainLengthAndPlatform();
} else { } else {
final String estimatedArrivalTimeText = departure final String estimatedArrivalTimeText = departure
.getEstimatedArrivalTimeText(getContext(), false); .getEstimatedArrivalTimeText(getContext(), false);
if (StringUtils.isBlank(estimatedArrivalTimeText)) { if (StringUtils.isBlank(estimatedArrivalTimeText)) {
return ""; return "";
} else { } else {
return arrivesAtDestinationPrefix return arrivesAtDestinationPrefix
+ estimatedArrivalTimeText; + estimatedArrivalTimeText;
} }
} }
} }
}); });
} }
ImageView colorBar = (ImageView) view ImageView colorBar = (ImageView) view
.findViewById(R.id.destinationColorBar); .findViewById(R.id.destinationColorBar);
((GradientDrawable) colorBar.getDrawable()).setColor(Color ((GradientDrawable) colorBar.getDrawable()).setColor(Color
.parseColor(departure.getTrainDestinationColor())); .parseColor(departure.getTrainDestinationColor()));
CountdownTextView countdownTextView = (CountdownTextView) view CountdownTextView countdownTextView = (CountdownTextView) view
.findViewById(R.id.countdown); .findViewById(R.id.countdown);
countdownTextView.setText(departure.getCountdownText()); countdownTextView.setText(departure.getCountdownText());
countdownTextView.setTextProvider(new TextProvider() { countdownTextView.setTextProvider(new TextProvider() {
@Override @Override
public String getText(long tickNumber) { public String getText(long tickNumber) {
return departure.getCountdownText(); return departure.getCountdownText();
} }
}); });
TextView departureTime = (TextView) view TextView departureTime = (TextView) view
.findViewById(R.id.departureTime); .findViewById(R.id.departureTime);
if (departureTime != null) { if (departureTime != null) {
((TextView) view.findViewById(R.id.uncertainty)).setText(departure ((TextView) view.findViewById(R.id.uncertainty)).setText(departure
.getUncertaintyText()); .getUncertaintyText());
departureTime.setText(departure departureTime.setText(departure
.getEstimatedDepartureTimeText(getContext(), false)); .getEstimatedDepartureTimeText(getContext(), false));
} else { } else {
TimedTextSwitcher uncertaintySwitcher = (TimedTextSwitcher) view TimedTextSwitcher uncertaintySwitcher = (TimedTextSwitcher) view
.findViewById(R.id.uncertainty); .findViewById(R.id.uncertainty);
initTextSwitcher(uncertaintySwitcher, R.layout.uncertainty_textview); initTextSwitcher(uncertaintySwitcher, R.layout.uncertainty_textview);
uncertaintySwitcher.setTextProvider(new TextProvider() { uncertaintySwitcher.setTextProvider(new TextProvider() {
@Override @Override
public String getText(long tickNumber) { public String getText(long tickNumber) {
if (tickNumber % 4 == 0) { if (tickNumber % 4 == 0) {
return departure.getUncertaintyText(); return departure.getUncertaintyText();
} else { } else {
return departure return departure
.getEstimatedDepartureTimeText(getContext(), false); .getEstimatedDepartureTimeText(getContext(), false);
} }
} }
}); });
} }
ImageView bikeIcon = (ImageView) view.findViewById(R.id.bikeIcon);
if (departure.isBikeAllowed()) {
bikeIcon.setImageDrawable(bikeDrawable);
} else {
bikeIcon.setImageDrawable(noBikeDrawable);
}
if (departure.getRequiresTransfer()) {
((ImageView) view.findViewById(R.id.xferIcon))
.setVisibility(View.VISIBLE);
} else {
((ImageView) view.findViewById(R.id.xferIcon))
.setVisibility(View.INVISIBLE);
}
return view; ImageView bikeIcon = (ImageView) view.findViewById(R.id.bikeIcon);
} if (departure.isBikeAllowed()) {
bikeIcon.setImageDrawable(bikeDrawable);
} else {
bikeIcon.setImageDrawable(noBikeDrawable);
}
if (departure.getRequiresTransfer()) {
view.findViewById(R.id.xferIcon)
.setVisibility(View.VISIBLE);
} else {
view.findViewById(R.id.xferIcon)
.setVisibility(View.INVISIBLE);
}
private void initTextSwitcher(TextSwitcher textSwitcher, return view;
final int layoutView) { }
if (textSwitcher.getInAnimation() == null) {
textSwitcher.setFactory(new ViewFactory() {
public View makeView() {
return LayoutInflater.from(getContext()).inflate(
layoutView, null);
}
});
textSwitcher.setInAnimation(AnimationUtils.loadAnimation( private void initTextSwitcher(TextSwitcher textSwitcher,
getContext(), android.R.anim.slide_in_left)); final int layoutView) {
textSwitcher.setOutAnimation(AnimationUtils.loadAnimation( if (textSwitcher.getInAnimation() == null) {
getContext(), android.R.anim.slide_out_right)); textSwitcher.setFactory(new ViewFactory() {
} public View makeView() {
} return LayoutInflater.from(getContext()).inflate(
layoutView, null);
}
});
textSwitcher.setInAnimation(AnimationUtils.loadAnimation(
getContext(), android.R.anim.slide_in_left));
textSwitcher.setOutAnimation(AnimationUtils.loadAnimation(
getContext(), android.R.anim.slide_out_right));
}
}
} }

View File

@ -34,229 +34,229 @@ import com.dougkeen.bart.services.EtdService_;
public class FavoritesArrayAdapter extends ArrayAdapter<StationPair> { public class FavoritesArrayAdapter extends ArrayAdapter<StationPair> {
private boolean mBound = false; private boolean mBound = false;
private EtdService mEtdService; private EtdService mEtdService;
private Activity mHostActivity; private Activity mHostActivity;
private Map<StationPair, EtdListener> mEtdListeners = new HashMap<StationPair, EtdListener>(); private Map<StationPair, EtdListener> mEtdListeners = new HashMap<StationPair, EtdListener>();
private final ServiceConnection mConnection = new ServiceConnection() { private final ServiceConnection mConnection = new ServiceConnection() {
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
mEtdService = null; mEtdService = null;
mBound = false; mBound = false;
} }
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
mEtdService = ((EtdServiceBinder) service).getService(); mEtdService = ((EtdServiceBinder) service).getService();
mBound = true; mBound = true;
if (!isEmpty()) { if (!isEmpty()) {
setUpEtdListeners(); setUpEtdListeners();
} }
} }
}; };
public void setUpEtdListeners() { public void setUpEtdListeners() {
if (mBound && mEtdService != null) { if (mBound && mEtdService != null) {
for (int i = getCount() - 1; i >= 0; i--) { for (int i = getCount() - 1; i >= 0; i--) {
final StationPair item = getItem(i); final StationPair item = getItem(i);
mEtdListeners.put(item, new EtdListener(item, mEtdService)); mEtdListeners.put(item, new EtdListener(item, mEtdService));
} }
} }
} }
public void clearEtdListeners() { public void clearEtdListeners() {
if (mBound && mEtdService != null) { if (mBound && mEtdService != null) {
for (EtdListener listener : mEtdListeners.values()) { for (EtdListener listener : mEtdListeners.values()) {
listener.close(mEtdService); listener.close(mEtdService);
} }
mEtdListeners.clear(); mEtdListeners.clear();
} }
} }
public boolean areEtdListenersActive() { public boolean areEtdListenersActive() {
return !mEtdListeners.isEmpty(); return !mEtdListeners.isEmpty();
} }
public FavoritesArrayAdapter(Context context, int textViewResourceId, public FavoritesArrayAdapter(Context context, int textViewResourceId,
List<StationPair> objects) { List<StationPair> objects) {
super(context, textViewResourceId, objects); super(context, textViewResourceId, objects);
mHostActivity = (Activity) context; mHostActivity = (Activity) context;
mHostActivity.bindService(EtdService_.intent(mHostActivity).get(), mHostActivity.bindService(EtdService_.intent(mHostActivity).get(),
mConnection, Context.BIND_AUTO_CREATE); mConnection, Context.BIND_AUTO_CREATE);
} }
public void close() { public void close() {
if (mBound) { if (mBound) {
mHostActivity.unbindService(mConnection); mHostActivity.unbindService(mConnection);
} }
} }
@Override @Override
public void add(StationPair object) { public void add(StationPair object) {
super.add(object); super.add(object);
if (mEtdService != null && mBound) { if (mEtdService != null && mBound) {
mEtdListeners.put(object, new EtdListener(object, mEtdService)); mEtdListeners.put(object, new EtdListener(object, mEtdService));
} }
} }
@Override @Override
public void remove(StationPair object) { public void remove(StationPair object) {
super.remove(object); super.remove(object);
if (mEtdListeners.containsKey(object) && mEtdService != null & mBound) { if (mEtdListeners.containsKey(object) && mEtdService != null & mBound) {
mEtdListeners.get(object).close(mEtdService); mEtdListeners.get(object).close(mEtdService);
mEtdListeners.remove(object); mEtdListeners.remove(object);
} }
} }
public void move(StationPair object, int to) { public void move(StationPair object, int to) {
super.remove(object); super.remove(object);
super.insert(object, to); super.insert(object, to);
} }
@Override @Override
public void clear() { public void clear() {
super.clear(); super.clear();
clearEtdListeners(); clearEtdListeners();
} }
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
View view; View view;
if (convertView != null && convertView instanceof RelativeLayout) { if (convertView != null && convertView instanceof RelativeLayout) {
view = convertView; view = convertView;
} else { } else {
LayoutInflater inflater = LayoutInflater.from(getContext()); LayoutInflater inflater = LayoutInflater.from(getContext());
view = inflater.inflate(R.layout.favorite_listing, parent, false); view = inflater.inflate(R.layout.favorite_listing, parent, false);
} }
final StationPair pair = getItem(position); final StationPair pair = getItem(position);
final EtdListener etdListener = mEtdListeners.get(pair); final EtdListener etdListener = mEtdListeners.get(pair);
final TimedTextSwitcher uncertaintyTextSwitcher = (TimedTextSwitcher) view final TimedTextSwitcher uncertaintyTextSwitcher = (TimedTextSwitcher) view
.findViewById(R.id.uncertainty); .findViewById(R.id.uncertainty);
initTextSwitcher(uncertaintyTextSwitcher); initTextSwitcher(uncertaintyTextSwitcher);
if (etdListener == null || etdListener.getFirstDeparture() == null) { if (etdListener == null || etdListener.getFirstDeparture() == null) {
uncertaintyTextSwitcher.setCurrentText(pair.getFare()); uncertaintyTextSwitcher.setCurrentText(pair.getFare());
} else { } else {
CountdownTextView countdownTextView = (CountdownTextView) view CountdownTextView countdownTextView = (CountdownTextView) view
.findViewById(R.id.countdownText); .findViewById(R.id.countdownText);
countdownTextView.setText(etdListener.getFirstDeparture() countdownTextView.setText(etdListener.getFirstDeparture()
.getCountdownText()); .getCountdownText());
countdownTextView.setTextProvider(new TextProvider() { countdownTextView.setTextProvider(new TextProvider() {
@Override @Override
public String getText(long tickNumber) { public String getText(long tickNumber) {
return etdListener.getFirstDeparture().getCountdownText(); return etdListener.getFirstDeparture().getCountdownText();
} }
}); });
final String uncertaintyText = etdListener.getFirstDeparture() final String uncertaintyText = etdListener.getFirstDeparture()
.getUncertaintyText(); .getUncertaintyText();
if (!StringUtils.isBlank(uncertaintyText)) { if (!StringUtils.isBlank(uncertaintyText)) {
uncertaintyTextSwitcher.setCurrentText(uncertaintyText); uncertaintyTextSwitcher.setCurrentText(uncertaintyText);
} else { } else {
uncertaintyTextSwitcher.setCurrentText(pair.getFare()); uncertaintyTextSwitcher.setCurrentText(pair.getFare());
} }
uncertaintyTextSwitcher.setTextProvider(new TextProvider() { uncertaintyTextSwitcher.setTextProvider(new TextProvider() {
@Override @Override
public String getText(long tickNumber) { public String getText(long tickNumber) {
final String arrive = etdListener.getFirstDeparture() final String arrive = etdListener.getFirstDeparture()
.getEstimatedArrivalTimeText(getContext(), true); .getEstimatedArrivalTimeText(getContext(), true);
int mod = StringUtils.isNotBlank(arrive) ? 8 : 6; int mod = StringUtils.isNotBlank(arrive) ? 8 : 6;
if (tickNumber % mod <= 1) { if (tickNumber % mod <= 1) {
return pair.getFare(); return pair.getFare();
} else if (tickNumber % mod <= 3) { } else if (tickNumber % mod <= 3) {
return "Dep " return "Dep "
+ etdListener.getFirstDeparture() + etdListener.getFirstDeparture()
.getEstimatedDepartureTimeText( .getEstimatedDepartureTimeText(
getContext(), true); getContext(), true);
} else if (mod == 8 && tickNumber % mod <= 5) { } else if (mod == 8 && tickNumber % mod <= 5) {
return "Arr " + arrive; return "Arr " + arrive;
} else { } else {
return etdListener.getFirstDeparture() return etdListener.getFirstDeparture()
.getUncertaintyText(); .getUncertaintyText();
} }
} }
}); });
} }
((TextView) view.findViewById(R.id.originText)).setText(pair ((TextView) view.findViewById(R.id.originText)).setText(pair
.getOrigin().name); .getOrigin().name);
((TextView) view.findViewById(R.id.destinationText)).setText(pair ((TextView) view.findViewById(R.id.destinationText)).setText(pair
.getDestination().name); .getDestination().name);
return view; return view;
} }
private void initTextSwitcher(TextSwitcher textSwitcher) { private void initTextSwitcher(TextSwitcher textSwitcher) {
if (textSwitcher.getInAnimation() == null) { if (textSwitcher.getInAnimation() == null) {
textSwitcher.setFactory(new ViewFactory() { textSwitcher.setFactory(new ViewFactory() {
public View makeView() { public View makeView() {
return LayoutInflater.from(getContext()).inflate( return LayoutInflater.from(getContext()).inflate(
R.layout.uncertainty_textview, null); R.layout.uncertainty_textview, null);
} }
}); });
textSwitcher.setInAnimation(AnimationUtils.loadAnimation( textSwitcher.setInAnimation(AnimationUtils.loadAnimation(
getContext(), android.R.anim.slide_in_left)); getContext(), android.R.anim.slide_in_left));
textSwitcher.setOutAnimation(AnimationUtils.loadAnimation( textSwitcher.setOutAnimation(AnimationUtils.loadAnimation(
getContext(), android.R.anim.slide_out_right)); getContext(), android.R.anim.slide_out_right));
} }
} }
private class EtdListener implements EtdServiceListener { private class EtdListener implements EtdServiceListener {
private final StationPair mStationPair; private final StationPair mStationPair;
private Departure firstDeparture; private Departure firstDeparture;
protected EtdListener(StationPair mStationPair, EtdService etdService) { protected EtdListener(StationPair mStationPair, EtdService etdService) {
super(); super();
this.mStationPair = mStationPair; this.mStationPair = mStationPair;
etdService.registerListener(this, true); etdService.registerListener(this, true);
} }
protected void close(EtdService etdService) { protected void close(EtdService etdService) {
etdService.unregisterListener(this); etdService.unregisterListener(this);
} }
@Override @Override
public void onETDChanged(List<Departure> departures) { public void onETDChanged(List<Departure> departures) {
for (Departure departure : departures) { for (Departure departure : departures) {
if (!departure.hasDeparted()) { if (!departure.hasDeparted()) {
if (!departure.equals(firstDeparture)) { if (!departure.equals(firstDeparture)) {
firstDeparture = departure; firstDeparture = departure;
FavoritesArrayAdapter.this.notifyDataSetChanged(); FavoritesArrayAdapter.this.notifyDataSetChanged();
} }
return; return;
} }
} }
} }
@Override @Override
public void onError(String errorMessage) { public void onError(String errorMessage) {
} }
@Override @Override
public void onRequestStarted() { public void onRequestStarted() {
} }
@Override @Override
public void onRequestEnded() { public void onRequestEnded() {
} }
@Override @Override
public StationPair getStationPair() { public StationPair getStationPair() {
return mStationPair; return mStationPair;
} }
public Departure getFirstDeparture() { public Departure getFirstDeparture() {
return firstDeparture; return firstDeparture;
} }
} }
} }

View File

@ -18,46 +18,46 @@ import com.googlecode.androidannotations.annotations.EBean;
@EBean @EBean
public class FavoritesPersistence { public class FavoritesPersistence {
private static final String TAG = "FavoritesPersistence"; private static final String TAG = "FavoritesPersistence";
private final ObjectMapper objectMapper = new ObjectMapper(); private final ObjectMapper objectMapper = new ObjectMapper();
private BartRunnerApplication app; private BartRunnerApplication app;
public FavoritesPersistence(Context context) { public FavoritesPersistence(Context context) {
app = (BartRunnerApplication) context.getApplicationContext(); app = (BartRunnerApplication) context.getApplicationContext();
} }
public void persist(List<StationPair> favorites) { public void persist(List<StationPair> favorites) {
FileOutputStream outputStream = null; FileOutputStream outputStream = null;
try { try {
outputStream = app outputStream = app
.openFileOutput("favorites", Context.MODE_PRIVATE); .openFileOutput("favorites", Context.MODE_PRIVATE);
objectMapper.writeValue(outputStream, favorites); objectMapper.writeValue(outputStream, favorites);
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Could not write favorites file", e); Log.e(TAG, "Could not write favorites file", e);
} finally { } finally {
IOUtils.closeQuietly(outputStream); IOUtils.closeQuietly(outputStream);
} }
} }
public List<StationPair> restore() { public List<StationPair> restore() {
for (String file : app.fileList()) { for (String file : app.fileList()) {
if ("favorites".equals(file)) { if ("favorites".equals(file)) {
FileInputStream inputStream = null; FileInputStream inputStream = null;
try { try {
inputStream = app.openFileInput("favorites"); inputStream = app.openFileInput("favorites");
return objectMapper.readValue(inputStream, return objectMapper.readValue(inputStream,
new TypeReference<ArrayList<StationPair>>() { new TypeReference<ArrayList<StationPair>>() {
}); });
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Could not read favorites file", e); Log.e(TAG, "Could not read favorites file", e);
} finally { } finally {
IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(inputStream);
} }
} }
} }
return new ArrayList<StationPair>(); return new ArrayList<StationPair>();
} }
} }

View File

@ -1,33 +1,33 @@
package com.dougkeen.bart.data; package com.dougkeen.bart.data;
public enum RoutesColumns { public enum RoutesColumns {
_ID("_id", "INTEGER", false), FROM_STATION("FROM_STATION", "TEXT", false), TO_STATION( _ID("_id", "INTEGER", false), FROM_STATION("FROM_STATION", "TEXT", false), TO_STATION(
"TO_STATION", "TEXT", false), FARE("FARE", "TEXT", true), FARE_LAST_UPDATED( "TO_STATION", "TEXT", false), FARE("FARE", "TEXT", true), FARE_LAST_UPDATED(
"FARE_LAST_UPDATED", "INTEGER", true), AVERAGE_TRIP_SAMPLE_COUNT( "FARE_LAST_UPDATED", "INTEGER", true), AVERAGE_TRIP_SAMPLE_COUNT(
"AVE_TRIP_SAMPLE_COUNT", "INTEGER", true), AVERAGE_TRIP_LENGTH( "AVE_TRIP_SAMPLE_COUNT", "INTEGER", true), AVERAGE_TRIP_LENGTH(
"AVE_TRIP_LENGTH", "INTEGER", true); "AVE_TRIP_LENGTH", "INTEGER", true);
// This class cannot be instantiated // This class cannot be instantiated
private RoutesColumns(String string, String type, Boolean nullable) { RoutesColumns(String string, String type, Boolean nullable) {
this.string = string; this.string = string;
this.sqliteType = type; this.sqliteType = type;
this.nullable = nullable; this.nullable = nullable;
} }
public final String string; public final String string;
public final String sqliteType; public final String sqliteType;
public final Boolean nullable; public final Boolean nullable;
protected String getColumnDef() { protected String getColumnDef() {
return string + " " + sqliteType + (nullable ? "" : " NOT NULL"); return string + " " + sqliteType + (nullable ? "" : " NOT NULL");
} }
public static String[] all() { public static String[] all() {
final RoutesColumns[] values = RoutesColumns.values(); final RoutesColumns[] values = RoutesColumns.values();
String[] returnArray = new String[values.length]; String[] returnArray = new String[values.length];
for (int i = values.length - 1; i >= 0; i--) { for (int i = values.length - 1; i >= 0; i--) {
returnArray[i] = values[i].string; returnArray[i] = values[i].string;
} }
return returnArray; return returnArray;
} }
} }

View File

@ -4,86 +4,86 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Alert { public class Alert {
private String id; private String id;
private String type; private String type;
private String description; private String description;
private String postedTime; private String postedTime;
private String expiresTime; private String expiresTime;
public Alert(String id) { public Alert(String id) {
super(); super();
this.id = id; this.id = id;
} }
public String getId() { public String getId() {
return id; return id;
} }
public void setId(String id) { public void setId(String id) {
this.id = id; this.id = id;
} }
public String getType() { public String getType() {
return type; return type;
} }
public void setType(String type) { public void setType(String type) {
this.type = type; this.type = type;
} }
public String getDescription() { public String getDescription() {
return description; return description;
} }
public void setDescription(String description) { public void setDescription(String description) {
this.description = description; this.description = description;
} }
public String getPostedTime() { public String getPostedTime() {
return postedTime; return postedTime;
} }
public void setPostedTime(String postedTime) { public void setPostedTime(String postedTime) {
this.postedTime = postedTime; this.postedTime = postedTime;
} }
public String getExpiresTime() { public String getExpiresTime() {
return expiresTime; return expiresTime;
} }
public void setExpiresTime(String expiresTime) { public void setExpiresTime(String expiresTime) {
this.expiresTime = expiresTime; this.expiresTime = expiresTime;
} }
public static class AlertList { public static class AlertList {
private List<Alert> alerts; private List<Alert> alerts;
private boolean noDelaysReported; private boolean noDelaysReported;
public List<Alert> getAlerts() { public List<Alert> getAlerts() {
if (alerts == null) { if (alerts == null) {
alerts = new ArrayList<Alert>(); alerts = new ArrayList<Alert>();
} }
return alerts; return alerts;
} }
public void addAlert(Alert alert) { public void addAlert(Alert alert) {
getAlerts().add(alert); getAlerts().add(alert);
} }
public void clear() { public void clear() {
getAlerts().clear(); getAlerts().clear();
} }
public boolean hasAlerts() { public boolean hasAlerts() {
return !getAlerts().isEmpty(); return !getAlerts().isEmpty();
} }
public boolean areNoDelaysReported() { public boolean areNoDelaysReported() {
return noDelaysReported; return noDelaysReported;
} }
public void setNoDelaysReported(boolean noDelaysReported) { public void setNoDelaysReported(boolean noDelaysReported) {
this.noDelaysReported = noDelaysReported; this.noDelaysReported = noDelaysReported;
} }
} }
} }

View File

@ -3,19 +3,19 @@ package com.dougkeen.bart.model;
import android.net.Uri; import android.net.Uri;
public class Constants { public class Constants {
public static final String AUTHORITY = "com.dougkeen.bart.dataprovider"; public static final String AUTHORITY = "com.dougkeen.bart.dataprovider";
public static final String FAVORITE_CONTENT_TYPE = "vnd.android.cursor.dir/com.dougkeen.bart.favorite"; public static final String FAVORITE_CONTENT_TYPE = "vnd.android.cursor.dir/com.dougkeen.bart.favorite";
public static final String ARBITRARY_ROUTE_UNDEFINED_TYPE = "vnd.android.cursor.dir/com.dougkeen.bart.arbitraryroute"; public static final String ARBITRARY_ROUTE_UNDEFINED_TYPE = "vnd.android.cursor.dir/com.dougkeen.bart.arbitraryroute";
public static final String ARBITRARY_ROUTE_TYPE = "vnd.android.cursor.item/com.dougkeen.bart.arbitraryroute"; public static final String ARBITRARY_ROUTE_TYPE = "vnd.android.cursor.item/com.dougkeen.bart.arbitraryroute";
public static final String FAVORITE_CONTENT_ITEM_TYPE = "vnd.android.cursor.item/com.dougkeen.bart.favorite"; public static final String FAVORITE_CONTENT_ITEM_TYPE = "vnd.android.cursor.item/com.dougkeen.bart.favorite";
public static final Uri FAVORITE_CONTENT_URI = Uri.parse("content://" public static final Uri FAVORITE_CONTENT_URI = Uri.parse("content://"
+ AUTHORITY + "/favorites"); + AUTHORITY + "/favorites");
public static final Uri ARBITRARY_ROUTE_CONTENT_URI_ROOT = Uri public static final Uri ARBITRARY_ROUTE_CONTENT_URI_ROOT = Uri
.parse("content://" + AUTHORITY + "/route"); .parse("content://" + AUTHORITY + "/route");
public static final String MAP_URL = "http://m.bart.gov/images/global/system-map29.gif"; public static final String MAP_URL = "http://m.bart.gov/images/global/system-map29.gif";
public static final String TAG = "com.dougkeen.BartRunner"; public static final String TAG = "com.dougkeen.BartRunner";
public static final String API_KEY = "5LD9-IAYI-TRAT-MHHW"; public static final String API_KEY = "5LD9-IAYI-TRAT-MHHW";
public static final String ACTION_ALARM = "com.dougkeen.action.ALARM"; public static final String ACTION_ALARM = "com.dougkeen.action.ALARM";
public static final String STATION_PAIR_EXTRA = "StationPair"; public static final String STATION_PAIR_EXTRA = "StationPair";
} }

File diff suppressed because it is too large Load Diff

View File

@ -8,108 +8,108 @@ import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
public enum Line { public enum Line {
RED(false, Station.MLBR, Station.SBRN, Station.SSAN, Station.COLM, RED(false, Station.MLBR, Station.SBRN, Station.SSAN, Station.COLM,
Station.DALY, Station.BALB, Station.GLEN, Station._24TH, Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT, Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station._12TH, Station._19TH, Station.EMBR, Station.WOAK, Station._12TH, Station._19TH,
Station.MCAR, Station.ASHB, Station.DBRK, Station.NBRK, Station.MCAR, Station.ASHB, Station.DBRK, Station.NBRK,
Station.PLZA, Station.DELN, Station.RICH), Station.PLZA, Station.DELN, Station.RICH),
ORANGE(false, Station.FRMT, Station.UCTY, Station.SHAY, Station.HAYW, ORANGE(false, Station.FRMT, Station.UCTY, Station.SHAY, Station.HAYW,
Station.BAYF, Station.SANL, Station.COLS, Station.FTVL, Station.BAYF, Station.SANL, Station.COLS, Station.FTVL,
Station.LAKE, Station._12TH, Station._19TH, Station.MCAR, Station.LAKE, Station._12TH, Station._19TH, Station.MCAR,
Station.ASHB, Station.DBRK, Station.NBRK, Station.PLZA, Station.ASHB, Station.DBRK, Station.NBRK, Station.PLZA,
Station.DELN, Station.RICH), Station.DELN, Station.RICH),
YELLOW(false, Station.MLBR, Station.SFIA, Station.SBRN, Station.SSAN, YELLOW(false, Station.MLBR, Station.SFIA, Station.SBRN, Station.SSAN,
Station.COLM, Station.DALY, Station.BALB, Station.GLEN, Station.COLM, Station.DALY, Station.BALB, Station.GLEN,
Station._24TH, Station._16TH, Station.CIVC, Station.POWL, Station._24TH, Station._16TH, Station.CIVC, Station.POWL,
Station.MONT, Station.EMBR, Station.WOAK, Station._12TH, Station.MONT, Station.EMBR, Station.WOAK, Station._12TH,
Station._19TH, Station.MCAR, Station.ROCK, Station.ORIN, Station._19TH, Station.MCAR, Station.ROCK, Station.ORIN,
Station.LAFY, Station.WCRK, Station.PHIL, Station.CONC, Station.LAFY, Station.WCRK, Station.PHIL, Station.CONC,
Station.NCON, Station.PITT), Station.NCON, Station.PITT),
BLUE(true, Station.DALY, Station.BALB, Station.GLEN, Station._24TH, BLUE(true, Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT, Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station.LAKE, Station.FTVL, Station.EMBR, Station.WOAK, Station.LAKE, Station.FTVL,
Station.COLS, Station.SANL, Station.BAYF, Station.CAST, Station.COLS, Station.SANL, Station.BAYF, Station.CAST,
Station.WDUB, Station.DUBL), Station.WDUB, Station.DUBL),
GREEN(true, Station.DALY, Station.BALB, Station.GLEN, Station._24TH, GREEN(true, Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT, Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station.LAKE, Station.FTVL, Station.EMBR, Station.WOAK, Station.LAKE, Station.FTVL,
Station.COLS, Station.SANL, Station.BAYF, Station.HAYW, Station.COLS, Station.SANL, Station.BAYF, Station.HAYW,
Station.SHAY, Station.UCTY, Station.FRMT), Station.SHAY, Station.UCTY, Station.FRMT),
YELLOW_ORANGE_SCHEDULED_TRANSFER(YELLOW, ORANGE, Station.MLBR, YELLOW_ORANGE_SCHEDULED_TRANSFER(YELLOW, ORANGE, Station.MLBR,
Station.SFIA, Station.SBRN, Station.SSAN, Station.COLM, Station.SFIA, Station.SBRN, Station.SSAN, Station.COLM,
Station.DALY, Station.BALB, Station.GLEN, Station._24TH, Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT, Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station.ASHB, Station.DBRK, Station.EMBR, Station.WOAK, Station.ASHB, Station.DBRK,
Station.NBRK, Station.PLZA, Station.DELN, Station.RICH); Station.NBRK, Station.PLZA, Station.DELN, Station.RICH);
public final List<Station> stations; public final List<Station> stations;
protected final boolean directionMayInvert; protected final boolean directionMayInvert;
protected final boolean requiresTransfer; protected final boolean requiresTransfer;
protected final Line transferLine1; protected final Line transferLine1;
protected final Line transferLine2; protected final Line transferLine2;
private Line(boolean directionMayInvert, Station... stationArray) { Line(boolean directionMayInvert, Station... stationArray) {
this.requiresTransfer = false; this.requiresTransfer = false;
this.directionMayInvert = directionMayInvert; this.directionMayInvert = directionMayInvert;
stations = Arrays.asList(stationArray); stations = Arrays.asList(stationArray);
this.transferLine1 = null; this.transferLine1 = null;
this.transferLine2 = null; this.transferLine2 = null;
} }
private Line(Line transferLine1, Line transferLine2, Line(Line transferLine1, Line transferLine2,
Station... stationArray) { Station... stationArray) {
this.requiresTransfer = true; this.requiresTransfer = true;
this.directionMayInvert = false; this.directionMayInvert = false;
stations = Arrays.asList(stationArray); stations = Arrays.asList(stationArray);
this.transferLine1 = transferLine1; this.transferLine1 = transferLine1;
this.transferLine2 = transferLine2; this.transferLine2 = transferLine2;
} }
private Line(boolean directionMayInvert, Line transferLine1, Line(boolean directionMayInvert, Line transferLine1,
Line transferLine2, Station... stationArray) { Line transferLine2, Station... stationArray) {
this.requiresTransfer = true; this.requiresTransfer = true;
this.directionMayInvert = directionMayInvert; this.directionMayInvert = directionMayInvert;
stations = Arrays.asList(stationArray); stations = Arrays.asList(stationArray);
this.transferLine1 = transferLine1; this.transferLine1 = transferLine1;
this.transferLine2 = transferLine2; this.transferLine2 = transferLine2;
} }
public static Collection<Line> getLinesForStation(Station station) { public static Collection<Line> getLinesForStation(Station station) {
Collection<Line> lines = new ArrayList<Line>(); Collection<Line> lines = new ArrayList<Line>();
for (Line line : Line.values()) { for (Line line : Line.values()) {
if (line.stations.contains(station)) { if (line.stations.contains(station)) {
lines.add(line); lines.add(line);
} }
} }
return lines; return lines;
} }
public static Collection<Line> getLinesWithStations(Station station1, public static Collection<Line> getLinesWithStations(Station station1,
Station station2) { Station station2) {
Collection<Line> lines = new ArrayList<Line>(); Collection<Line> lines = new ArrayList<Line>();
for (Line line : Line.values()) { for (Line line : Line.values()) {
if (line.stations.contains(station1) if (line.stations.contains(station1)
&& line.stations.contains(station2)) { && line.stations.contains(station2)) {
lines.add(line); lines.add(line);
} }
} }
return lines; return lines;
} }
public static Set<Station> getPotentialDestinations(Station station) { public static Set<Station> getPotentialDestinations(Station station) {
Set<Station> destinations = new TreeSet<Station>(); Set<Station> destinations = new TreeSet<Station>();
for (Line line : getLinesForStation(station)) { for (Line line : getLinesForStation(station)) {
destinations.addAll(line.stations); destinations.addAll(line.stations);
} }
destinations.remove(station); destinations.remove(station);
return destinations; return destinations;
} }
} }

View File

@ -6,147 +6,147 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
public class RealTimeDepartures { public class RealTimeDepartures {
public RealTimeDepartures(Station origin, Station destination, public RealTimeDepartures(Station origin, Station destination,
List<Route> routes) { List<Route> routes) {
this.origin = origin; this.origin = origin;
this.destination = destination; this.destination = destination;
this.routes = routes; this.routes = routes;
this.unfilteredDepartures = new ArrayList<Departure>(); this.unfilteredDepartures = new ArrayList<Departure>();
} }
private Station origin; private Station origin;
private Station destination; private Station destination;
private long time; private long time;
private List<Departure> departures; private List<Departure> departures;
final private List<Departure> unfilteredDepartures; final private List<Departure> unfilteredDepartures;
private List<Route> routes; private List<Route> routes;
public Station getOrigin() { public Station getOrigin() {
return origin; return origin;
} }
public void setOrigin(Station origin) { public void setOrigin(Station origin) {
this.origin = origin; this.origin = origin;
} }
public Station getDestination() { public Station getDestination() {
return destination; return destination;
} }
public void setDestination(Station destination) { public void setDestination(Station destination) {
this.destination = destination; this.destination = destination;
} }
public long getTime() { public long getTime() {
return time; return time;
} }
public void setTime(long time) { public void setTime(long time) {
this.time = time; this.time = time;
} }
public List<Departure> getDepartures() { public List<Departure> getDepartures() {
if (departures == null) { if (departures == null) {
departures = new ArrayList<Departure>(); departures = new ArrayList<Departure>();
} }
return departures; return departures;
} }
public void setDepartures(List<Departure> departures) { public void setDepartures(List<Departure> departures) {
this.departures = departures; this.departures = departures;
} }
public void includeTransferRoutes() { public void includeTransferRoutes() {
routes.addAll(origin.getTransferRoutes(destination)); routes.addAll(origin.getTransferRoutes(destination));
rebuildFilteredDepaturesCollection(); rebuildFilteredDepaturesCollection();
} }
public void includeDoubleTransferRoutes() { public void includeDoubleTransferRoutes() {
routes.addAll(origin.getDoubleTransferRoutes(destination)); routes.addAll(origin.getDoubleTransferRoutes(destination));
rebuildFilteredDepaturesCollection(); rebuildFilteredDepaturesCollection();
} }
private void rebuildFilteredDepaturesCollection() { private void rebuildFilteredDepaturesCollection() {
getDepartures().clear(); getDepartures().clear();
for (Departure departure : unfilteredDepartures) { for (Departure departure : unfilteredDepartures) {
addDepartureIfApplicable(departure); addDepartureIfApplicable(departure);
} }
} }
public void addDeparture(Departure departure) { public void addDeparture(Departure departure) {
unfilteredDepartures.add(departure); unfilteredDepartures.add(departure);
addDepartureIfApplicable(departure); addDepartureIfApplicable(departure);
} }
private void addDepartureIfApplicable(Departure departure) { private void addDepartureIfApplicable(Departure departure) {
Station destination = Station.getByAbbreviation(departure Station destination = Station.getByAbbreviation(departure
.getTrainDestinationAbbreviation()); .getTrainDestinationAbbreviation());
if (departure.getLine() == null) if (departure.getLine() == null)
return; return;
for (Route route : routes) { for (Route route : routes) {
if (route.trainDestinationIsApplicable(destination, if (route.trainDestinationIsApplicable(destination,
departure.getLine())) { departure.getLine())) {
departure.setRequiresTransfer(route.hasTransfer()); departure.setRequiresTransfer(route.hasTransfer());
departure departure
.setTransferScheduled(Line.YELLOW_ORANGE_SCHEDULED_TRANSFER .setTransferScheduled(Line.YELLOW_ORANGE_SCHEDULED_TRANSFER
.equals(route.getDirectLine())); .equals(route.getDirectLine()));
getDepartures().add(departure); getDepartures().add(departure);
departure.calculateEstimates(time); departure.calculateEstimates(time);
return; return;
} }
} }
} }
public void sortDepartures() { public void sortDepartures() {
Collections.sort(getDepartures()); Collections.sort(getDepartures());
} }
public void finalizeDeparturesList() { public void finalizeDeparturesList() {
boolean hasDirectRoute = false; boolean hasDirectRoute = false;
for (Departure departure : getDepartures()) { for (Departure departure : getDepartures()) {
if (!departure.getRequiresTransfer()) { if (!departure.getRequiresTransfer()) {
hasDirectRoute = true; hasDirectRoute = true;
break; break;
} }
} }
if (hasDirectRoute) { if (hasDirectRoute) {
Iterator<Departure> iterator = getDepartures().iterator(); Iterator<Departure> iterator = getDepartures().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Departure departure = iterator.next(); Departure departure = iterator.next();
if (departure.getRequiresTransfer() if (departure.getRequiresTransfer()
&& (!departure.isTransferScheduled() || departure && (!departure.isTransferScheduled() || departure
.getTrainDestination().isBetween(getOrigin(), .getTrainDestination().isBetween(getOrigin(),
getDestination(), departure.getLine()))) { getDestination(), departure.getLine()))) {
iterator.remove(); iterator.remove();
} }
} }
} }
sortDepartures(); sortDepartures();
} }
public List<Route> getRoutes() { public List<Route> getRoutes() {
return routes; return routes;
} }
public void setRoutes(List<Route> routes) { public void setRoutes(List<Route> routes) {
this.routes = routes; this.routes = routes;
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("RealTimeDepartures [origin="); builder.append("RealTimeDepartures [origin=");
builder.append(origin); builder.append(origin);
builder.append(", destination="); builder.append(", destination=");
builder.append(destination); builder.append(destination);
builder.append(", time="); builder.append(", time=");
builder.append(time); builder.append(time);
builder.append(", departures="); builder.append(", departures=");
builder.append(departures); builder.append(departures);
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }
} }

View File

@ -3,109 +3,109 @@ package com.dougkeen.bart.model;
import java.util.Collection; import java.util.Collection;
public class Route { public class Route {
private Station origin; private Station origin;
private Station destination; private Station destination;
private Line directLine; private Line directLine;
private Collection<Line> transferLines; private Collection<Line> transferLines;
private boolean requiresTransfer; private boolean requiresTransfer;
private Station transferStation; private Station transferStation;
private String direction; private String direction;
public Station getOrigin() { public Station getOrigin() {
return origin; return origin;
} }
public void setOrigin(Station origin) { public void setOrigin(Station origin) {
this.origin = origin; this.origin = origin;
} }
public Station getDestination() { public Station getDestination() {
return destination; return destination;
} }
public void setDestination(Station destination) { public void setDestination(Station destination) {
this.destination = destination; this.destination = destination;
} }
public Line getDirectLine() { public Line getDirectLine() {
return directLine; return directLine;
} }
public void setDirectLine(Line line) { public void setDirectLine(Line line) {
this.directLine = line; this.directLine = line;
} }
public Collection<Line> getTransferLines() { public Collection<Line> getTransferLines() {
return transferLines; return transferLines;
} }
public void setTransferLines(Collection<Line> transferLines) { public void setTransferLines(Collection<Line> transferLines) {
this.transferLines = transferLines; this.transferLines = transferLines;
} }
public boolean hasTransfer() { public boolean hasTransfer() {
return requiresTransfer; return requiresTransfer;
} }
public void setTransfer(boolean requiresTransfer) { public void setTransfer(boolean requiresTransfer) {
this.requiresTransfer = requiresTransfer; this.requiresTransfer = requiresTransfer;
} }
public Station getTransferStation() { public Station getTransferStation() {
return transferStation; return transferStation;
} }
public void setTransferStation(Station transferStation) { public void setTransferStation(Station transferStation) {
this.transferStation = transferStation; this.transferStation = transferStation;
} }
public String getDirection() { public String getDirection() {
return direction; return direction;
} }
public void setDirection(String direction) { public void setDirection(String direction) {
this.direction = direction; this.direction = direction;
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("Route [origin="); builder.append("Route [origin=");
builder.append(origin); builder.append(origin);
builder.append(", destination="); builder.append(", destination=");
builder.append(destination); builder.append(destination);
builder.append(", line="); builder.append(", line=");
builder.append(directLine); builder.append(directLine);
builder.append(", requiresTransfer="); builder.append(", requiresTransfer=");
builder.append(requiresTransfer); builder.append(requiresTransfer);
builder.append(", transferStation="); builder.append(", transferStation=");
builder.append(transferStation); builder.append(transferStation);
builder.append(", direction="); builder.append(", direction=");
builder.append(direction); builder.append(direction);
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }
public boolean trainDestinationIsApplicable(Station lineDestination, public boolean trainDestinationIsApplicable(Station lineDestination,
Line viaLine) { Line viaLine) {
Line routeLine = getDirectLine(); Line routeLine = getDirectLine();
if (routeLine.transferLine1 != null if (routeLine.transferLine1 != null
&& viaLine.equals(routeLine.transferLine1)) { && viaLine.equals(routeLine.transferLine1)) {
return true; return true;
} else if (routeLine.transferLine2 != null } else if (routeLine.transferLine2 != null
&& viaLine.equals(routeLine.transferLine2)) { && viaLine.equals(routeLine.transferLine2)) {
return true; return true;
} else if (requiresTransfer && transferLines != null } else if (requiresTransfer && transferLines != null
&& !transferLines.isEmpty()) { && !transferLines.isEmpty()) {
return transferLines.contains(viaLine); return transferLines.contains(viaLine);
} else { } else {
int originIndex = viaLine.stations.indexOf(origin); int originIndex = viaLine.stations.indexOf(origin);
int routeDestinationIndex = viaLine.stations.indexOf(destination); int routeDestinationIndex = viaLine.stations.indexOf(destination);
int lineDestinationIndex = viaLine.stations int lineDestinationIndex = viaLine.stations
.indexOf(lineDestination); .indexOf(lineDestination);
return routeDestinationIndex >= 0 return routeDestinationIndex >= 0
&& ((originIndex <= routeDestinationIndex && routeDestinationIndex <= lineDestinationIndex) || (originIndex >= routeDestinationIndex && routeDestinationIndex >= lineDestinationIndex)); && ((originIndex <= routeDestinationIndex && routeDestinationIndex <= lineDestinationIndex) || (originIndex >= routeDestinationIndex && routeDestinationIndex >= lineDestinationIndex));
} }
} }
} }

View File

@ -5,85 +5,85 @@ import java.util.List;
public class ScheduleInformation { public class ScheduleInformation {
public ScheduleInformation(Station origin, Station destination) { public ScheduleInformation(Station origin, Station destination) {
super(); super();
this.origin = origin; this.origin = origin;
this.destination = destination; this.destination = destination;
} }
private Station origin; private Station origin;
private Station destination; private Station destination;
private long date; private long date;
private List<ScheduleItem> trips; private List<ScheduleItem> trips;
public Station getOrigin() { public Station getOrigin() {
return origin; return origin;
} }
public void setOrigin(Station origin) { public void setOrigin(Station origin) {
this.origin = origin; this.origin = origin;
} }
public Station getDestination() { public Station getDestination() {
return destination; return destination;
} }
public void setDestination(Station destination) { public void setDestination(Station destination) {
this.destination = destination; this.destination = destination;
} }
public long getDate() { public long getDate() {
return date; return date;
} }
public void setDate(long date) { public void setDate(long date) {
this.date = date; this.date = date;
} }
public List<ScheduleItem> getTrips() { public List<ScheduleItem> getTrips() {
if (trips == null) { if (trips == null) {
trips = new ArrayList<ScheduleItem>(); trips = new ArrayList<ScheduleItem>();
} }
return trips; return trips;
} }
public void setTrips(List<ScheduleItem> trips) { public void setTrips(List<ScheduleItem> trips) {
this.trips = trips; this.trips = trips;
} }
public void addTrip(ScheduleItem trip) { public void addTrip(ScheduleItem trip) {
getTrips().add(trip); getTrips().add(trip);
} }
public long getLatestDepartureTime() { public long getLatestDepartureTime() {
if (getTrips().isEmpty()) if (getTrips().isEmpty())
return -1; return -1;
else else
return getTrips().get(getTrips().size() - 1).getDepartureTime(); return getTrips().get(getTrips().size() - 1).getDepartureTime();
} }
private int aveTripLength = -1; private int aveTripLength = -1;
private int tripCount = 0; private int tripCount = 0;
public int getAverageTripLength() { public int getAverageTripLength() {
if (aveTripLength < 0) { if (aveTripLength < 0) {
int sum = 0; int sum = 0;
for (ScheduleItem trip : getTrips()) { for (ScheduleItem trip : getTrips()) {
int tripLength = trip.getTripLength(); int tripLength = trip.getTripLength();
if (tripLength > 0) { if (tripLength > 0) {
sum += tripLength; sum += tripLength;
tripCount++; tripCount++;
} }
} }
if (tripCount > 0) { if (tripCount > 0) {
aveTripLength = sum / tripCount; aveTripLength = sum / tripCount;
} }
} }
return aveTripLength; return aveTripLength;
} }
public int getTripCountForAverage() { public int getTripCountForAverage() {
getAverageTripLength(); getAverageTripLength();
return tripCount; return tripCount;
} }
} }

View File

@ -6,110 +6,110 @@ import java.util.Date;
public class ScheduleItem { public class ScheduleItem {
public ScheduleItem() { public ScheduleItem() {
super(); super();
} }
public ScheduleItem(Station origin, Station destination) { public ScheduleItem(Station origin, Station destination) {
super(); super();
this.origin = origin; this.origin = origin;
this.destination = destination; this.destination = destination;
} }
public static final int SCHEDULE_ITEM_DEPARTURE_EQUALS_TOLERANCE = 120000; public static final int SCHEDULE_ITEM_DEPARTURE_EQUALS_TOLERANCE = 120000;
private Station origin; private Station origin;
private Station destination; private Station destination;
private String fare; private String fare;
private long departureTime; private long departureTime;
private long arrivalTime; private long arrivalTime;
private boolean bikesAllowed; private boolean bikesAllowed;
private String trainHeadStation; private String trainHeadStation;
public Station getOrigin() { public Station getOrigin() {
return origin; return origin;
} }
public void setOrigin(Station origin) { public void setOrigin(Station origin) {
this.origin = origin; this.origin = origin;
} }
public Station getDestination() { public Station getDestination() {
return destination; return destination;
} }
public void setDestination(Station destination) { public void setDestination(Station destination) {
this.destination = destination; this.destination = destination;
} }
public String getFare() { public String getFare() {
return fare; return fare;
} }
public void setFare(String fare) { public void setFare(String fare) {
this.fare = fare; this.fare = fare;
} }
public long getDepartureTime() { public long getDepartureTime() {
return departureTime; return departureTime;
} }
public void setDepartureTime(long departureTime) { public void setDepartureTime(long departureTime) {
this.departureTime = departureTime; this.departureTime = departureTime;
} }
public long getArrivalTime() { public long getArrivalTime() {
return arrivalTime; return arrivalTime;
} }
public void setArrivalTime(long arrivalTime) { public void setArrivalTime(long arrivalTime) {
this.arrivalTime = arrivalTime; this.arrivalTime = arrivalTime;
} }
public int getTripLength() { public int getTripLength() {
if (departureTime <= 0 || arrivalTime <= 0) { if (departureTime <= 0 || arrivalTime <= 0) {
return 0; return 0;
} else { } else {
return (int) (arrivalTime - departureTime); return (int) (arrivalTime - departureTime);
} }
} }
public boolean isBikesAllowed() { public boolean isBikesAllowed() {
return bikesAllowed; return bikesAllowed;
} }
public void setBikesAllowed(boolean bikesAllowed) { public void setBikesAllowed(boolean bikesAllowed) {
this.bikesAllowed = bikesAllowed; this.bikesAllowed = bikesAllowed;
} }
public String getTrainHeadStation() { public String getTrainHeadStation() {
return trainHeadStation; return trainHeadStation;
} }
public void setTrainHeadStation(String trainHeadStation) { public void setTrainHeadStation(String trainHeadStation) {
this.trainHeadStation = trainHeadStation; this.trainHeadStation = trainHeadStation;
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
DateFormat format = SimpleDateFormat.getTimeInstance(); DateFormat format = SimpleDateFormat.getTimeInstance();
builder.append("ScheduleItem [origin="); builder.append("ScheduleItem [origin=");
builder.append(origin); builder.append(origin);
builder.append(", destination="); builder.append(", destination=");
builder.append(destination); builder.append(destination);
builder.append(", fare="); builder.append(", fare=");
builder.append(fare); builder.append(fare);
builder.append(", departureTime="); builder.append(", departureTime=");
builder.append(format.format(new Date(departureTime))); builder.append(format.format(new Date(departureTime)));
builder.append(", arrivalTime="); builder.append(", arrivalTime=");
builder.append(format.format(new Date(arrivalTime))); builder.append(format.format(new Date(arrivalTime)));
builder.append(", bikesAllowed="); builder.append(", bikesAllowed=");
builder.append(bikesAllowed); builder.append(bikesAllowed);
builder.append(", trainHeadStation="); builder.append(", trainHeadStation=");
builder.append(trainHeadStation); builder.append(trainHeadStation);
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }
} }

View File

@ -7,280 +7,280 @@ import java.util.List;
import android.util.Log; import android.util.Log;
public enum Station { public enum Station {
_12TH("12th", "12th St./Oakland City Center", "12th St Oak", false, false, _12TH("12th", "12th St./Oakland City Center", "12th St Oak", false, false,
"bayf", "bayf"), "bayf", "bayf"),
_16TH("16th", "16th St. Mission", "16th St", false, false), _16TH("16th", "16th St. Mission", "16th St", false, false),
_19TH("19th", "19th St./Oakland", "19th St Oak", false, false, "bayf", _19TH("19th", "19th St./Oakland", "19th St Oak", false, false, "bayf",
"bayf"), "bayf"),
_24TH("24th", "24th St. Mission", "24th St", false, false), _24TH("24th", "24th St. Mission", "24th St", false, false),
ASHB("ashb", "Ashby", "Ashby", false, false, "mcar", "mcar"), ASHB("ashb", "Ashby", "Ashby", false, false, "mcar", "mcar"),
BALB("balb", "Balboa Park", "Balboa", false, false), BALB("balb", "Balboa Park", "Balboa", false, false),
BAYF("bayf", "Bay Fair", "Bay Fair", true, false, "mcar", "mcar"), BAYF("bayf", "Bay Fair", "Bay Fair", true, false, "mcar", "mcar"),
CAST("cast", "Castro Valley", "Castro Vly", false, false, "bayf", "bayf"), CAST("cast", "Castro Valley", "Castro Vly", false, false, "bayf", "bayf"),
CIVC("civc", "Civic Center", "Civic Ctr", false, false), CIVC("civc", "Civic Center", "Civic Ctr", false, false),
COLS("cols", "Coliseum/Oakland Airport", "Coliseum/OAK", true, false, COLS("cols", "Coliseum/Oakland Airport", "Coliseum/OAK", true, false,
"mcar", "mcar"), "mcar", "mcar"),
COLM("colm", "Colma", "Colma", false, false, "balb", "balb"), COLM("colm", "Colma", "Colma", false, false, "balb", "balb"),
CONC("conc", "Concord", "Concord", false, false, "mcar", "mcar"), CONC("conc", "Concord", "Concord", false, false, "mcar", "mcar"),
DALY("daly", "Daly City", "Daly City", false, false), DALY("daly", "Daly City", "Daly City", false, false),
DBRK("dbrk", "Downtown Berkeley", "Dtwn Berk", false, false, "mcar", "mcar"), DBRK("dbrk", "Downtown Berkeley", "Dtwn Berk", false, false, "mcar", "mcar"),
DUBL("dubl", "Dublin/Pleasanton", "Dbln/Plsntn", false, true, "bayf", DUBL("dubl", "Dublin/Pleasanton", "Dbln/Plsntn", false, true, "bayf",
"bayf", true, 719999), "bayf", true, 719999),
DELN("deln", "El Cerrito del Norte", "El Cer/Norte", false, false, "mcar", DELN("deln", "El Cerrito del Norte", "El Cer/Norte", false, false, "mcar",
"mcar"), "mcar"),
PLZA("plza", "El Cerrito Plaza", "El Cer/Plz", false, false, "mcar", "mcar"), PLZA("plza", "El Cerrito Plaza", "El Cer/Plz", false, false, "mcar", "mcar"),
EMBR("embr", "Embarcadero", "Embarcdro", false, false), EMBR("embr", "Embarcadero", "Embarcdro", false, false),
FRMT("frmt", "Fremont", "Fremont", true, true, "bayf", "bayf", true, 299999), FRMT("frmt", "Fremont", "Fremont", true, true, "bayf", "bayf", true, 299999),
FTVL("ftvl", "Fruitvale", "Fruitvale", true, false, "mcar", "mcar"), FTVL("ftvl", "Fruitvale", "Fruitvale", true, false, "mcar", "mcar"),
GLEN("glen", "Glen Park", "Glen Park", false, false), GLEN("glen", "Glen Park", "Glen Park", false, false),
HAYW("hayw", "Hayward", "Hayward", true, false, "bayf", "bayf"), HAYW("hayw", "Hayward", "Hayward", true, false, "bayf", "bayf"),
LAFY("lafy", "Lafayette", "Lafayette", false, false, "mcar", "mcar"), LAFY("lafy", "Lafayette", "Lafayette", false, false, "mcar", "mcar"),
LAKE("lake", "Lake Merritt", "Lk Merritt", true, false, "mcar", "mcar"), LAKE("lake", "Lake Merritt", "Lk Merritt", true, false, "mcar", "mcar"),
MCAR("mcar", "MacArthur", "MacArthur", false, false, "bayf", "bayf"), MCAR("mcar", "MacArthur", "MacArthur", false, false, "bayf", "bayf"),
MLBR("mlbr", "Millbrae", "Millbrae", false, true, "balb", "balb", true, MLBR("mlbr", "Millbrae", "Millbrae", false, true, "balb", "balb", true,
719999), 719999),
MONT("mont", "Montgomery St.", "Montgomery", false, false), MONT("mont", "Montgomery St.", "Montgomery", false, false),
NBRK("nbrk", "North Berkeley", "N Berkeley", false, false, "mcar", "mcar"), NBRK("nbrk", "North Berkeley", "N Berkeley", false, false, "mcar", "mcar"),
NCON("ncon", "North Concord/Martinez", "N Conc/Mrtnz", false, false, NCON("ncon", "North Concord/Martinez", "N Conc/Mrtnz", false, false,
"mcar", "mcar"), "mcar", "mcar"),
ORIN("orin", "Orinda", "Orinda", false, false, "mcar", "mcar"), ORIN("orin", "Orinda", "Orinda", false, false, "mcar", "mcar"),
PITT("pitt", "Pittsburg/Bay Point", "Pitt/Bay Pt", false, true, "mcar", PITT("pitt", "Pittsburg/Bay Point", "Pitt/Bay Pt", false, true, "mcar",
"mcar", true, 719999), "mcar", true, 719999),
PHIL("phil", "Pleasant Hill", "Plsnt Hill", false, false, "mcar", "mcar"), PHIL("phil", "Pleasant Hill", "Plsnt Hill", false, false, "mcar", "mcar"),
POWL("powl", "Powell St.", "Powell", false, false), POWL("powl", "Powell St.", "Powell", false, false),
RICH("rich", "Richmond", "Richmond", false, true, "mcar", "mcar", true, RICH("rich", "Richmond", "Richmond", false, true, "mcar", "mcar", true,
299999), 299999),
ROCK("rock", "Rockridge", "Rockridge", false, false, "mcar", "mcar"), ROCK("rock", "Rockridge", "Rockridge", false, false, "mcar", "mcar"),
SBRN("sbrn", "San Bruno", "San Bruno", false, false, "balb", "balb"), SBRN("sbrn", "San Bruno", "San Bruno", false, false, "balb", "balb"),
SANL("sanl", "San Leandro", "San Leandro", true, false, "mcar", "mcar"), SANL("sanl", "San Leandro", "San Leandro", true, false, "mcar", "mcar"),
SFIA("sfia", "SFO Airport", "SFO", false, false, "balb", "balb", true, SFIA("sfia", "SFO Airport", "SFO", false, false, "balb", "balb", true,
719999), 719999),
SHAY("shay", "South Hayward", "S Hayward", true, false, "bayf", "bayf"), SHAY("shay", "South Hayward", "S Hayward", true, false, "bayf", "bayf"),
SSAN("ssan", "South San Francisco", "S San Fran", false, false, "balb", SSAN("ssan", "South San Francisco", "S San Fran", false, false, "balb",
"balb"), "balb"),
UCTY("ucty", "Union City", "Union City", true, false, "bayf", "bayf"), UCTY("ucty", "Union City", "Union City", true, false, "bayf", "bayf"),
WCRK("wcrk", "Walnut Creek", "Walnut Crk", false, false, "mcar", "mcar"), WCRK("wcrk", "Walnut Creek", "Walnut Crk", false, false, "mcar", "mcar"),
WDUB("wdub", "West Dublin/Pleasanton", "W Dbln/Plsntn", false, false, WDUB("wdub", "West Dublin/Pleasanton", "W Dbln/Plsntn", false, false,
"bayf", "bayf"), "bayf", "bayf"),
WOAK("woak", "West Oakland", "W Oakland", false, false), WOAK("woak", "West Oakland", "W Oakland", false, false),
SPCL("spcl", "Special", "Special", false, false); SPCL("spcl", "Special", "Special", false, false);
public final String abbreviation; public final String abbreviation;
public final String name; public final String name;
public final String shortName; public final String shortName;
public final boolean transferFriendly; public final boolean transferFriendly;
public final boolean invertDirection; public final boolean invertDirection;
protected final String inboundTransferStation; protected final String inboundTransferStation;
protected final String outboundTransferStation; protected final String outboundTransferStation;
public final boolean endOfLine; public final boolean endOfLine;
public final boolean longStationLinger; public final boolean longStationLinger;
public final int departureEqualityTolerance; public final int departureEqualityTolerance;
public final static int DEFAULT_DEPARTURE_EQUALITY_TOLERANCE = 119999; public final static int DEFAULT_DEPARTURE_EQUALITY_TOLERANCE = 119999;
private Station(String abbreviation, String name, String shortName, Station(String abbreviation, String name, String shortName,
boolean invertDirection, boolean endOfLine) { boolean invertDirection, boolean endOfLine) {
this(abbreviation, name, shortName, invertDirection, endOfLine, null, this(abbreviation, name, shortName, invertDirection, endOfLine, null,
null, false, DEFAULT_DEPARTURE_EQUALITY_TOLERANCE); null, false, DEFAULT_DEPARTURE_EQUALITY_TOLERANCE);
} }
private Station(String abbreviation, String name, String shortName, Station(String abbreviation, String name, String shortName,
boolean invertDirection, boolean endOfLine, String transferStation) { boolean invertDirection, boolean endOfLine, String transferStation) {
this(abbreviation, name, shortName, invertDirection, endOfLine, this(abbreviation, name, shortName, invertDirection, endOfLine,
transferStation, null, false, transferStation, null, false,
DEFAULT_DEPARTURE_EQUALITY_TOLERANCE); DEFAULT_DEPARTURE_EQUALITY_TOLERANCE);
} }
private Station(String abbreviation, String name, String shortName, Station(String abbreviation, String name, String shortName,
boolean invertDirection, boolean endOfLine, boolean invertDirection, boolean endOfLine,
String inboundTransferStation, String outboundTransferStation) { String inboundTransferStation, String outboundTransferStation) {
this(abbreviation, name, shortName, invertDirection, endOfLine, this(abbreviation, name, shortName, invertDirection, endOfLine,
inboundTransferStation, outboundTransferStation, false, inboundTransferStation, outboundTransferStation, false,
DEFAULT_DEPARTURE_EQUALITY_TOLERANCE); DEFAULT_DEPARTURE_EQUALITY_TOLERANCE);
} }
private Station(String abbreviation, String name, String shortName, Station(String abbreviation, String name, String shortName,
boolean invertDirection, boolean endOfLine, boolean invertDirection, boolean endOfLine,
String inboundTransferStation, String outboundTransferStation, String inboundTransferStation, String outboundTransferStation,
boolean longStationLinger, int departureEqualityTolerance) { boolean longStationLinger, int departureEqualityTolerance) {
this.abbreviation = abbreviation; this.abbreviation = abbreviation;
this.name = name; this.name = name;
this.shortName = shortName; this.shortName = shortName;
this.invertDirection = invertDirection; this.invertDirection = invertDirection;
this.inboundTransferStation = inboundTransferStation; this.inboundTransferStation = inboundTransferStation;
this.transferFriendly = outboundTransferStation != null; this.transferFriendly = outboundTransferStation != null;
this.outboundTransferStation = outboundTransferStation; this.outboundTransferStation = outboundTransferStation;
this.endOfLine = endOfLine; this.endOfLine = endOfLine;
this.longStationLinger = longStationLinger; this.longStationLinger = longStationLinger;
this.departureEqualityTolerance = departureEqualityTolerance; this.departureEqualityTolerance = departureEqualityTolerance;
} }
public static Station getByAbbreviation(String abbr) { public static Station getByAbbreviation(String abbr) {
try { try {
if (abbr == null) { if (abbr == null) {
return null; return null;
} else if (Character.isDigit(abbr.charAt(0))) { } else if (Character.isDigit(abbr.charAt(0))) {
return Station.valueOf("_" + abbr.toUpperCase()); return Station.valueOf("_" + abbr.toUpperCase());
} else { } else {
return Station.valueOf(abbr.toUpperCase()); return Station.valueOf(abbr.toUpperCase());
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.e(Constants.TAG, "Could not find station for '" + abbr + "'", e); Log.e(Constants.TAG, "Could not find station for '" + abbr + "'", e);
return null; return null;
} }
} }
public Station getInboundTransferStation() { public Station getInboundTransferStation() {
return getByAbbreviation(inboundTransferStation); return getByAbbreviation(inboundTransferStation);
} }
public Station getOutboundTransferStation() { public Station getOutboundTransferStation() {
return getByAbbreviation(outboundTransferStation); return getByAbbreviation(outboundTransferStation);
} }
public boolean isValidEndpointForDestination(Station dest, Station endpoint) { public boolean isValidEndpointForDestination(Station dest, Station endpoint) {
for (Line line : Line.values()) { for (Line line : Line.values()) {
int origIndex = line.stations.indexOf(this); int origIndex = line.stations.indexOf(this);
if (origIndex < 0) if (origIndex < 0)
continue; continue;
int destIndex = line.stations.indexOf(dest); int destIndex = line.stations.indexOf(dest);
if (destIndex < 0) if (destIndex < 0)
continue; continue;
int endpointIndex = line.stations.indexOf(endpoint); int endpointIndex = line.stations.indexOf(endpoint);
if (endpointIndex >= 0) if (endpointIndex >= 0)
return true; return true;
} }
return false; return false;
} }
public List<Route> getDirectRoutesForDestination(Station dest) { public List<Route> getDirectRoutesForDestination(Station dest) {
return getDirectRoutesForDestination(this, dest, null, null); return getDirectRoutesForDestination(this, dest, null, null);
} }
public List<Route> getDirectRoutesForDestination(Station origin, public List<Route> getDirectRoutesForDestination(Station origin,
Station dest, Station transferStation, Station dest, Station transferStation,
Collection<Line> transferLines) { Collection<Line> transferLines) {
if (dest == null) if (dest == null)
return null; return null;
Boolean isNorth = null; Boolean isNorth = null;
List<Route> returnList = new ArrayList<Route>(); List<Route> returnList = new ArrayList<Route>();
final Collection<Line> applicableLines = Line.getLinesWithStations( final Collection<Line> applicableLines = Line.getLinesWithStations(
this, dest); this, dest);
if (transferLines != null && !transferLines.isEmpty()) { if (transferLines != null && !transferLines.isEmpty()) {
for (Line transferLine : transferLines) { for (Line transferLine : transferLines) {
int origIndex = transferLine.stations.indexOf(origin); int origIndex = transferLine.stations.indexOf(origin);
int destIndex = transferLine.stations.indexOf(origin int destIndex = transferLine.stations.indexOf(origin
.getOutboundTransferStation()); .getOutboundTransferStation());
isNorth = (origIndex < destIndex); isNorth = (origIndex < destIndex);
if (origin.invertDirection && transferLine.directionMayInvert) { if (origin.invertDirection && transferLine.directionMayInvert) {
isNorth = !isNorth; isNorth = !isNorth;
break; break;
} }
} }
} }
for (Line line : applicableLines) { for (Line line : applicableLines) {
if (transferLines == null || transferLines.isEmpty()) { if (transferLines == null || transferLines.isEmpty()) {
int origIndex = line.stations.indexOf(this); int origIndex = line.stations.indexOf(this);
int destIndex = line.stations.indexOf(dest); int destIndex = line.stations.indexOf(dest);
isNorth = (origIndex < destIndex); isNorth = (origIndex < destIndex);
if (line.directionMayInvert && this.invertDirection) { if (line.directionMayInvert && this.invertDirection) {
isNorth = !isNorth; isNorth = !isNorth;
} }
} }
Route route = new Route(); Route route = new Route();
route.setOrigin(origin); route.setOrigin(origin);
route.setDirectLine(line); route.setDirectLine(line);
if (this.equals(origin)) { if (this.equals(origin)) {
route.setDestination(dest); route.setDestination(dest);
} else { } else {
// This must be the outbound transfer station // This must be the outbound transfer station
route.setDestination(origin.getOutboundTransferStation()); route.setDestination(origin.getOutboundTransferStation());
route.setTransferLines(transferLines); route.setTransferLines(transferLines);
} }
route.setDirection(isNorth ? "n" : "s"); route.setDirection(isNorth ? "n" : "s");
if (transferStation != null || line.requiresTransfer) { if (transferStation != null || line.requiresTransfer) {
route.setTransfer(true); route.setTransfer(true);
} else { } else {
route.setTransfer(false); route.setTransfer(false);
} }
returnList.add(route); returnList.add(route);
} }
return returnList; return returnList;
} }
public List<Route> getTransferRoutes(Station dest) { public List<Route> getTransferRoutes(Station dest) {
List<Route> returnList = new ArrayList<Route>(); List<Route> returnList = new ArrayList<Route>();
if (dest.getInboundTransferStation() != null) { if (dest.getInboundTransferStation() != null) {
// Try getting to the destination's inbound xfer station first // Try getting to the destination's inbound xfer station first
returnList.addAll(getDirectRoutesForDestination(this, returnList.addAll(getDirectRoutesForDestination(this,
dest.getInboundTransferStation(), dest.getInboundTransferStation(),
dest.getInboundTransferStation(), null)); dest.getInboundTransferStation(), null));
} }
if (returnList.isEmpty() && outboundTransferStation != null) { if (returnList.isEmpty() && outboundTransferStation != null) {
// Try getting from the outbound transfer station to the // Try getting from the outbound transfer station to the
// destination next // destination next
final Collection<Line> outboundTransferLines = Line final Collection<Line> outboundTransferLines = Line
.getLinesWithStations(this, getOutboundTransferStation()); .getLinesWithStations(this, getOutboundTransferStation());
final List<Route> routesForDestination = getOutboundTransferStation() final List<Route> routesForDestination = getOutboundTransferStation()
.getDirectRoutesForDestination(this, dest, .getDirectRoutesForDestination(this, dest,
getOutboundTransferStation(), outboundTransferLines); getOutboundTransferStation(), outboundTransferLines);
if (routesForDestination != null && !routesForDestination.isEmpty()) { if (routesForDestination != null && !routesForDestination.isEmpty()) {
returnList.addAll(routesForDestination); returnList.addAll(routesForDestination);
} }
} }
if (returnList.isEmpty()) { if (returnList.isEmpty()) {
// Try getting from the outbound transfer station to the // Try getting from the outbound transfer station to the
// destination's inbound xfer station // destination's inbound xfer station
final List<Route> routesForDestination = getDoubleTransferRoutes(dest); final List<Route> routesForDestination = getDoubleTransferRoutes(dest);
if (routesForDestination != null && !routesForDestination.isEmpty()) { if (routesForDestination != null && !routesForDestination.isEmpty()) {
returnList.addAll(routesForDestination); returnList.addAll(routesForDestination);
} }
} }
return returnList; return returnList;
} }
public List<Route> getDoubleTransferRoutes(Station dest) { public List<Route> getDoubleTransferRoutes(Station dest) {
if (getOutboundTransferStation() == null if (getOutboundTransferStation() == null
|| dest.getInboundTransferStation() == null) || dest.getInboundTransferStation() == null)
return new ArrayList<Route>(); return new ArrayList<Route>();
// Get routes from the outbound transfer station to the // Get routes from the outbound transfer station to the
// destination's inbound xfer station // destination's inbound xfer station
return getOutboundTransferStation().getDirectRoutesForDestination(this, return getOutboundTransferStation().getDirectRoutesForDestination(this,
dest.getInboundTransferStation(), getOutboundTransferStation(), dest.getInboundTransferStation(), getOutboundTransferStation(),
Line.getLinesWithStations(this, getOutboundTransferStation())); Line.getLinesWithStations(this, getOutboundTransferStation()));
} }
static public List<Station> getStationList() { static public List<Station> getStationList() {
List<Station> list = new ArrayList<Station>(); List<Station> list = new ArrayList<Station>();
for (Station station : values()) { for (Station station : values()) {
if (!station.equals(Station.SPCL)) { if (!station.equals(Station.SPCL)) {
list.add(station); list.add(station);
} }
} }
return list; return list;
} }
public String toString() { public String toString() {
return name; return name;
} }
public boolean isBetween(Station origin, Station destination, Line line) { public boolean isBetween(Station origin, Station destination, Line line) {
int originIndex = line.stations.indexOf(origin); int originIndex = line.stations.indexOf(origin);
int destinationIndex = line.stations.indexOf(destination); int destinationIndex = line.stations.indexOf(destination);
int stationIndex = line.stations.indexOf(this); int stationIndex = line.stations.indexOf(this);
if (originIndex < 0 || destinationIndex < 0 || stationIndex < 0) { if (originIndex < 0 || destinationIndex < 0 || stationIndex < 0) {
return false; return false;
} }
return Math.abs(stationIndex - originIndex) < Math.abs(destinationIndex return Math.abs(stationIndex - originIndex) < Math.abs(destinationIndex
- originIndex); - originIndex);
} }
} }

View File

@ -12,149 +12,147 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
public class StationPair implements Parcelable { public class StationPair implements Parcelable {
@JsonCreator @JsonCreator
public StationPair(@JsonProperty("origin") Station origin, public StationPair(@JsonProperty("origin") Station origin,
@JsonProperty("destination") Station destination) { @JsonProperty("destination") Station destination) {
super(); super();
this.origin = origin; this.origin = origin;
this.destination = destination; this.destination = destination;
} }
public StationPair(Parcel in) { public StationPair(Parcel in) {
readFromParcel(in); readFromParcel(in);
} }
public static StationPair createFromCursor(Cursor cursor) { public static StationPair createFromCursor(Cursor cursor) {
StationPair pair = new StationPair( StationPair pair = new StationPair(
Station.getByAbbreviation(CursorUtils.getString(cursor, Station.getByAbbreviation(CursorUtils.getString(cursor,
RoutesColumns.FROM_STATION)), RoutesColumns.FROM_STATION)),
Station.getByAbbreviation(CursorUtils.getString(cursor, Station.getByAbbreviation(CursorUtils.getString(cursor,
RoutesColumns.TO_STATION))); RoutesColumns.TO_STATION)));
pair.fare = CursorUtils.getString(cursor, RoutesColumns.FARE); pair.fare = CursorUtils.getString(cursor, RoutesColumns.FARE);
pair.fareLastUpdated = CursorUtils.getLong(cursor, pair.fareLastUpdated = CursorUtils.getLong(cursor,
RoutesColumns.FARE_LAST_UPDATED); RoutesColumns.FARE_LAST_UPDATED);
pair.averageTripLength = CursorUtils.getInteger(cursor, pair.averageTripLength = CursorUtils.getInteger(cursor,
RoutesColumns.AVERAGE_TRIP_LENGTH); RoutesColumns.AVERAGE_TRIP_LENGTH);
pair.averageTripSampleCount = CursorUtils.getInteger(cursor, pair.averageTripSampleCount = CursorUtils.getInteger(cursor,
RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT); RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT);
return pair; return pair;
} }
private Station origin; private Station origin;
private Station destination; private Station destination;
private String fare; private String fare;
private long fareLastUpdated; private long fareLastUpdated;
private int averageTripLength; private int averageTripLength;
private int averageTripSampleCount; private int averageTripSampleCount;
public Station getOrigin() { public Station getOrigin() {
return origin; return origin;
} }
public Station getDestination() { public Station getDestination() {
return destination; return destination;
} }
public String getFare() { public String getFare() {
return fare; return fare;
} }
public void setFare(String fare) { public void setFare(String fare) {
this.fare = fare; this.fare = fare;
} }
public long getFareLastUpdated() { public long getFareLastUpdated() {
return fareLastUpdated; return fareLastUpdated;
} }
public void setFareLastUpdated(long fareLastUpdated) { public void setFareLastUpdated(long fareLastUpdated) {
this.fareLastUpdated = fareLastUpdated; this.fareLastUpdated = fareLastUpdated;
} }
public int getAverageTripLength() { public int getAverageTripLength() {
return averageTripLength; return averageTripLength;
} }
public void setAverageTripLength(int averageTripLength) { public void setAverageTripLength(int averageTripLength) {
this.averageTripLength = averageTripLength; this.averageTripLength = averageTripLength;
} }
public int getAverageTripSampleCount() { public int getAverageTripSampleCount() {
return averageTripSampleCount; return averageTripSampleCount;
} }
public void setAverageTripSampleCount(int averageTripSampleCount) { public void setAverageTripSampleCount(int averageTripSampleCount) {
this.averageTripSampleCount = averageTripSampleCount; this.averageTripSampleCount = averageTripSampleCount;
} }
public boolean isBetweenStations(Station station1, Station station2) { public boolean isBetweenStations(Station station1, Station station2) {
return (origin.equals(station1) && destination.equals(station2)) return (origin.equals(station1) && destination.equals(station2))
|| (origin.equals(station2) && destination.equals(station1)); || (origin.equals(station2) && destination.equals(station1));
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result result = prime * result
+ ((destination == null) ? 0 : destination.hashCode()); + ((destination == null) ? 0 : destination.hashCode());
result = prime * result + ((origin == null) ? 0 : origin.hashCode()); result = prime * result + ((origin == null) ? 0 : origin.hashCode());
return result; return result;
} }
public boolean fareEquals(StationPair other) { public boolean fareEquals(StationPair other) {
if (other == null) if (other == null)
return false; return false;
return ObjectUtils.equals(getFare(), other.getFare()) return ObjectUtils.equals(getFare(), other.getFare())
&& ObjectUtils.equals(getFareLastUpdated(), && ObjectUtils.equals(getFareLastUpdated(),
other.getFareLastUpdated()); other.getFareLastUpdated());
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
StationPair other = (StationPair) obj; StationPair other = (StationPair) obj;
if (destination != other.destination) if (destination != other.destination)
return false; return false;
if (origin != other.origin) return origin == other.origin;
return false; }
return true;
}
@Override @Override
public String toString() { public String toString() {
return "StationPair [origin=" + origin + ", destination=" + destination return "StationPair [origin=" + origin + ", destination=" + destination
+ "]"; + "]";
} }
@Override @Override
public int describeContents() { public int describeContents() {
return 0; return 0;
} }
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeString(origin.abbreviation); dest.writeString(origin.abbreviation);
dest.writeString(destination.abbreviation); dest.writeString(destination.abbreviation);
} }
private void readFromParcel(Parcel in) { private void readFromParcel(Parcel in) {
origin = Station.getByAbbreviation(in.readString()); origin = Station.getByAbbreviation(in.readString());
destination = Station.getByAbbreviation(in.readString()); destination = Station.getByAbbreviation(in.readString());
} }
public static final Parcelable.Creator<StationPair> CREATOR = new Parcelable.Creator<StationPair>() { public static final Parcelable.Creator<StationPair> CREATOR = new Parcelable.Creator<StationPair>() {
public StationPair createFromParcel(Parcel in) { public StationPair createFromParcel(Parcel in) {
return new StationPair(in); return new StationPair(in);
} }
public StationPair[] newArray(int size) { public StationPair[] newArray(int size) {
return new StationPair[size]; return new StationPair[size];
} }
}; };
} }

View File

@ -3,6 +3,6 @@ package com.dougkeen.bart.model;
public interface TextProvider { public interface TextProvider {
String getText(long tickNumber); String getText(long tickNumber);
} }

View File

@ -23,118 +23,118 @@ import android.util.Xml;
import com.dougkeen.bart.model.Alert; import com.dougkeen.bart.model.Alert;
public class AlertListConverter extends public class AlertListConverter extends
AbstractHttpMessageConverter<Alert.AlertList> { AbstractHttpMessageConverter<Alert.AlertList> {
@Override @Override
protected Alert.AlertList readInternal( protected Alert.AlertList readInternal(
Class<? extends Alert.AlertList> clazz, Class<? extends Alert.AlertList> clazz,
HttpInputMessage inputMessage) throws IOException, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException { HttpMessageNotReadableException {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
IOUtils.copy(inputMessage.getBody(), writer, "UTF-8"); IOUtils.copy(inputMessage.getBody(), writer, "UTF-8");
String xml = writer.toString(); String xml = writer.toString();
if (xml.length() == 0) { if (xml.length() == 0) {
throw new IOException("Server returned blank xml document"); throw new IOException("Server returned blank xml document");
} }
AlertListHandler handler = new AlertListHandler(); AlertListHandler handler = new AlertListHandler();
try { try {
Xml.parse(xml, handler); Xml.parse(xml, handler);
} catch (SAXException e) { } catch (SAXException e) {
Log.e("AlertListConverter", "XML parsing error", e); Log.e("AlertListConverter", "XML parsing error", e);
return null; return null;
} }
return handler.getAlertList(); return handler.getAlertList();
} }
@Override @Override
protected boolean supports(Class<?> clazz) { protected boolean supports(Class<?> clazz) {
return Alert.AlertList.class.equals(clazz); return Alert.AlertList.class.equals(clazz);
} }
@Override @Override
public List<MediaType> getSupportedMediaTypes() { public List<MediaType> getSupportedMediaTypes() {
final List<MediaType> supportedMediaTypes = new ArrayList<MediaType>(); final List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
supportedMediaTypes.add(MediaType.TEXT_HTML); supportedMediaTypes.add(MediaType.TEXT_HTML);
supportedMediaTypes.add(MediaType.TEXT_XML); supportedMediaTypes.add(MediaType.TEXT_XML);
supportedMediaTypes.addAll(super.getSupportedMediaTypes()); supportedMediaTypes.addAll(super.getSupportedMediaTypes());
return supportedMediaTypes; return supportedMediaTypes;
} }
@Override @Override
protected void writeInternal(Alert.AlertList arg0, HttpOutputMessage arg1) protected void writeInternal(Alert.AlertList arg0, HttpOutputMessage arg1)
throws IOException, HttpMessageNotWritableException { throws IOException, HttpMessageNotWritableException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
private static class AlertListHandler extends DefaultHandler { private static class AlertListHandler extends DefaultHandler {
private final static List<String> TAGS = Arrays.asList("bsa", "type", private final static List<String> TAGS = Arrays.asList("bsa", "type",
"description", "posted", "expires"); "description", "posted", "expires");
private String currentValue; private String currentValue;
private boolean isParsingTag; private boolean isParsingTag;
private Alert currentAlert; private Alert currentAlert;
private Alert.AlertList returnList = new Alert.AlertList(); private Alert.AlertList returnList = new Alert.AlertList();
public Alert.AlertList getAlertList() { public Alert.AlertList getAlertList() {
return returnList; return returnList;
} }
@Override @Override
public void characters(char[] ch, int start, int length) public void characters(char[] ch, int start, int length)
throws SAXException { throws SAXException {
if (isParsingTag) { if (isParsingTag) {
currentValue = new String(ch, start, length); currentValue = new String(ch, start, length);
} }
} }
@Override @Override
public void startElement(String uri, String localName, String qName, public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException { Attributes attributes) throws SAXException {
if (TAGS.contains(localName)) { if (TAGS.contains(localName)) {
isParsingTag = true; isParsingTag = true;
} }
final int numberOfAttributes = attributes.getLength(); final int numberOfAttributes = attributes.getLength();
if (localName.equals("bsa")) { if (localName.equals("bsa")) {
for (int i = 0; i < numberOfAttributes; i++) { for (int i = 0; i < numberOfAttributes; i++) {
if (attributes.getLocalName(i).equalsIgnoreCase("id")) { if (attributes.getLocalName(i).equalsIgnoreCase("id")) {
currentAlert = new Alert(attributes.getValue(i)); currentAlert = new Alert(attributes.getValue(i));
break; break;
} }
} }
} }
} }
@Override @Override
public void endElement(String uri, String localName, String qName) public void endElement(String uri, String localName, String qName)
throws SAXException { throws SAXException {
if (currentAlert != null) { if (currentAlert != null) {
if (localName.equals("type")) { if (localName.equals("type")) {
currentAlert.setType(currentValue); currentAlert.setType(currentValue);
} else if (localName.equals("description")) { } else if (localName.equals("description")) {
currentAlert.setDescription(currentValue); currentAlert.setDescription(currentValue);
} else if (localName.equals("posted")) { } else if (localName.equals("posted")) {
currentAlert.setPostedTime(currentValue); currentAlert.setPostedTime(currentValue);
} else if (localName.equals("expires")) { } else if (localName.equals("expires")) {
currentAlert.setExpiresTime(currentValue); currentAlert.setExpiresTime(currentValue);
} else if (localName.equals("bsa")) { } else if (localName.equals("bsa")) {
returnList.addAlert(currentAlert); returnList.addAlert(currentAlert);
currentAlert = null; currentAlert = null;
} }
} }
isParsingTag = false; isParsingTag = false;
currentValue = null; currentValue = null;
} }
@Override @Override
public void endDocument() throws SAXException { public void endDocument() throws SAXException {
super.endDocument(); super.endDocument();
if (!returnList.hasAlerts()) { if (!returnList.hasAlerts()) {
returnList.setNoDelaysReported(true); returnList.setNoDelaysReported(true);
} }
} }
} }
} }

View File

@ -5,8 +5,8 @@ import com.dougkeen.bart.model.Constants;
import com.googlecode.androidannotations.annotations.rest.Get; import com.googlecode.androidannotations.annotations.rest.Get;
import com.googlecode.androidannotations.annotations.rest.Rest; import com.googlecode.androidannotations.annotations.rest.Rest;
@Rest(rootUrl = "http://api.bart.gov", converters = { AlertListConverter.class }) @Rest(rootUrl = "http://api.bart.gov", converters = {AlertListConverter.class})
public interface AlertsClient { public interface AlertsClient {
@Get("/api/bsa.aspx?cmd=bsa&key=" + Constants.API_KEY) @Get("/api/bsa.aspx?cmd=bsa&key=" + Constants.API_KEY)
Alert.AlertList getAlerts(); Alert.AlertList getAlerts();
} }

View File

@ -4,8 +4,8 @@ import com.dougkeen.bart.model.Constants;
import com.googlecode.androidannotations.annotations.rest.Get; import com.googlecode.androidannotations.annotations.rest.Get;
import com.googlecode.androidannotations.annotations.rest.Rest; import com.googlecode.androidannotations.annotations.rest.Rest;
@Rest(rootUrl = "http://api.bart.gov", converters = { ElevatorMessageConverter.class }) @Rest(rootUrl = "http://api.bart.gov", converters = {ElevatorMessageConverter.class})
public interface ElevatorClient { public interface ElevatorClient {
@Get("/api/bsa.aspx?cmd=elev&key=" + Constants.API_KEY) @Get("/api/bsa.aspx?cmd=elev&key=" + Constants.API_KEY)
String getElevatorMessage(); String getElevatorMessage();
} }

View File

@ -19,81 +19,81 @@ import android.util.Log;
import android.util.Xml; import android.util.Xml;
public class ElevatorMessageConverter extends public class ElevatorMessageConverter extends
AbstractHttpMessageConverter<String> { AbstractHttpMessageConverter<String> {
private static final String TAG = "ElevatorMessageConverter"; private static final String TAG = "ElevatorMessageConverter";
@Override @Override
protected String readInternal(Class<? extends String> clazz, protected String readInternal(Class<? extends String> clazz,
HttpInputMessage inputMessage) throws IOException, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException { HttpMessageNotReadableException {
final ElevatorMessageHandler handler = new ElevatorMessageHandler(); final ElevatorMessageHandler handler = new ElevatorMessageHandler();
try { try {
Xml.parse(new InputStreamReader(inputMessage.getBody()), handler); Xml.parse(new InputStreamReader(inputMessage.getBody()), handler);
} catch (SAXException e) { } catch (SAXException e) {
Log.e(TAG, "Unable to parse elevator message", e); Log.e(TAG, "Unable to parse elevator message", e);
return null; return null;
} }
return handler.getMessage(); return handler.getMessage();
} }
@Override @Override
protected boolean supports(Class<?> arg0) { protected boolean supports(Class<?> arg0) {
return String.class.equals(arg0); return String.class.equals(arg0);
} }
@Override @Override
public List<MediaType> getSupportedMediaTypes() { public List<MediaType> getSupportedMediaTypes() {
final List<MediaType> supportedMediaTypes = new ArrayList<MediaType>(); final List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
supportedMediaTypes.add(MediaType.TEXT_HTML); supportedMediaTypes.add(MediaType.TEXT_HTML);
supportedMediaTypes.add(MediaType.TEXT_XML); supportedMediaTypes.add(MediaType.TEXT_XML);
supportedMediaTypes.addAll(super.getSupportedMediaTypes()); supportedMediaTypes.addAll(super.getSupportedMediaTypes());
return supportedMediaTypes; return supportedMediaTypes;
} }
@Override @Override
protected void writeInternal(String arg0, HttpOutputMessage arg1) protected void writeInternal(String arg0, HttpOutputMessage arg1)
throws IOException, HttpMessageNotWritableException { throws IOException, HttpMessageNotWritableException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
private static class ElevatorMessageHandler extends DefaultHandler { private static class ElevatorMessageHandler extends DefaultHandler {
private String currentValue; private String currentValue;
private boolean isParsingTag; private boolean isParsingTag;
private String message; private String message;
public String getMessage() { public String getMessage() {
return message; return message;
} }
@Override @Override
public void characters(char[] ch, int start, int length) public void characters(char[] ch, int start, int length)
throws SAXException { throws SAXException {
if (isParsingTag) { if (isParsingTag) {
currentValue = new String(ch, start, length); currentValue = new String(ch, start, length);
} }
} }
@Override @Override
public void startElement(String uri, String localName, String qName, public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException { Attributes attributes) throws SAXException {
if ("description".equals(localName)) { if ("description".equals(localName)) {
isParsingTag = true; isParsingTag = true;
} }
} }
@Override @Override
public void endElement(String uri, String localName, String qName) public void endElement(String uri, String localName, String qName)
throws SAXException { throws SAXException {
if ("description".equals(localName)) { if ("description".equals(localName)) {
message = currentValue; message = currentValue;
} }
isParsingTag = false; isParsingTag = false;
currentValue = null; currentValue = null;
} }
} }
} }

View File

@ -19,104 +19,104 @@ import com.dougkeen.bart.model.Route;
import com.dougkeen.bart.model.Station; import com.dougkeen.bart.model.Station;
public class EtdContentHandler extends DefaultHandler { public class EtdContentHandler extends DefaultHandler {
public EtdContentHandler(Station origin, Station destination, public EtdContentHandler(Station origin, Station destination,
List<Route> routes) { List<Route> routes) {
super(); super();
realTimeDepartures = new RealTimeDepartures(origin, destination, routes); realTimeDepartures = new RealTimeDepartures(origin, destination, routes);
} }
private final static List<String> TAGS = Arrays.asList("date", "time", private final static List<String> TAGS = Arrays.asList("date", "time",
"abbreviation", "minutes", "platform", "direction", "length", "abbreviation", "minutes", "platform", "direction", "length",
"color", "hexcolor", "bikeflag"); "color", "hexcolor", "bikeflag");
private RealTimeDepartures realTimeDepartures; private RealTimeDepartures realTimeDepartures;
public RealTimeDepartures getRealTimeDepartures() { public RealTimeDepartures getRealTimeDepartures() {
return realTimeDepartures; return realTimeDepartures;
} }
private String date; private String date;
private String currentDestination; private String currentDestination;
private String currentValue; private String currentValue;
private Departure currentDeparture; private Departure currentDeparture;
private boolean isParsingTag; private boolean isParsingTag;
@Override @Override
public void characters(char[] ch, int start, int length) public void characters(char[] ch, int start, int length)
throws SAXException { throws SAXException {
if (isParsingTag) { if (isParsingTag) {
currentValue = new String(ch, start, length); currentValue = new String(ch, start, length);
} }
} }
@Override @Override
public void startElement(String uri, String localName, String qName, public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException { Attributes attributes) throws SAXException {
if (TAGS.contains(localName)) { if (TAGS.contains(localName)) {
isParsingTag = true; isParsingTag = true;
} }
if (localName.equals("estimate")) { if (localName.equals("estimate")) {
currentDeparture = new Departure(); currentDeparture = new Departure();
currentDeparture.setTrainDestination(Station currentDeparture.setTrainDestination(Station
.getByAbbreviation(currentDestination)); .getByAbbreviation(currentDestination));
currentDeparture.setOrigin(realTimeDepartures.getOrigin()); currentDeparture.setOrigin(realTimeDepartures.getOrigin());
} }
} }
@Override @Override
public void endElement(String uri, String localName, String qName) public void endElement(String uri, String localName, String qName)
throws SAXException { throws SAXException {
if (localName.equals("date")) { if (localName.equals("date")) {
date = currentValue; date = currentValue;
} else if (localName.equals("time")) { } else if (localName.equals("time")) {
realTimeDepartures.setTime(Date.parse(date + " " + currentValue)); realTimeDepartures.setTime(Date.parse(date + " " + currentValue));
} else if (localName.equals("abbreviation")) { } else if (localName.equals("abbreviation")) {
currentDestination = currentValue; currentDestination = currentValue;
} else if (localName.equals("minutes")) { } else if (localName.equals("minutes")) {
if (StringUtils.isNumeric(currentValue)) { if (StringUtils.isNumeric(currentValue)) {
currentDeparture.setMinutes(Integer.parseInt(currentValue)); currentDeparture.setMinutes(Integer.parseInt(currentValue));
} else { } else {
currentDeparture.setMinutes(0); currentDeparture.setMinutes(0);
} }
} else if (localName.equals("platform")) { } else if (localName.equals("platform")) {
currentDeparture.setPlatform(currentValue); currentDeparture.setPlatform(currentValue);
} else if (localName.equals("direction")) { } else if (localName.equals("direction")) {
currentDeparture.setDirection(currentValue); currentDeparture.setDirection(currentValue);
} else if (localName.equals("length")) { } else if (localName.equals("length")) {
currentDeparture.setTrainLength(currentValue); currentDeparture.setTrainLength(currentValue);
} else if (localName.equals("color")) { } else if (localName.equals("color")) {
try { try {
if (currentValue.equalsIgnoreCase("WHITE")) { if (currentValue.equalsIgnoreCase("WHITE")) {
for (Line line : Line.values()) { for (Line line : Line.values()) {
if (line.stations.indexOf(currentDeparture if (line.stations.indexOf(currentDeparture
.getTrainDestination()) >= 0 .getTrainDestination()) >= 0
&& line.stations.indexOf(realTimeDepartures && line.stations.indexOf(realTimeDepartures
.getDestination()) >= 0) { .getDestination()) >= 0) {
currentDeparture.setLine(line); currentDeparture.setLine(line);
break; break;
} }
} }
} else { } else {
currentDeparture.setLine(Line.valueOf(currentValue)); currentDeparture.setLine(Line.valueOf(currentValue));
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.w(Constants.TAG, "There is no line called '" + currentValue Log.w(Constants.TAG, "There is no line called '" + currentValue
+ "'"); + "'");
} }
} else if (localName.equals("hexcolor")) { } else if (localName.equals("hexcolor")) {
currentDeparture.setTrainDestinationColor("#ff" currentDeparture.setTrainDestinationColor("#ff"
+ currentValue.substring(1)); + currentValue.substring(1));
} else if (localName.equals("bikeflag")) { } else if (localName.equals("bikeflag")) {
currentDeparture.setBikeAllowed(currentValue.equalsIgnoreCase("1")); currentDeparture.setBikeAllowed(currentValue.equalsIgnoreCase("1"));
} else if (localName.equals("estimate")) { } else if (localName.equals("estimate")) {
realTimeDepartures.addDeparture(currentDeparture); realTimeDepartures.addDeparture(currentDeparture);
currentDeparture = null; currentDeparture = null;
} else if (localName.equals("etd")) { } else if (localName.equals("etd")) {
currentDestination = null; currentDestination = null;
} else if (localName.equals("station")) { } else if (localName.equals("station")) {
realTimeDepartures.finalizeDeparturesList(); realTimeDepartures.finalizeDeparturesList();
} }
isParsingTag = false; isParsingTag = false;
currentValue = null; currentValue = null;
} }
} }

View File

@ -5,42 +5,42 @@ import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
public class FareContentHandler extends DefaultHandler { public class FareContentHandler extends DefaultHandler {
public FareContentHandler() { public FareContentHandler() {
super(); super();
} }
private String currentValue; private String currentValue;
private boolean isParsingTag; private boolean isParsingTag;
private String fare; private String fare;
public String getFare() { public String getFare() {
return fare; return fare;
} }
@Override @Override
public void characters(char[] ch, int start, int length) public void characters(char[] ch, int start, int length)
throws SAXException { throws SAXException {
if (isParsingTag) { if (isParsingTag) {
currentValue = new String(ch, start, length); currentValue = new String(ch, start, length);
} }
} }
@Override @Override
public void startElement(String uri, String localName, String qName, public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException { Attributes attributes) throws SAXException {
if (localName.equals("fare")) { if (localName.equals("fare")) {
isParsingTag = true; isParsingTag = true;
} }
} }
@Override @Override
public void endElement(String uri, String localName, String qName) public void endElement(String uri, String localName, String qName)
throws SAXException { throws SAXException {
if (localName.equals("fare")) { if (localName.equals("fare")) {
fare = "$" + currentValue; fare = "$" + currentValue;
} }
isParsingTag = false; isParsingTag = false;
currentValue = null; currentValue = null;
} }
} }

View File

@ -22,132 +22,132 @@ import com.dougkeen.bart.model.Route;
import com.dougkeen.bart.model.StationPair; import com.dougkeen.bart.model.StationPair;
public abstract class GetRealTimeDeparturesTask extends public abstract class GetRealTimeDeparturesTask extends
AsyncTask<StationPair, Integer, RealTimeDepartures> { AsyncTask<StationPair, Integer, RealTimeDepartures> {
private final static String ETD_URL = "http://api.bart.gov/api/etd.aspx?cmd=etd&key=" private final static String ETD_URL = "http://api.bart.gov/api/etd.aspx?cmd=etd&key="
+ Constants.API_KEY + "&orig=%1$s&dir=%2$s"; + Constants.API_KEY + "&orig=%1$s&dir=%2$s";
private final static String ETD_URL_NO_DIRECTION = "http://api.bart.gov/api/etd.aspx?cmd=etd&key=" private final static String ETD_URL_NO_DIRECTION = "http://api.bart.gov/api/etd.aspx?cmd=etd&key="
+ Constants.API_KEY + "&orig=%1$s"; + Constants.API_KEY + "&orig=%1$s";
private final static int MAX_ATTEMPTS = 5; private final static int MAX_ATTEMPTS = 5;
private Exception mException; private Exception mException;
private List<Route> mRoutes; private List<Route> mRoutes;
private final boolean ignoreDirection; private final boolean ignoreDirection;
public GetRealTimeDeparturesTask(boolean ignoreDirection) { public GetRealTimeDeparturesTask(boolean ignoreDirection) {
super(); super();
this.ignoreDirection = ignoreDirection; this.ignoreDirection = ignoreDirection;
} }
@Override @Override
protected RealTimeDepartures doInBackground(StationPair... paramsArray) { protected RealTimeDepartures doInBackground(StationPair... paramsArray) {
// Always expect one param // Always expect one param
StationPair params = paramsArray[0]; StationPair params = paramsArray[0];
mRoutes = params.getOrigin().getDirectRoutesForDestination( mRoutes = params.getOrigin().getDirectRoutesForDestination(
params.getDestination()); params.getDestination());
boolean hasDirectLine = false; boolean hasDirectLine = false;
for (Route route : mRoutes) { for (Route route : mRoutes) {
if (!route.hasTransfer()) { if (!route.hasTransfer()) {
hasDirectLine = true; hasDirectLine = true;
break; break;
} }
} }
if (mRoutes.isEmpty() if (mRoutes.isEmpty()
|| (params.getOrigin().transferFriendly && !hasDirectLine)) { || (params.getOrigin().transferFriendly && !hasDirectLine)) {
mRoutes.addAll(params.getOrigin().getTransferRoutes( mRoutes.addAll(params.getOrigin().getTransferRoutes(
params.getDestination())); params.getDestination()));
} }
if (!isCancelled()) { if (!isCancelled()) {
return getDeparturesFromNetwork(params, 0); return getDeparturesFromNetwork(params, 0);
} else { } else {
return null; return null;
} }
} }
private RealTimeDepartures getDeparturesFromNetwork(StationPair params, private RealTimeDepartures getDeparturesFromNetwork(StationPair params,
int attemptNumber) { int attemptNumber) {
String xml = null; String xml = null;
try { try {
String url; String url;
if (ignoreDirection || params.getOrigin().endOfLine) { if (ignoreDirection || params.getOrigin().endOfLine) {
url = String.format(ETD_URL_NO_DIRECTION, url = String.format(ETD_URL_NO_DIRECTION,
params.getOrigin().abbreviation); params.getOrigin().abbreviation);
} else { } else {
url = String.format(ETD_URL, params.getOrigin().abbreviation, url = String.format(ETD_URL, params.getOrigin().abbreviation,
mRoutes.get(0).getDirection()); mRoutes.get(0).getDirection());
} }
HttpUriRequest request = new HttpGet(url); HttpUriRequest request = new HttpGet(url);
EtdContentHandler handler = new EtdContentHandler( EtdContentHandler handler = new EtdContentHandler(
params.getOrigin(), params.getDestination(), mRoutes); params.getOrigin(), params.getDestination(), mRoutes);
if (isCancelled()) { if (isCancelled()) {
return null; return null;
} }
HttpResponse response = NetworkUtils.executeWithRecovery(request); HttpResponse response = NetworkUtils.executeWithRecovery(request);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new IOException("Server returned " throw new IOException("Server returned "
+ response.getStatusLine().toString()); + response.getStatusLine().toString());
} }
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8"); IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8");
xml = writer.toString(); xml = writer.toString();
if (xml.length() == 0) { if (xml.length() == 0) {
throw new IOException("Server returned blank xml document"); throw new IOException("Server returned blank xml document");
} }
try { try {
Xml.parse(xml, handler); Xml.parse(xml, handler);
} catch (Exception e) { } catch (Exception e) {
mException = new IOException("Server returned malformed xml: " mException = new IOException("Server returned malformed xml: "
+ xml); + xml);
return null; return null;
} }
final RealTimeDepartures realTimeDepartures = handler final RealTimeDepartures realTimeDepartures = handler
.getRealTimeDepartures(); .getRealTimeDepartures();
return realTimeDepartures; return realTimeDepartures;
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (IOException e) { } catch (IOException e) {
if (attemptNumber < MAX_ATTEMPTS - 1) { if (attemptNumber < MAX_ATTEMPTS - 1) {
try { try {
Log.w(Constants.TAG, Log.w(Constants.TAG,
"Attempt to contact server failed... retrying in 3s", "Attempt to contact server failed... retrying in 3s",
e); e);
Thread.sleep(3000); Thread.sleep(3000);
} catch (InterruptedException interrupt) { } catch (InterruptedException interrupt) {
// Ignore... just go on to next attempt // Ignore... just go on to next attempt
} }
return getDeparturesFromNetwork(params, attemptNumber + 1); return getDeparturesFromNetwork(params, attemptNumber + 1);
} else { } else {
mException = new Exception("Could not contact BART system", e); mException = new Exception("Could not contact BART system", e);
return null; return null;
} }
} }
} }
@Override @Override
protected void onPostExecute(RealTimeDepartures result) { protected void onPostExecute(RealTimeDepartures result) {
if (result != null) { if (result != null) {
onResult(result); onResult(result);
} else { } else {
onError(mException); onError(mException);
} }
} }
public abstract void onResult(RealTimeDepartures result); public abstract void onResult(RealTimeDepartures result);
public abstract void onError(Exception exception); public abstract void onError(Exception exception);
} }

View File

@ -20,106 +20,106 @@ import com.dougkeen.bart.model.Constants;
import com.dougkeen.bart.model.Station; import com.dougkeen.bart.model.Station;
public abstract class GetRouteFareTask extends public abstract class GetRouteFareTask extends
AsyncTask<GetRouteFareTask.Params, Integer, String> { AsyncTask<GetRouteFareTask.Params, Integer, String> {
private final static int MAX_ATTEMPTS = 5; private final static int MAX_ATTEMPTS = 5;
private final static String FARE_URL = "http://api.bart.gov/api/sched.aspx?cmd=fare&date=today&key=" private final static String FARE_URL = "http://api.bart.gov/api/sched.aspx?cmd=fare&date=today&key="
+ Constants.API_KEY + "&orig=%1$s&dest=%2$s"; + Constants.API_KEY + "&orig=%1$s&dest=%2$s";
private Exception mException; private Exception mException;
private String fare; private String fare;
@Override @Override
protected String doInBackground(Params... paramsArray) { protected String doInBackground(Params... paramsArray) {
Params params = paramsArray[0]; Params params = paramsArray[0];
if (!isCancelled()) { if (!isCancelled()) {
return getFareFromNetwork(params, 0); return getFareFromNetwork(params, 0);
} else { } else {
return null; return null;
} }
} }
private String getFareFromNetwork(Params params, int attemptNumber) { private String getFareFromNetwork(Params params, int attemptNumber) {
String xml = null; String xml = null;
try { try {
HttpUriRequest request = new HttpGet( HttpUriRequest request = new HttpGet(
String.format(FARE_URL, params.origin.abbreviation, String.format(FARE_URL, params.origin.abbreviation,
params.destination.abbreviation)); params.destination.abbreviation));
FareContentHandler handler = new FareContentHandler(); FareContentHandler handler = new FareContentHandler();
if (isCancelled()) { if (isCancelled()) {
return null; return null;
} }
HttpResponse response = NetworkUtils.executeWithRecovery(request); HttpResponse response = NetworkUtils.executeWithRecovery(request);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new IOException("Server returned " throw new IOException("Server returned "
+ response.getStatusLine().toString()); + response.getStatusLine().toString());
} }
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8"); IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8");
xml = writer.toString(); xml = writer.toString();
if (xml.length() == 0) { if (xml.length() == 0) {
throw new IOException("Server returned blank xml document"); throw new IOException("Server returned blank xml document");
} }
Xml.parse(xml, handler); Xml.parse(xml, handler);
fare = handler.getFare(); fare = handler.getFare();
return fare; return fare;
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (IOException e) { } catch (IOException e) {
if (attemptNumber < MAX_ATTEMPTS - 1) { if (attemptNumber < MAX_ATTEMPTS - 1) {
try { try {
Log.w(Constants.TAG, Log.w(Constants.TAG,
"Attempt to contact server failed... retrying in 3s", "Attempt to contact server failed... retrying in 3s",
e); e);
Thread.sleep(3000); Thread.sleep(3000);
} catch (InterruptedException interrupt) { } catch (InterruptedException interrupt) {
// Ignore... just go on to next attempt // Ignore... just go on to next attempt
} }
return getFareFromNetwork(params, attemptNumber + 1); return getFareFromNetwork(params, attemptNumber + 1);
} else { } else {
mException = new Exception("Could not contact BART system", e); mException = new Exception("Could not contact BART system", e);
return null; return null;
} }
} catch (SAXException e) { } catch (SAXException e) {
mException = new Exception( mException = new Exception(
"Could not understand response from BART system: " + xml, e); "Could not understand response from BART system: " + xml, e);
return null; return null;
} }
} }
public static class Params { public static class Params {
public Params(Station origin, Station destination) { public Params(Station origin, Station destination) {
super(); super();
this.origin = origin; this.origin = origin;
this.destination = destination; this.destination = destination;
} }
public final Station origin; public final Station origin;
public final Station destination; public final Station destination;
} }
@Override @Override
protected void onPostExecute(String result) { protected void onPostExecute(String result) {
if (result != null) { if (result != null) {
onResult(fare); onResult(fare);
} else { } else {
onError(mException); onError(mException);
} }
} }
public abstract void onResult(String fare); public abstract void onResult(String fare);
public abstract void onError(Exception exception); public abstract void onError(Exception exception);
} }

View File

@ -21,98 +21,98 @@ import com.dougkeen.bart.model.ScheduleInformation;
import com.dougkeen.bart.model.StationPair; import com.dougkeen.bart.model.StationPair;
public abstract class GetScheduleInformationTask extends public abstract class GetScheduleInformationTask extends
AsyncTask<StationPair, Integer, ScheduleInformation> { AsyncTask<StationPair, Integer, ScheduleInformation> {
private final static String SCHED_URL = "http://api.bart.gov/api/sched.aspx?cmd=depart&key=" private final static String SCHED_URL = "http://api.bart.gov/api/sched.aspx?cmd=depart&key="
+ Constants.API_KEY + "&orig=%1$s&dest=%2$s&b=1&a=4"; + Constants.API_KEY + "&orig=%1$s&dest=%2$s&b=1&a=4";
private final static int MAX_ATTEMPTS = 5; private final static int MAX_ATTEMPTS = 5;
private Exception mException; private Exception mException;
@Override @Override
protected ScheduleInformation doInBackground(StationPair... paramsArray) { protected ScheduleInformation doInBackground(StationPair... paramsArray) {
// Always expect one param // Always expect one param
StationPair params = paramsArray[0]; StationPair params = paramsArray[0];
if (!isCancelled()) { if (!isCancelled()) {
return getScheduleFromNetwork(params, 0); return getScheduleFromNetwork(params, 0);
} else { } else {
return null; return null;
} }
} }
private ScheduleInformation getScheduleFromNetwork(StationPair params, private ScheduleInformation getScheduleFromNetwork(StationPair params,
int attemptNumber) { int attemptNumber) {
String xml = null; String xml = null;
try { try {
String url = String.format(SCHED_URL, String url = String.format(SCHED_URL,
params.getOrigin().abbreviation, params.getOrigin().abbreviation,
params.getDestination().abbreviation); params.getDestination().abbreviation);
HttpUriRequest request = new HttpGet(url); HttpUriRequest request = new HttpGet(url);
if (isCancelled()) { if (isCancelled()) {
return null; return null;
} }
ScheduleContentHandler handler = new ScheduleContentHandler( ScheduleContentHandler handler = new ScheduleContentHandler(
params.getOrigin(), params.getDestination()); params.getOrigin(), params.getDestination());
HttpResponse response = NetworkUtils.executeWithRecovery(request); HttpResponse response = NetworkUtils.executeWithRecovery(request);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new IOException("Server returned " throw new IOException("Server returned "
+ response.getStatusLine().toString()); + response.getStatusLine().toString());
} }
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8"); IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8");
xml = writer.toString(); xml = writer.toString();
if (xml.length() == 0) { if (xml.length() == 0) {
throw new IOException("Server returned blank xml document"); throw new IOException("Server returned blank xml document");
} }
Xml.parse(xml, handler); Xml.parse(xml, handler);
final ScheduleInformation schedule = handler.getSchedule(); final ScheduleInformation schedule = handler.getSchedule();
return schedule; return schedule;
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (IOException e) { } catch (IOException e) {
if (attemptNumber < MAX_ATTEMPTS - 1) { if (attemptNumber < MAX_ATTEMPTS - 1) {
try { try {
Log.w(Constants.TAG, Log.w(Constants.TAG,
"Attempt to contact server failed... retrying in 3s", "Attempt to contact server failed... retrying in 3s",
e); e);
Thread.sleep(3000); Thread.sleep(3000);
} catch (InterruptedException interrupt) { } catch (InterruptedException interrupt) {
// Ignore... just go on to next attempt // Ignore... just go on to next attempt
} }
return getScheduleFromNetwork(params, attemptNumber + 1); return getScheduleFromNetwork(params, attemptNumber + 1);
} else { } else {
mException = new Exception("Could not contact BART system", e); mException = new Exception("Could not contact BART system", e);
return null; return null;
} }
} catch (SAXException e) { } catch (SAXException e) {
mException = new Exception( mException = new Exception(
"Could not understand response from BART system: " + xml, e); "Could not understand response from BART system: " + xml, e);
return null; return null;
} }
} }
@Override @Override
protected void onPostExecute(ScheduleInformation result) { protected void onPostExecute(ScheduleInformation result) {
if (result != null) { if (result != null) {
onResult(result); onResult(result);
} else { } else {
onError(mException); onError(mException);
} }
} }
public abstract void onResult(ScheduleInformation result); public abstract void onResult(ScheduleInformation result);
public abstract void onError(Exception exception); public abstract void onError(Exception exception);
} }

View File

@ -13,28 +13,28 @@ import org.apache.http.params.HttpParams;
public class NetworkUtils { public class NetworkUtils {
public static HttpClient getHttpClient() { public static HttpClient getHttpClient() {
HttpClient client = new DefaultHttpClient(); HttpClient client = new DefaultHttpClient();
final HttpParams params = client.getParams(); final HttpParams params = client.getParams();
HttpConnectionParams.setConnectionTimeout(params, HttpConnectionParams.setConnectionTimeout(params,
NetworkUtils.CONNECTION_TIMEOUT_MILLIS); NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
HttpConnectionParams.setSoTimeout(params, HttpConnectionParams.setSoTimeout(params,
NetworkUtils.CONNECTION_TIMEOUT_MILLIS); NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
ConnManagerParams.setTimeout(params, ConnManagerParams.setTimeout(params,
NetworkUtils.CONNECTION_TIMEOUT_MILLIS); NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
return client; return client;
} }
public static HttpResponse executeWithRecovery(final HttpUriRequest request) public static HttpResponse executeWithRecovery(final HttpUriRequest request)
throws IOException, ClientProtocolException { throws IOException {
try { try {
return getHttpClient().execute(request); return getHttpClient().execute(request);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
// try again... this is a rare error // try again... this is a rare error
return getHttpClient().execute(request); return getHttpClient().execute(request);
} }
} }
static final int CONNECTION_TIMEOUT_MILLIS = 10000; static final int CONNECTION_TIMEOUT_MILLIS = 10000;
} }

View File

@ -19,149 +19,149 @@ import com.dougkeen.bart.model.ScheduleItem;
import com.dougkeen.bart.model.Station; import com.dougkeen.bart.model.Station;
public class ScheduleContentHandler extends DefaultHandler { public class ScheduleContentHandler extends DefaultHandler {
public ScheduleContentHandler(Station origin, Station destination) { public ScheduleContentHandler(Station origin, Station destination) {
super(); super();
schedule = new ScheduleInformation(origin, destination); schedule = new ScheduleInformation(origin, destination);
} }
private final static List<String> TAGS = Arrays.asList("date", "time", private final static List<String> TAGS = Arrays.asList("date", "time",
"trip", "leg"); "trip", "leg");
private final static DateFormat TRIP_DATE_FORMAT; private final static DateFormat TRIP_DATE_FORMAT;
private final static DateFormat REQUEST_DATE_FORMAT; private final static DateFormat REQUEST_DATE_FORMAT;
private final static TimeZone PACIFIC_TIME = TimeZone private final static TimeZone PACIFIC_TIME = TimeZone
.getTimeZone("America/Los_Angeles"); .getTimeZone("America/Los_Angeles");
static { static {
TRIP_DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy h:mm a"); TRIP_DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy h:mm a");
REQUEST_DATE_FORMAT = new SimpleDateFormat("MMM d, yyyy h:mm a"); REQUEST_DATE_FORMAT = new SimpleDateFormat("MMM d, yyyy h:mm a");
TRIP_DATE_FORMAT.setTimeZone(PACIFIC_TIME); TRIP_DATE_FORMAT.setTimeZone(PACIFIC_TIME);
REQUEST_DATE_FORMAT.setTimeZone(PACIFIC_TIME); REQUEST_DATE_FORMAT.setTimeZone(PACIFIC_TIME);
} }
private ScheduleInformation schedule; private ScheduleInformation schedule;
public ScheduleInformation getSchedule() { public ScheduleInformation getSchedule() {
return schedule; return schedule;
} }
private String currentValue; private String currentValue;
private boolean isParsingTag; private boolean isParsingTag;
private String requestDate; private String requestDate;
private String requestTime; private String requestTime;
private ScheduleItem currentTrip; private ScheduleItem currentTrip;
@Override @Override
public void characters(char[] ch, int start, int length) public void characters(char[] ch, int start, int length)
throws SAXException { throws SAXException {
if (isParsingTag) { if (isParsingTag) {
currentValue = new String(ch, start, length); currentValue = new String(ch, start, length);
} }
} }
@Override @Override
public void startElement(String uri, String localName, String qName, public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException { Attributes attributes) throws SAXException {
if (TAGS.contains(localName)) { if (TAGS.contains(localName)) {
isParsingTag = true; isParsingTag = true;
} }
final int numberOfAttributes = attributes.getLength(); final int numberOfAttributes = attributes.getLength();
if (localName.equals("trip")) { if (localName.equals("trip")) {
currentTrip = new ScheduleItem(); currentTrip = new ScheduleItem();
String originDate = null; String originDate = null;
String originTime = null; String originTime = null;
String destinationDate = null; String destinationDate = null;
String destinationTime = null; String destinationTime = null;
for (int i = 0; i < numberOfAttributes; i++) { for (int i = 0; i < numberOfAttributes; i++) {
if (attributes.getLocalName(i).equalsIgnoreCase("origin")) { if (attributes.getLocalName(i).equalsIgnoreCase("origin")) {
currentTrip.setOrigin(Station.getByAbbreviation(attributes currentTrip.setOrigin(Station.getByAbbreviation(attributes
.getValue(i))); .getValue(i)));
} else if (attributes.getLocalName(i).equalsIgnoreCase( } else if (attributes.getLocalName(i).equalsIgnoreCase(
"destination")) { "destination")) {
currentTrip.setDestination(Station currentTrip.setDestination(Station
.getByAbbreviation(attributes.getValue(i))); .getByAbbreviation(attributes.getValue(i)));
} else if (attributes.getLocalName(i).equalsIgnoreCase("fare")) { } else if (attributes.getLocalName(i).equalsIgnoreCase("fare")) {
currentTrip.setFare(attributes.getValue(i)); currentTrip.setFare(attributes.getValue(i));
} else if (attributes.getLocalName(i).equalsIgnoreCase( } else if (attributes.getLocalName(i).equalsIgnoreCase(
"origTimeMin")) { "origTimeMin")) {
originTime = attributes.getValue(i); originTime = attributes.getValue(i);
} else if (attributes.getLocalName(i).equalsIgnoreCase( } else if (attributes.getLocalName(i).equalsIgnoreCase(
"origTimeDate")) { "origTimeDate")) {
originDate = attributes.getValue(i); originDate = attributes.getValue(i);
} else if (attributes.getLocalName(i).equalsIgnoreCase( } else if (attributes.getLocalName(i).equalsIgnoreCase(
"destTimeMin")) { "destTimeMin")) {
destinationTime = attributes.getValue(i); destinationTime = attributes.getValue(i);
} else if (attributes.getLocalName(i).equalsIgnoreCase( } else if (attributes.getLocalName(i).equalsIgnoreCase(
"destTimeDate")) { "destTimeDate")) {
destinationDate = attributes.getValue(i); destinationDate = attributes.getValue(i);
} else if (attributes.getLocalName(i).equalsIgnoreCase( } else if (attributes.getLocalName(i).equalsIgnoreCase(
"bikeFlag")) { "bikeFlag")) {
currentTrip.setBikesAllowed(attributes.getValue(i).equals( currentTrip.setBikesAllowed(attributes.getValue(i).equals(
"1")); "1"));
} }
} }
long departTime = parseDate(TRIP_DATE_FORMAT, originDate, long departTime = parseDate(TRIP_DATE_FORMAT, originDate,
originTime); originTime);
if (departTime > 0) if (departTime > 0)
currentTrip.setDepartureTime(departTime); currentTrip.setDepartureTime(departTime);
long arriveTime = parseDate(TRIP_DATE_FORMAT, destinationDate, long arriveTime = parseDate(TRIP_DATE_FORMAT, destinationDate,
destinationTime); destinationTime);
if (arriveTime > 0) if (arriveTime > 0)
currentTrip.setArrivalTime(arriveTime); currentTrip.setArrivalTime(arriveTime);
schedule.addTrip(currentTrip); schedule.addTrip(currentTrip);
} }
if (localName.equals("leg")) { if (localName.equals("leg")) {
String legNumber = null; String legNumber = null;
for (int i = 0; i < numberOfAttributes; i++) { for (int i = 0; i < numberOfAttributes; i++) {
if (attributes.getLocalName(i).equals("order")) { if (attributes.getLocalName(i).equals("order")) {
legNumber = attributes.getValue(i); legNumber = attributes.getValue(i);
} else if (attributes.getLocalName(i) } else if (attributes.getLocalName(i)
.equals("trainHeadStation") && "1".equals(legNumber)) { .equals("trainHeadStation") && "1".equals(legNumber)) {
currentTrip.setTrainHeadStation(attributes.getValue(i) currentTrip.setTrainHeadStation(attributes.getValue(i)
.toLowerCase()); .toLowerCase());
} }
} }
} }
} }
private long parseDate(DateFormat format, String dateString, private long parseDate(DateFormat format, String dateString,
String timeString) { String timeString) {
if (dateString == null || timeString == null) { if (dateString == null || timeString == null) {
return -1; return -1;
} }
try { try {
return format.parse(dateString + " " + timeString).getTime(); return format.parse(dateString + " " + timeString).getTime();
} catch (ParseException e) { } catch (ParseException e) {
Log.e(Constants.TAG, "Unable to parse datetime '" + dateString Log.e(Constants.TAG, "Unable to parse datetime '" + dateString
+ " " + timeString + "'", e); + " " + timeString + "'", e);
return -1; return -1;
} }
} }
@Override @Override
public void endElement(String uri, String localName, String qName) public void endElement(String uri, String localName, String qName)
throws SAXException { throws SAXException {
if (localName.equals("date")) { if (localName.equals("date")) {
requestDate = currentValue; requestDate = currentValue;
} else if (localName.equals("time")) { } else if (localName.equals("time")) {
requestTime = currentValue; requestTime = currentValue;
} }
isParsingTag = false; isParsingTag = false;
currentValue = null; currentValue = null;
} }
@Override @Override
public void endDocument() { public void endDocument() {
long date = parseDate(REQUEST_DATE_FORMAT, requestDate, requestTime); long date = parseDate(REQUEST_DATE_FORMAT, requestDate, requestTime);
if (date > 0) { if (date > 0) {
schedule.setDate(date); schedule.setDate(date);
} }
} }
} }

View File

@ -12,28 +12,28 @@ import com.dougkeen.util.WakeLocker;
public class AlarmBroadcastReceiver extends BroadcastReceiver { public class AlarmBroadcastReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
BartRunnerApplication application = (BartRunnerApplication) context BartRunnerApplication application = (BartRunnerApplication) context
.getApplicationContext(); .getApplicationContext();
final Departure boardedDeparture = application.getBoardedDeparture(true); final Departure boardedDeparture = application.getBoardedDeparture(true);
if (boardedDeparture == null) { if (boardedDeparture == null) {
// Nothing to notify about // Nothing to notify about
return; return;
} }
WakeLocker.acquire(context); WakeLocker.acquire(context);
application.setPlayAlarmRingtone(true); application.setPlayAlarmRingtone(true);
Intent targetIntent = new Intent(context, ViewDeparturesActivity.class); Intent targetIntent = new Intent(context, ViewDeparturesActivity.class);
targetIntent.putExtra(Constants.STATION_PAIR_EXTRA, targetIntent.putExtra(Constants.STATION_PAIR_EXTRA,
boardedDeparture.getStationPair()); boardedDeparture.getStationPair());
targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(targetIntent); context.startActivity(targetIntent);
boardedDeparture.notifyAlarmHasBeenHandled(); boardedDeparture.notifyAlarmHasBeenHandled();
} }
} }

View File

@ -24,229 +24,229 @@ import com.dougkeen.bart.services.EtdService.EtdServiceListener;
import com.dougkeen.util.Observer; import com.dougkeen.util.Observer;
public class BoardedDepartureService extends Service implements public class BoardedDepartureService extends Service implements
EtdServiceListener { EtdServiceListener {
private static final int DEPARTURE_NOTIFICATION_ID = 123; private static final int DEPARTURE_NOTIFICATION_ID = 123;
private volatile Looper mServiceLooper; private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler; private volatile ServiceHandler mServiceHandler;
private boolean mBound = false; private boolean mBound = false;
private EtdService mEtdService; private EtdService mEtdService;
private StationPair mStationPair; private StationPair mStationPair;
private NotificationManager mNotificationManager; private NotificationManager mNotificationManager;
private AlarmManager mAlarmManager; private AlarmManager mAlarmManager;
private Handler mHandler; private Handler mHandler;
private boolean mHasShutDown = false; private boolean mHasShutDown = false;
public BoardedDepartureService() { public BoardedDepartureService() {
super(); super();
} }
private static final class ServiceHandler extends Handler { private static final class ServiceHandler extends Handler {
private final WeakReference<BoardedDepartureService> mServiceRef; private final WeakReference<BoardedDepartureService> mServiceRef;
public ServiceHandler(Looper looper, public ServiceHandler(Looper looper,
BoardedDepartureService boardedDepartureService) { BoardedDepartureService boardedDepartureService) {
super(looper); super(looper);
mServiceRef = new WeakReference<BoardedDepartureService>( mServiceRef = new WeakReference<BoardedDepartureService>(
boardedDepartureService); boardedDepartureService);
} }
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
BoardedDepartureService service = mServiceRef.get(); BoardedDepartureService service = mServiceRef.get();
if (service != null) { if (service != null) {
service.onHandleIntent((Intent) msg.obj); service.onHandleIntent((Intent) msg.obj);
} }
} }
} }
private final ServiceConnection mConnection = new ServiceConnection() { private final ServiceConnection mConnection = new ServiceConnection() {
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
mEtdService = null; mEtdService = null;
mBound = false; mBound = false;
} }
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
mEtdService = ((EtdServiceBinder) service).getService(); mEtdService = ((EtdServiceBinder) service).getService();
if (getStationPair() != null) { if (getStationPair() != null) {
mEtdService.registerListener(BoardedDepartureService.this, mEtdService.registerListener(BoardedDepartureService.this,
false); false);
} }
mBound = true; mBound = true;
} }
}; };
@Override @Override
public void onCreate() { public void onCreate() {
HandlerThread thread = new HandlerThread( HandlerThread thread = new HandlerThread(
"BartRunnerNotificationService"); "BartRunnerNotificationService");
thread.start(); thread.start();
mServiceLooper = thread.getLooper(); mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper, this); mServiceHandler = new ServiceHandler(mServiceLooper, this);
bindService(EtdService_.intent(this).get(), mConnection, bindService(EtdService_.intent(this).get(), mConnection,
Context.BIND_AUTO_CREATE); Context.BIND_AUTO_CREATE);
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mHandler = new Handler(); mHandler = new Handler();
super.onCreate(); super.onCreate();
} }
@Override @Override
public void onStart(Intent intent, int startId) { public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage(); Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId; msg.arg1 = startId;
msg.obj = intent; msg.obj = intent;
mServiceHandler.sendMessage(msg); mServiceHandler.sendMessage(msg);
} }
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
mHasShutDown = false; mHasShutDown = false;
onStart(intent, startId); onStart(intent, startId);
return START_REDELIVER_INTENT; return START_REDELIVER_INTENT;
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
shutDown(true); shutDown(true);
if (mBound) if (mBound)
unbindService(mConnection); unbindService(mConnection);
mServiceLooper.quit(); mServiceLooper.quit();
super.onDestroy(); super.onDestroy();
} }
protected void onHandleIntent(Intent intent) { protected void onHandleIntent(Intent intent) {
if (intent == null) if (intent == null)
return; return;
final BartRunnerApplication application = (BartRunnerApplication) getApplication(); final BartRunnerApplication application = (BartRunnerApplication) getApplication();
final Departure boardedDeparture; final Departure boardedDeparture;
if (intent.hasExtra("departure")) { if (intent.hasExtra("departure")) {
boardedDeparture = intent.getExtras().getParcelable("departure"); boardedDeparture = intent.getExtras().getParcelable("departure");
} else { } else {
boardedDeparture = application.getBoardedDeparture(); boardedDeparture = application.getBoardedDeparture();
} }
if (boardedDeparture == null) { if (boardedDeparture == null) {
// Nothing to notify about // Nothing to notify about
if (mNotificationManager != null) { if (mNotificationManager != null) {
mNotificationManager.cancel(DEPARTURE_NOTIFICATION_ID); mNotificationManager.cancel(DEPARTURE_NOTIFICATION_ID);
} }
return; return;
} }
if (intent.getBooleanExtra("cancelNotifications", false) if (intent.getBooleanExtra("cancelNotifications", false)
|| intent.getBooleanExtra("clearBoardedDeparture", false)) { || intent.getBooleanExtra("clearBoardedDeparture", false)) {
// We want to cancel the alarm // We want to cancel the alarm
boardedDeparture boardedDeparture
.cancelAlarm(getApplicationContext(), mAlarmManager); .cancelAlarm(getApplicationContext(), mAlarmManager);
if (intent.getBooleanExtra("clearBoardedDeparture", false)) { if (intent.getBooleanExtra("clearBoardedDeparture", false)) {
application.setBoardedDeparture(null); application.setBoardedDeparture(null);
shutDown(false); shutDown(false);
} else { } else {
updateNotification(); updateNotification();
} }
return; return;
} }
StationPair oldStationPair = mStationPair; StationPair oldStationPair = mStationPair;
mStationPair = boardedDeparture.getStationPair(); mStationPair = boardedDeparture.getStationPair();
if (mEtdService != null && mStationPair != null if (mEtdService != null && mStationPair != null
&& !mStationPair.equals(oldStationPair)) { && !mStationPair.equals(oldStationPair)) {
mEtdService.unregisterListener(this); mEtdService.unregisterListener(this);
} }
if (getStationPair() != null && mEtdService != null) { if (getStationPair() != null && mEtdService != null) {
mEtdService.registerListener(this, false); mEtdService.registerListener(this, false);
} }
boardedDeparture.getAlarmLeadTimeMinutesObservable().registerObserver( boardedDeparture.getAlarmLeadTimeMinutesObservable().registerObserver(
new Observer<Integer>() { new Observer<Integer>() {
@Override @Override
public void onUpdate(Integer newValue) { public void onUpdate(Integer newValue) {
updateNotification(); updateNotification();
} }
}); });
boardedDeparture.getAlarmPendingObservable().registerObserver( boardedDeparture.getAlarmPendingObservable().registerObserver(
new Observer<Boolean>() { new Observer<Boolean>() {
@Override @Override
public void onUpdate(Boolean newValue) { public void onUpdate(Boolean newValue) {
updateNotification(); updateNotification();
} }
}); });
updateNotification(); updateNotification();
pollDepartureStatus(); pollDepartureStatus();
} }
private void updateAlarm() { private void updateAlarm() {
Departure boardedDeparture = ((BartRunnerApplication) getApplication()) Departure boardedDeparture = ((BartRunnerApplication) getApplication())
.getBoardedDeparture(); .getBoardedDeparture();
if (boardedDeparture != null) { if (boardedDeparture != null) {
boardedDeparture boardedDeparture
.updateAlarm(getApplicationContext(), mAlarmManager); .updateAlarm(getApplicationContext(), mAlarmManager);
} }
} }
@Override @Override
public void onETDChanged(List<Departure> departures) { public void onETDChanged(List<Departure> departures) {
final Departure boardedDeparture = ((BartRunnerApplication) getApplication()) final Departure boardedDeparture = ((BartRunnerApplication) getApplication())
.getBoardedDeparture(); .getBoardedDeparture();
for (Departure departure : departures) { for (Departure departure : departures) {
if (departure.equals(boardedDeparture) if (departure.equals(boardedDeparture)
&& (boardedDeparture.getMeanSecondsLeft() != departure && (boardedDeparture.getMeanSecondsLeft() != departure
.getMeanSecondsLeft() || boardedDeparture .getMeanSecondsLeft() || boardedDeparture
.getUncertaintySeconds() != departure .getUncertaintySeconds() != departure
.getUncertaintySeconds())) { .getUncertaintySeconds())) {
boardedDeparture.mergeEstimate(departure); boardedDeparture.mergeEstimate(departure);
// Also merge back, in case boardedDeparture estimate is better // Also merge back, in case boardedDeparture estimate is better
departure.mergeEstimate(boardedDeparture); departure.mergeEstimate(boardedDeparture);
updateAlarm(); updateAlarm();
break; break;
} }
} }
} }
@Override @Override
public void onError(String errorMessage) { public void onError(String errorMessage) {
// Do nothing // Do nothing
} }
@Override @Override
public void onRequestStarted() { public void onRequestStarted() {
// Do nothing // Do nothing
} }
@Override @Override
public void onRequestEnded() { public void onRequestEnded() {
// Do nothing // Do nothing
} }
@Override @Override
public StationPair getStationPair() { public StationPair getStationPair() {
return mStationPair; return mStationPair;
} }
private long mNextScheduledCheckClockTime = 0; private long mNextScheduledCheckClockTime = 0;
private void pollDepartureStatus() { private void pollDepartureStatus() {
final Departure boardedDeparture = ((BartRunnerApplication) getApplication()) final Departure boardedDeparture = ((BartRunnerApplication) getApplication())
.getBoardedDeparture(); .getBoardedDeparture();
if (boardedDeparture == null || boardedDeparture.hasDeparted()) { if (boardedDeparture == null || boardedDeparture.hasDeparted()) {
shutDown(false); shutDown(false);
return; return;
} }
if (mEtdService != null) { if (mEtdService != null) {
/* /*
* Make sure we're still listening for ETD changes (in case weak ref * Make sure we're still listening for ETD changes (in case weak ref
* was garbage collected). Not a huge fan of this approach, but I * was garbage collected). Not a huge fan of this approach, but I
* think I'd rather keep the weak references to avoid memory leaks * think I'd rather keep the weak references to avoid memory leaks
@ -255,73 +255,73 @@ public class BoardedDepartureService extends Service implements
* few constant-time map operations, so there shouldn't be a big * few constant-time map operations, so there shouldn't be a big
* performance hit. * performance hit.
*/ */
mEtdService.registerListener(this, false); mEtdService.registerListener(this, false);
} }
boardedDeparture.updateAlarm(getApplicationContext(), mAlarmManager); boardedDeparture.updateAlarm(getApplicationContext(), mAlarmManager);
updateNotification(); updateNotification();
final int pollIntervalMillis = getPollIntervalMillis(); final int pollIntervalMillis = getPollIntervalMillis();
final long scheduledCheckClockTime = System.currentTimeMillis() final long scheduledCheckClockTime = System.currentTimeMillis()
+ pollIntervalMillis; + pollIntervalMillis;
if (mNextScheduledCheckClockTime < scheduledCheckClockTime) { if (mNextScheduledCheckClockTime < scheduledCheckClockTime) {
mHandler.postDelayed(new Runnable() { mHandler.postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
pollDepartureStatus(); pollDepartureStatus();
} }
}, pollIntervalMillis); }, pollIntervalMillis);
mNextScheduledCheckClockTime = scheduledCheckClockTime; mNextScheduledCheckClockTime = scheduledCheckClockTime;
} }
} }
private void shutDown(boolean isBeingDestroyed) { private void shutDown(boolean isBeingDestroyed) {
if (!mHasShutDown) { if (!mHasShutDown) {
mHasShutDown = true; mHasShutDown = true;
if (mEtdService != null) { if (mEtdService != null) {
mEtdService.unregisterListener(this); mEtdService.unregisterListener(this);
} }
if (mNotificationManager != null) { if (mNotificationManager != null) {
mNotificationManager.cancel(DEPARTURE_NOTIFICATION_ID); mNotificationManager.cancel(DEPARTURE_NOTIFICATION_ID);
} }
if (!isBeingDestroyed) if (!isBeingDestroyed)
stopSelf(); stopSelf();
} }
} }
private void updateNotification() { private void updateNotification() {
if (mHasShutDown) { if (mHasShutDown) {
if (mEtdService != null) { if (mEtdService != null) {
mEtdService.unregisterListener(this); mEtdService.unregisterListener(this);
} }
return; return;
} }
final Departure boardedDeparture = ((BartRunnerApplication) getApplication()) final Departure boardedDeparture = ((BartRunnerApplication) getApplication())
.getBoardedDeparture(); .getBoardedDeparture();
if (boardedDeparture != null) { if (boardedDeparture != null) {
mNotificationManager.notify(DEPARTURE_NOTIFICATION_ID, mNotificationManager.notify(DEPARTURE_NOTIFICATION_ID,
boardedDeparture boardedDeparture
.createNotification(getApplicationContext())); .createNotification(getApplicationContext()));
} }
} }
private int getPollIntervalMillis() { private int getPollIntervalMillis() {
final Departure boardedDeparture = ((BartRunnerApplication) getApplication()) final Departure boardedDeparture = ((BartRunnerApplication) getApplication())
.getBoardedDeparture(); .getBoardedDeparture();
if (boardedDeparture.getSecondsUntilAlarm() > 3 * 60) { if (boardedDeparture.getSecondsUntilAlarm() > 3 * 60) {
return 15 * 1000; return 15 * 1000;
} else { } else {
return 6 * 1000; return 6 * 1000;
} }
} }
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
// Doesn't support binding // Doesn't support binding
return null; return null;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -5,46 +5,46 @@ import java.util.WeakHashMap;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
public class Observable<T> { public class Observable<T> {
private T value; private T value;
private WeakHashMap<Observer<T>, Boolean> listeners = new WeakHashMap<Observer<T>, Boolean>(); private WeakHashMap<Observer<T>, Boolean> listeners = new WeakHashMap<Observer<T>, Boolean>();
public Observable() { public Observable() {
super(); super();
} }
public Observable(T value) { public Observable(T value) {
super(); super();
this.value = value; this.value = value;
} }
public T getValue() { public T getValue() {
return value; return value;
} }
public void setValue(T value) { public void setValue(T value) {
if (!ObjectUtils.equals(this.value, value)) { if (!ObjectUtils.equals(this.value, value)) {
this.value = value; this.value = value;
notifyOfChange(value); notifyOfChange(value);
} }
} }
public void registerObserver(Observer<T> observer) { public void registerObserver(Observer<T> observer) {
listeners.put(observer, true); listeners.put(observer, true);
} }
public void unregisterObserver(Observer<T> observer) { public void unregisterObserver(Observer<T> observer) {
listeners.remove(observer); listeners.remove(observer);
} }
public void unregisterAllObservers() { public void unregisterAllObservers() {
listeners.clear(); listeners.clear();
} }
protected void notifyOfChange(T value) { protected void notifyOfChange(T value) {
for (Observer<T> listener : listeners.keySet()) { for (Observer<T> listener : listeners.keySet()) {
if (listener != null) { if (listener != null) {
listener.onUpdate(value); listener.onUpdate(value);
} }
} }
} }
} }

View File

@ -2,5 +2,5 @@ package com.dougkeen.util;
public interface Observer<T> { public interface Observer<T> {
void onUpdate(final T newValue); void onUpdate(final T newValue);
} }

View File

@ -6,23 +6,23 @@ import android.os.PowerManager;
import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.Constants;
public abstract class WakeLocker { public abstract class WakeLocker {
private static PowerManager.WakeLock wakeLock; private static PowerManager.WakeLock wakeLock;
public static void acquire(Context ctx) { public static void acquire(Context ctx) {
if (wakeLock != null) if (wakeLock != null)
wakeLock.release(); wakeLock.release();
PowerManager pm = (PowerManager) ctx PowerManager pm = (PowerManager) ctx
.getSystemService(Context.POWER_SERVICE); .getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.ON_AFTER_RELEASE, Constants.TAG); | PowerManager.ON_AFTER_RELEASE, Constants.TAG);
wakeLock.acquire(); wakeLock.acquire();
} }
public static void release() { public static void release() {
if (wakeLock != null) if (wakeLock != null)
wakeLock.release(); wakeLock.release();
wakeLock = null; wakeLock = null;
} }
} }

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" > android:shape="rectangle">
<size android:width="15dp" /> <size android:width="15dp" />

View File

@ -2,7 +2,7 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android" <merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bart="http://schemas.android.com/apk/res/com.dougkeen.bart" xmlns:bart="http://schemas.android.com/apk/res/com.dougkeen.bart"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" > android:layout_height="fill_parent">
<ImageView <ImageView
android:id="@+id/destinationColorBar" android:id="@+id/destinationColorBar"
@ -17,7 +17,7 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_toRightOf="@id/destinationColorBar" > android:layout_toRightOf="@id/destinationColorBar">
<TextView <TextView
android:id="@+id/destinationText" android:id="@+id/destinationText"

View File

@ -2,7 +2,7 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android" <merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bart="http://schemas.android.com/apk/res/com.dougkeen.bart" xmlns:bart="http://schemas.android.com/apk/res/com.dougkeen.bart"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" > android:layout_height="fill_parent">
<ImageView <ImageView
android:id="@+id/destinationColorBar" android:id="@+id/destinationColorBar"
@ -17,7 +17,7 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_toRightOf="@id/destinationColorBar" > android:layout_toRightOf="@id/destinationColorBar">
<TextView <TextView
android:id="@+id/destinationText" android:id="@+id/destinationText"

View File

@ -3,7 +3,7 @@
xmlns:bart="http://schemas.android.com/apk/res/com.dougkeen.bart" xmlns:bart="http://schemas.android.com/apk/res/com.dougkeen.bart"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical" > android:orientation="vertical">
<TextView <TextView
android:id="@+id/listTitle" android:id="@+id/listTitle"
@ -20,8 +20,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:padding="10dp" android:padding="10dp"
android:visibility="gone" > android:visibility="gone"></com.dougkeen.bart.controls.YourTrainLayout>
</com.dougkeen.bart.controls.YourTrainLayout>
<TextView <TextView
android:id="@android:id/empty" android:id="@android:id/empty"

View File

@ -4,7 +4,7 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:paddingLeft="5dp" android:paddingLeft="5dp"
android:paddingRight="5dp" > android:paddingRight="5dp">
<ImageView <ImageView
android:id="@+id/dragHandle" android:id="@+id/dragHandle"

View File

@ -4,7 +4,7 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:gravity="center" android:gravity="center"
android:orientation="vertical" > android:orientation="vertical">
<com.mobeta.android.dslv.DragSortListView <com.mobeta.android.dslv.DragSortListView
android:id="@android:id/list" android:id="@android:id/list"
@ -43,7 +43,7 @@
style="ButtonBar" style="ButtonBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" > android:layout_gravity="bottom">
<Button <Button
android:id="@+id/quickLookupButton" android:id="@+id/quickLookupButton"

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="56dp" android:layout_width="56dp"
android:layout_height="45dp" > android:layout_height="45dp">
<ProgressBar <ProgressBar
style="?android:attr/progressBarStyleSmallInverse" style="?android:attr/progressBarStyleSmallInverse"

View File

@ -3,7 +3,7 @@
xmlns:holo="http://schemas.android.com/apk/res-auto" xmlns:holo="http://schemas.android.com/apk/res-auto"
android:layout_width="300dp" android:layout_width="300dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" > android:gravity="center_vertical">
<View <View
android:id="@+id/titleDivider" android:id="@+id/titleDivider"
@ -36,8 +36,7 @@
android:paddingRight="5dp" android:paddingRight="5dp"
android:paddingTop="15dip" android:paddingTop="15dip"
android:text="@string/origin" android:text="@string/origin"
android:textSize="15sp" > android:textSize="15sp"></TextView>
</TextView>
<Spinner <Spinner
android:id="@+id/destination_spinner" android:id="@+id/destination_spinner"
@ -63,8 +62,7 @@
android:paddingRight="5dp" android:paddingRight="5dp"
android:paddingTop="15dip" android:paddingTop="15dip"
android:text="@string/destination" android:text="@string/destination"
android:textSize="15sp" > android:textSize="15sp"></TextView>
</TextView>
<CheckBox <CheckBox
android:id="@+id/return_checkbox" android:id="@+id/return_checkbox"

View File

@ -3,14 +3,13 @@
xmlns:holo="http://schemas.android.com/apk/res-auto" xmlns:holo="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="horizontal" > android:orientation="horizontal">
<NumberPicker <NumberPicker
android:id="@+id/numberPicker" android:id="@+id/numberPicker"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" > android:layout_weight="1"></NumberPicker>
</NumberPicker>
<TextView <TextView
android:id="@+id/textView1" android:id="@+id/textView1"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" <merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bart="http://schemas.android.com/apk/res/com.dougkeen.bart" > xmlns:bart="http://schemas.android.com/apk/res/com.dougkeen.bart">
<TextView <TextView
android:id="@+id/alarmText" android:id="@+id/alarmText"
@ -11,8 +11,7 @@
android:drawableLeft="@drawable/ic_action_alarm" android:drawableLeft="@drawable/ic_action_alarm"
android:gravity="center_vertical" android:gravity="center_vertical"
android:textSize="16dp" android:textSize="16dp"
android:visibility="gone" > android:visibility="gone"></TextView>
</TextView>
<TextView <TextView
android:id="@+id/yourTrainHeader" android:id="@+id/yourTrainHeader"

View File

@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:id="@+id/boardTrain" android:id="@+id/boardTrain"
android:icon="@drawable/ic_action_boarding" android:icon="@drawable/ic_action_boarding"
android:showAsAction="ifRoom|withText" android:showAsAction="ifRoom|withText"
android:title="@string/getting_on_this_train"> android:title="@string/getting_on_this_train"></item>
</item>
</menu> </menu>

View File

@ -1,17 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:id="@+id/view" android:id="@+id/view"
android:icon="@drawable/ic_action_departure" android:icon="@drawable/ic_action_departure"
android:showAsAction="ifRoom|withText" android:showAsAction="ifRoom|withText"
android:title="@string/view_departures"> android:title="@string/view_departures"></item>
</item>
<item <item
android:id="@+id/delete" android:id="@+id/delete"
android:icon="@drawable/ic_action_delete" android:icon="@drawable/ic_action_delete"
android:showAsAction="ifRoom|withText" android:showAsAction="ifRoom|withText"
android:title="@string/delete"> android:title="@string/delete"></item>
</item>
</menu> </menu>

View File

@ -1,17 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:id="@+id/view_on_bart_site_button" android:id="@+id/view_on_bart_site_button"
android:icon="@drawable/ic_action_web" android:icon="@drawable/ic_action_web"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/view_on_bart_site"> android:title="@string/view_on_bart_site"></item>
</item>
<item <item
android:id="@+id/view_system_map_button" android:id="@+id/view_system_map_button"
android:icon="@drawable/ic_action_map" android:icon="@drawable/ic_action_map"
android:showAsAction="ifRoom|withText" android:showAsAction="ifRoom|withText"
android:title="@string/view_system_map"> android:title="@string/view_system_map"></item>
</item>
</menu> </menu>

View File

@ -1,23 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:id="@+id/add_favorite_menu_button" android:id="@+id/add_favorite_menu_button"
android:icon="@drawable/ic_action_new" android:icon="@drawable/ic_action_new"
android:showAsAction="ifRoom|withText" android:showAsAction="ifRoom|withText"
android:title="@string/add_route"> android:title="@string/add_route"></item>
</item>
<item <item
android:id="@+id/view_system_map_button" android:id="@+id/view_system_map_button"
android:icon="@drawable/ic_action_map" android:icon="@drawable/ic_action_map"
android:showAsAction="ifRoom|withText" android:showAsAction="ifRoom|withText"
android:title="@string/view_system_map"> android:title="@string/view_system_map"></item>
</item>
<item <item
android:id="@+id/elevator_button" android:id="@+id/elevator_button"
android:icon="@drawable/ic_action_elevator" android:icon="@drawable/ic_action_elevator"
android:showAsAction="ifRoom|withText" android:showAsAction="ifRoom|withText"
android:title="Check elevator status"> android:title="Check elevator status"></item>
</item>
</menu> </menu>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android">
</menu> </menu>

View File

@ -1,27 +1,26 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:id="@+id/cancel_alarm_button" android:id="@+id/cancel_alarm_button"
android:icon="@drawable/ic_action_cancel_alarm" android:icon="@drawable/ic_action_cancel_alarm"
android:showAsAction="always|withText" android:showAsAction="always|withText"
android:title="@string/cancel_alarm" android:title="@string/cancel_alarm"
android:visible="false"/> android:visible="false" />
<item <item
android:id="@+id/set_alarm_button" android:id="@+id/set_alarm_button"
android:icon="@drawable/ic_action_alarm" android:icon="@drawable/ic_action_alarm"
android:showAsAction="always|withText" android:showAsAction="always|withText"
android:title="@string/set_alarm"/> android:title="@string/set_alarm" />
<item <item
android:id="@+id/share_arrival" android:id="@+id/share_arrival"
android:icon="@drawable/ic_action_mail" android:icon="@drawable/ic_action_mail"
android:showAsAction="always|withText" android:showAsAction="always|withText"
android:title="@string/share_arrival_time" /> android:title="@string/share_arrival_time" />
<item <item
android:id="@+id/delete" android:id="@+id/delete"
android:icon="@drawable/ic_action_delete" android:icon="@drawable/ic_action_delete"
android:showAsAction="always|withText" android:showAsAction="always|withText"
android:title="@string/delete"> android:title="@string/delete"></item>
</item>
</menu> </menu>

View File

@ -3,8 +3,7 @@
<!-- Base application theme is the default theme. --> <!-- Base application theme is the default theme. -->
<style name="AppTheme" parent="@style/Holo.Theme"> <style name="AppTheme" parent="@style/Holo.Theme"></style>
</style>
<style name="ButtonBar"> <style name="ButtonBar">
<item name="android:layout_width">fill_parent</item> <item name="android:layout_width">fill_parent</item>