Changed "departed" to "leaving". Abstracted out string value.

This commit is contained in:
Doug Keen 2012-10-09 13:51:00 -07:00
parent f5ba6d27cc
commit 8955bd209b
30 changed files with 3166 additions and 3151 deletions

View File

@ -42,5 +42,6 @@
<string name="silence_alarm">Silence alarm</string> <string name="silence_alarm">Silence alarm</string>
<string name="cancel_alarm">Cancel alarm</string> <string name="cancel_alarm">Cancel alarm</string>
<string name="set_alarm">Set alarm</string> <string name="set_alarm">Set alarm</string>
<string name="leaving">Leaving</string>
</resources> </resources>

View File

@ -31,6 +31,18 @@ public class BartRunnerApplication extends Application {
private MediaPlayer mAlarmMediaPlayer; private MediaPlayer mAlarmMediaPlayer;
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getAppContext() {
return context;
}
public boolean shouldPlayAlarmRingtone() { public boolean shouldPlayAlarmRingtone() {
return mPlayAlarmRingtone; return mPlayAlarmRingtone;
} }

View File

@ -18,11 +18,10 @@ import android.widget.AdapterView;
import android.widget.Button; import android.widget.Button;
import android.widget.ListAdapter; import android.widget.ListAdapter;
import com.WazaBe.HoloEverywhere.widget.TextView;
import com.WazaBe.HoloEverywhere.app.AlertDialog; import com.WazaBe.HoloEverywhere.app.AlertDialog;
import com.WazaBe.HoloEverywhere.app.DialogFragment; import com.WazaBe.HoloEverywhere.app.DialogFragment;
import com.WazaBe.HoloEverywhere.sherlock.SActivity; import com.WazaBe.HoloEverywhere.sherlock.SActivity;
import com.WazaBe.HoloEverywhere.widget.TextView;
import com.actionbarsherlock.view.ActionMode; import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuInflater;

View File

@ -1,57 +1,57 @@
package com.dougkeen.bart.controls; package com.dougkeen.bart.controls;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.TextView; 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

@ -86,8 +86,8 @@ public class SwipeHelper implements View.OnTouchListener {
private float mTranslationX; private float mTranslationX;
/** /**
* The callback interface used by {@link SwipeHelper} to inform its * The callback interface used by {@link SwipeHelper} to inform its client
* 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 {
/** /**

View File

@ -1,114 +1,114 @@
package com.dougkeen.bart.controls; package com.dougkeen.bart.controls;
import java.util.Iterator; import java.util.Iterator;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
public class Ticker { public class Ticker {
public static interface TickSubscriber { public static 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

@ -1,67 +1,67 @@
package com.dougkeen.bart.controls; package com.dougkeen.bart.controls;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.TextSwitcher; 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

@ -95,7 +95,7 @@ public class YourTrainLayout extends RelativeLayout implements Checkable {
@Override @Override
public String getText(long tickNumber) { public String getText(long tickNumber) {
if (boardedDeparture.hasDeparted()) { if (boardedDeparture.hasDeparted()) {
return "Departed"; return getContext().getString(R.string.leaving);
} else { } else {
return "Leaves in " + boardedDeparture.getCountdownText() return "Leaves in " + boardedDeparture.getCountdownText()
+ " " + boardedDeparture.getUncertaintyText(); + " " + boardedDeparture.getUncertaintyText();

View File

@ -1,271 +1,271 @@
package com.dougkeen.bart.data; package com.dougkeen.bart.data;
import java.util.HashMap; import java.util.HashMap;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.UriMatcher; import android.content.UriMatcher;
import android.database.Cursor; import android.database.Cursor;
import android.database.MatrixCursor; import android.database.MatrixCursor;
import android.database.MatrixCursor.RowBuilder; import android.database.MatrixCursor.RowBuilder;
import android.database.SQLException; import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder; import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.Constants;
public class BartContentProvider extends ContentProvider { public class BartContentProvider extends ContentProvider {
private static final UriMatcher sUriMatcher; private static final UriMatcher sUriMatcher;
private static HashMap<String, String> sFavoritesProjectionMap; private static HashMap<String, String> sFavoritesProjectionMap;
private static final int FAVORITES = 1; private static final int FAVORITES = 1;
private static final int FAVORITE_ID = 2; private static final int FAVORITE_ID = 2;
private static final int ARBITRARY_ROUTE = 3; private static final int ARBITRARY_ROUTE = 3;
private static final int ARBITRARY_ROUTE_UNDEFINED = 4; private static final int ARBITRARY_ROUTE_UNDEFINED = 4;
/** /**
* The default sort order for events * The default sort order for events
*/ */
private static final String DEFAULT_SORT_ORDER = RoutesColumns.FROM_STATION.string private static final String DEFAULT_SORT_ORDER = RoutesColumns.FROM_STATION.string
+ " DESC"; + " DESC";
static { static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(Constants.AUTHORITY, "favorites", FAVORITES); sUriMatcher.addURI(Constants.AUTHORITY, "favorites", FAVORITES);
sUriMatcher.addURI(Constants.AUTHORITY, "favorites/#", FAVORITE_ID); sUriMatcher.addURI(Constants.AUTHORITY, "favorites/#", FAVORITE_ID);
sUriMatcher.addURI(Constants.AUTHORITY, "route/*/*", ARBITRARY_ROUTE); sUriMatcher.addURI(Constants.AUTHORITY, "route/*/*", ARBITRARY_ROUTE);
sUriMatcher.addURI(Constants.AUTHORITY, "route", sUriMatcher.addURI(Constants.AUTHORITY, "route",
ARBITRARY_ROUTE_UNDEFINED); ARBITRARY_ROUTE_UNDEFINED);
sFavoritesProjectionMap = new HashMap<String, String>(); sFavoritesProjectionMap = new HashMap<String, String>();
sFavoritesProjectionMap.put(RoutesColumns._ID.string, sFavoritesProjectionMap.put(RoutesColumns._ID.string,
RoutesColumns._ID.string); RoutesColumns._ID.string);
sFavoritesProjectionMap.put(RoutesColumns.FROM_STATION.string, sFavoritesProjectionMap.put(RoutesColumns.FROM_STATION.string,
RoutesColumns.FROM_STATION.string); RoutesColumns.FROM_STATION.string);
sFavoritesProjectionMap.put(RoutesColumns.TO_STATION.string, sFavoritesProjectionMap.put(RoutesColumns.TO_STATION.string,
RoutesColumns.TO_STATION.string); RoutesColumns.TO_STATION.string);
sFavoritesProjectionMap.put(RoutesColumns.FARE.string, sFavoritesProjectionMap.put(RoutesColumns.FARE.string,
RoutesColumns.FARE.string); RoutesColumns.FARE.string);
sFavoritesProjectionMap.put(RoutesColumns.FARE_LAST_UPDATED.string, sFavoritesProjectionMap.put(RoutesColumns.FARE_LAST_UPDATED.string,
RoutesColumns.FARE_LAST_UPDATED.string); RoutesColumns.FARE_LAST_UPDATED.string);
sFavoritesProjectionMap.put( sFavoritesProjectionMap.put(
RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.string, RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.string,
RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.string); RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.string);
sFavoritesProjectionMap.put(RoutesColumns.AVERAGE_TRIP_LENGTH.string, sFavoritesProjectionMap.put(RoutesColumns.AVERAGE_TRIP_LENGTH.string,
RoutesColumns.AVERAGE_TRIP_LENGTH.string); RoutesColumns.AVERAGE_TRIP_LENGTH.string);
} }
private DatabaseHelper mDatabaseHelper; private DatabaseHelper mDatabaseHelper;
@Override @Override
public boolean onCreate() { public boolean onCreate() {
mDatabaseHelper = new DatabaseHelper(getContext()); mDatabaseHelper = new DatabaseHelper(getContext());
return true; return true;
} }
@Override @Override
public String getType(Uri uri) { public String getType(Uri uri) {
int match = sUriMatcher.match(uri); int match = sUriMatcher.match(uri);
if (match == FAVORITES) { if (match == FAVORITES) {
return Constants.FAVORITE_CONTENT_TYPE; return Constants.FAVORITE_CONTENT_TYPE;
} else if (match == FAVORITE_ID) { } else if (match == FAVORITE_ID) {
return Constants.FAVORITE_CONTENT_ITEM_TYPE; return Constants.FAVORITE_CONTENT_ITEM_TYPE;
} else if (match == ARBITRARY_ROUTE) { } else if (match == ARBITRARY_ROUTE) {
return Constants.ARBITRARY_ROUTE_TYPE; return Constants.ARBITRARY_ROUTE_TYPE;
} else if (match == ARBITRARY_ROUTE_UNDEFINED) { } else if (match == ARBITRARY_ROUTE_UNDEFINED) {
return Constants.ARBITRARY_ROUTE_UNDEFINED_TYPE; return Constants.ARBITRARY_ROUTE_UNDEFINED_TYPE;
} else { } else {
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
} }
@Override @Override
public Cursor query(Uri uri, String[] projection, String selection, public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) { String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
SQLiteDatabase db = mDatabaseHelper.getReadableDatabase(); SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
String orderBy = sortOrder; String orderBy = sortOrder;
int match = sUriMatcher.match(uri); int match = sUriMatcher.match(uri);
if (match == ARBITRARY_ROUTE) { if (match == ARBITRARY_ROUTE) {
final String origin = uri.getPathSegments().get(1); final String origin = uri.getPathSegments().get(1);
final String destination = uri.getPathSegments().get(2); final String destination = uri.getPathSegments().get(2);
qb.setTables(DatabaseHelper.FAVORITES_TABLE_NAME); qb.setTables(DatabaseHelper.FAVORITES_TABLE_NAME);
qb.setProjectionMap(sFavoritesProjectionMap); qb.setProjectionMap(sFavoritesProjectionMap);
qb.appendWhere(String.format("%s = '%s' AND %s = '%s'", qb.appendWhere(String.format("%s = '%s' AND %s = '%s'",
RoutesColumns.FROM_STATION, origin, RoutesColumns.FROM_STATION, origin,
RoutesColumns.TO_STATION, destination)); RoutesColumns.TO_STATION, destination));
Cursor query = qb.query(db, projection, selection, selectionArgs, Cursor query = qb.query(db, projection, selection, selectionArgs,
null, null, sortOrder); null, null, sortOrder);
if (query.getCount() > 0) if (query.getCount() > 0)
return query; return query;
MatrixCursor returnCursor = new MatrixCursor(projection); MatrixCursor returnCursor = new MatrixCursor(projection);
RowBuilder newRow = returnCursor.newRow(); RowBuilder newRow = returnCursor.newRow();
for (String column : projection) { for (String column : projection) {
if (column.equals(RoutesColumns.FROM_STATION.string)) { if (column.equals(RoutesColumns.FROM_STATION.string)) {
newRow.add(origin); newRow.add(origin);
} else if (column.equals(RoutesColumns.TO_STATION.string)) { } else if (column.equals(RoutesColumns.TO_STATION.string)) {
newRow.add(destination); newRow.add(destination);
} else { } else {
newRow.add(null); newRow.add(null);
} }
} }
return returnCursor; return returnCursor;
} else if (match == FAVORITE_ID) { } else if (match == FAVORITE_ID) {
qb.setTables(DatabaseHelper.FAVORITES_TABLE_NAME); qb.setTables(DatabaseHelper.FAVORITES_TABLE_NAME);
qb.setProjectionMap(sFavoritesProjectionMap); qb.setProjectionMap(sFavoritesProjectionMap);
qb.appendWhere(RoutesColumns._ID + " = " qb.appendWhere(RoutesColumns._ID + " = "
+ uri.getPathSegments().get(1)); + uri.getPathSegments().get(1));
} else if (match == FAVORITES) { } else if (match == FAVORITES) {
qb.setTables(DatabaseHelper.FAVORITES_TABLE_NAME); qb.setTables(DatabaseHelper.FAVORITES_TABLE_NAME);
qb.setProjectionMap(sFavoritesProjectionMap); qb.setProjectionMap(sFavoritesProjectionMap);
} else { } else {
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
// If no sort order is specified use the default // If no sort order is specified use the default
if (TextUtils.isEmpty(orderBy)) { if (TextUtils.isEmpty(orderBy)) {
orderBy = DEFAULT_SORT_ORDER; orderBy = DEFAULT_SORT_ORDER;
} }
// Get the database and run the query // Get the database and run the query
Cursor cursor = qb.query(db, projection, selection, selectionArgs, Cursor cursor = qb.query(db, projection, selection, selectionArgs,
null, null, orderBy); null, null, orderBy);
// Tell the cursor what uri to watch, so it knows when its source data // Tell the cursor what uri to watch, so it knows when its source data
// changes // changes
cursor.setNotificationUri(getContext().getContentResolver(), uri); cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor; return cursor;
} }
@Override @Override
public Uri insert(Uri uri, ContentValues initialValues) { public Uri insert(Uri uri, ContentValues initialValues) {
ContentValues values; ContentValues values;
if (initialValues != null) { if (initialValues != null) {
values = new ContentValues(initialValues); values = new ContentValues(initialValues);
} else { } else {
values = new ContentValues(); values = new ContentValues();
} }
SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
// Validate the requested uri // Validate the requested uri
int match = sUriMatcher.match(uri); int match = sUriMatcher.match(uri);
if (match == FAVORITES) { if (match == FAVORITES) {
long rowId = -1; long rowId = -1;
Cursor cursor = db Cursor cursor = db
.query(DatabaseHelper.FAVORITES_TABLE_NAME, .query(DatabaseHelper.FAVORITES_TABLE_NAME,
new String[] { RoutesColumns._ID.string }, new String[] { RoutesColumns._ID.string },
RoutesColumns.FROM_STATION + "=? AND " RoutesColumns.FROM_STATION + "=? AND "
+ RoutesColumns.TO_STATION + "=?", + RoutesColumns.TO_STATION + "=?",
new String[] { new String[] {
values.getAsString(RoutesColumns.FROM_STATION.string), values.getAsString(RoutesColumns.FROM_STATION.string),
values.getAsString(RoutesColumns.TO_STATION.string) }, values.getAsString(RoutesColumns.TO_STATION.string) },
null, null, null); null, null, null);
try { try {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
rowId = cursor.getLong(0); rowId = cursor.getLong(0);
} }
} finally { } finally {
CursorUtils.closeCursorQuietly(cursor); CursorUtils.closeCursorQuietly(cursor);
} }
if (rowId < 0) { if (rowId < 0) {
rowId = db.insert(DatabaseHelper.FAVORITES_TABLE_NAME, rowId = db.insert(DatabaseHelper.FAVORITES_TABLE_NAME,
RoutesColumns.FROM_STATION.string, values); RoutesColumns.FROM_STATION.string, values);
} }
if (rowId > 0) { if (rowId > 0) {
Uri eventUri = ContentUris.withAppendedId( Uri eventUri = ContentUris.withAppendedId(
Constants.FAVORITE_CONTENT_URI, rowId); Constants.FAVORITE_CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(eventUri, null, getContext().getContentResolver().notifyChange(eventUri, null,
false); false);
return eventUri; return eventUri;
} }
} else { } else {
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
throw new SQLException("Failed to insert row into " + uri); throw new SQLException("Failed to insert row into " + uri);
} }
@Override @Override
public int update(Uri uri, ContentValues values, String where, public int update(Uri uri, ContentValues values, String where,
String[] whereArgs) { String[] whereArgs) {
SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
// Validate the requested uri // Validate the requested uri
int match = sUriMatcher.match(uri); int match = sUriMatcher.match(uri);
if (match == FAVORITE_ID) { if (match == FAVORITE_ID) {
String favoriteId = uri.getPathSegments().get(1); String favoriteId = uri.getPathSegments().get(1);
int count = db.update( int count = db.update(
DatabaseHelper.FAVORITES_TABLE_NAME, DatabaseHelper.FAVORITES_TABLE_NAME,
values, values,
RoutesColumns._ID RoutesColumns._ID
+ " = " + " = "
+ favoriteId + favoriteId
+ (!TextUtils.isEmpty(where) ? " AND (" + where + (!TextUtils.isEmpty(where) ? " AND (" + where
+ ')' : ""), whereArgs); + ')' : ""), whereArgs);
getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, null);
return count; return count;
} else if (match == ARBITRARY_ROUTE) { } else if (match == ARBITRARY_ROUTE) {
// Get the route with the origin and destination provided, and // Get the route with the origin and destination provided, and
// simply delegate to the previous log branch. If the given route // simply delegate to the previous log branch. If the given route
// doesn't exist, do nothing. // doesn't exist, do nothing.
String origin = uri.getPathSegments().get(1); String origin = uri.getPathSegments().get(1);
String destination = uri.getPathSegments().get(2); String destination = uri.getPathSegments().get(2);
Cursor query = db.query(DatabaseHelper.FAVORITES_TABLE_NAME, Cursor query = db.query(DatabaseHelper.FAVORITES_TABLE_NAME,
new String[] { RoutesColumns._ID.string }, new String[] { RoutesColumns._ID.string },
RoutesColumns.FROM_STATION.string + "=? AND " RoutesColumns.FROM_STATION.string + "=? AND "
+ RoutesColumns.TO_STATION.string + "=?", + RoutesColumns.TO_STATION.string + "=?",
new String[] { origin, destination }, null, null, null); new String[] { origin, destination }, null, null, null);
try { try {
if (query.moveToFirst()) { if (query.moveToFirst()) {
return update(ContentUris.withAppendedId( return update(ContentUris.withAppendedId(
Constants.FAVORITE_CONTENT_URI, query.getLong(0)), Constants.FAVORITE_CONTENT_URI, query.getLong(0)),
values, where, whereArgs); values, where, whereArgs);
} }
} finally { } finally {
CursorUtils.closeCursorQuietly(query); CursorUtils.closeCursorQuietly(query);
} }
} }
return 0; return 0;
} }
@Override @Override
public int delete(Uri uri, String where, String[] whereArgs) { public int delete(Uri uri, String where, String[] whereArgs) {
// TODO: Sync with REST service? // TODO: Sync with REST service?
SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
int count; int count;
int match = sUriMatcher.match(uri); int match = sUriMatcher.match(uri);
if (match == FAVORITES) { if (match == FAVORITES) {
count = db.delete(DatabaseHelper.FAVORITES_TABLE_NAME, where, count = db.delete(DatabaseHelper.FAVORITES_TABLE_NAME, where,
whereArgs); whereArgs);
} else if (match == FAVORITE_ID) { } else if (match == FAVORITE_ID) {
String favoriteId = uri.getPathSegments().get(1); String favoriteId = uri.getPathSegments().get(1);
count = db.delete( count = db.delete(
DatabaseHelper.FAVORITES_TABLE_NAME, DatabaseHelper.FAVORITES_TABLE_NAME,
RoutesColumns._ID RoutesColumns._ID
+ " = " + " = "
+ favoriteId + favoriteId
+ (!TextUtils.isEmpty(where) ? " AND (" + where + (!TextUtils.isEmpty(where) ? " AND (" + where
+ ')' : ""), whereArgs); + ')' : ""), whereArgs);
} else { } else {
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, null);
return count; return count;
} }
} }

View File

@ -1,23 +1,23 @@
package com.dougkeen.bart.data; 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));
} }
} }

View File

@ -1,98 +1,98 @@
package com.dougkeen.bart.data; package com.dougkeen.bart.data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log; import android.util.Log;
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 = 4; private static final int DATABASE_VERSION = 4;
public static final String FAVORITES_TABLE_NAME = "Favorites"; public static final String FAVORITES_TABLE_NAME = "Favorites";
public DatabaseHelper(Context context) { public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); super(context, DATABASE_NAME, null, DATABASE_VERSION);
} }
@Override @Override
public void onCreate(SQLiteDatabase db) { public void onCreate(SQLiteDatabase db) {
createFavoritesTable(db); createFavoritesTable(db);
} }
private void createFavoritesTable(SQLiteDatabase db) { private void createFavoritesTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + FAVORITES_TABLE_NAME + " (" db.execSQL("CREATE TABLE IF NOT EXISTS " + FAVORITES_TABLE_NAME + " ("
+ RoutesColumns._ID.getColumnDef() + " PRIMARY KEY, " + RoutesColumns._ID.getColumnDef() + " PRIMARY KEY, "
+ RoutesColumns.FROM_STATION.getColumnDef() + ", " + RoutesColumns.FROM_STATION.getColumnDef() + ", "
+ RoutesColumns.TO_STATION.getColumnDef() + ", " + RoutesColumns.TO_STATION.getColumnDef() + ", "
+ RoutesColumns.FARE.getColumnDef() + ", " + RoutesColumns.FARE.getColumnDef() + ", "
+ RoutesColumns.FARE_LAST_UPDATED.getColumnDef() + ", " + RoutesColumns.FARE_LAST_UPDATED.getColumnDef() + ", "
+ RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.getColumnDef() + ", " + RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.getColumnDef() + ", "
+ RoutesColumns.AVERAGE_TRIP_LENGTH.getColumnDef() + ");"); + RoutesColumns.AVERAGE_TRIP_LENGTH.getColumnDef() + ");");
} }
@Override @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.beginTransaction(); db.beginTransaction();
try { try {
createFavoritesTable(db); createFavoritesTable(db);
List<String> columns = getColumns(db, FAVORITES_TABLE_NAME); List<String> columns = getColumns(db, FAVORITES_TABLE_NAME);
db.execSQL("ALTER TABLE " + FAVORITES_TABLE_NAME db.execSQL("ALTER TABLE " + FAVORITES_TABLE_NAME
+ " RENAME TO temp_" + FAVORITES_TABLE_NAME); + " RENAME TO temp_" + FAVORITES_TABLE_NAME);
createFavoritesTable(db); createFavoritesTable(db);
columns.retainAll(getColumns(db, FAVORITES_TABLE_NAME)); columns.retainAll(getColumns(db, FAVORITES_TABLE_NAME));
String cols = StringUtils.join(columns, ","); String cols = StringUtils.join(columns, ",");
db.execSQL(String.format( db.execSQL(String.format(
"INSERT INTO %s (%s) SELECT %s from temp_%s", "INSERT INTO %s (%s) SELECT %s from temp_%s",
FAVORITES_TABLE_NAME, cols, cols, FAVORITES_TABLE_NAME)); FAVORITES_TABLE_NAME, cols, cols, FAVORITES_TABLE_NAME));
db.execSQL("DROP TABLE temp_" + FAVORITES_TABLE_NAME); db.execSQL("DROP TABLE temp_" + FAVORITES_TABLE_NAME);
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} finally { } finally {
db.endTransaction(); db.endTransaction();
} }
} }
public static List<String> getColumns(SQLiteDatabase db, String tableName) { public static List<String> getColumns(SQLiteDatabase db, String tableName) {
List<String> ar = null; List<String> ar = null;
Cursor c = null; Cursor c = null;
try { try {
c = db.rawQuery("select * from " + tableName + " limit 1", null); c = db.rawQuery("select * from " + tableName + " limit 1", null);
if (c != null) { if (c != null) {
ar = new ArrayList<String>(Arrays.asList(c.getColumnNames())); ar = new ArrayList<String>(Arrays.asList(c.getColumnNames()));
} }
} catch (Exception e) { } catch (Exception e) {
Log.v(tableName, e.getMessage(), e); Log.v(tableName, e.getMessage(), e);
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (c != null) if (c != null)
c.close(); c.close();
} }
return ar; return ar;
} }
public static String join(List<String> list, String delim) { public static String join(List<String> list, String delim) {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
int num = list.size(); int num = list.size();
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
if (i != 0) if (i != 0)
buf.append(delim); buf.append(delim);
buf.append((String) list.get(i)); buf.append((String) list.get(i));
} }
return buf.toString(); return buf.toString();
} }
} }

View File

@ -1,28 +1,26 @@
package com.dougkeen.bart.data; package com.dougkeen.bart.data;
public enum RoutesColumns {
public enum RoutesColumns { _ID("_id", "INTEGER", false),
_ID("_id", "INTEGER", false), FROM_STATION("FROM_STATION", "TEXT", false),
FROM_STATION("FROM_STATION", "TEXT", false), TO_STATION("TO_STATION", "TEXT", false),
TO_STATION("TO_STATION", "TEXT", false), FARE("FARE", "TEXT", true),
FARE("FARE", "TEXT", true), FARE_LAST_UPDATED("FARE_LAST_UPDATED", "INTEGER", true),
FARE_LAST_UPDATED("FARE_LAST_UPDATED", "INTEGER", true), AVERAGE_TRIP_SAMPLE_COUNT("AVE_TRIP_SAMPLE_COUNT", "INTEGER", true),
AVERAGE_TRIP_SAMPLE_COUNT("AVE_TRIP_SAMPLE_COUNT", "INTEGER", true), AVERAGE_TRIP_LENGTH("AVE_TRIP_LENGTH", "INTEGER", true);
AVERAGE_TRIP_LENGTH("AVE_TRIP_LENGTH", "INTEGER", true);
// This class cannot be instantiated
private RoutesColumns(String string, String type, Boolean nullable) {
// This class cannot be instantiated this.string = string;
private RoutesColumns(String string, String type, Boolean nullable) { this.sqliteType = type;
this.string = string; this.nullable = nullable;
this.sqliteType = type; }
this.nullable = nullable;
} public final String string;
public final String sqliteType;
public final String string; public final Boolean nullable;
public final String sqliteType;
public final Boolean nullable; protected String getColumnDef() {
return string + " " + sqliteType + (nullable ? "" : " NOT NULL");
protected String getColumnDef() { }
return string + " " + sqliteType + (nullable?"":" NOT NULL"); }
}
}

View File

@ -1,20 +1,20 @@
package com.dougkeen.bart.model; 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";
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,113 +1,115 @@
package com.dougkeen.bart.model; package com.dougkeen.bart.model;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set; 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) { private 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, private 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, private 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, Station station2) { public static Collection<Line> getLinesWithStations(Station station1,
Collection<Line> lines = new ArrayList<Line>(); Station station2) {
for (Line line : Line.values()) { Collection<Line> lines = new ArrayList<Line>();
if (line.stations.contains(station1) && line.stations.contains(station2)) { for (Line line : Line.values()) {
lines.add(line); if (line.stations.contains(station1)
} && line.stations.contains(station2)) {
} lines.add(line);
return lines; }
} }
return lines;
public static Set<Station> getPotentialDestinations(Station station) { }
Set<Station> destinations = new TreeSet<Station>();
public static Set<Station> getPotentialDestinations(Station station) {
for (Line line : getLinesForStation(station)) { Set<Station> destinations = new TreeSet<Station>();
destinations.addAll(line.stations);
} for (Line line : getLinesForStation(station)) {
destinations.addAll(line.stations);
destinations.remove(station); }
return destinations; destinations.remove(station);
}
} return destinations;
}
}

View File

@ -1,152 +1,152 @@
package com.dougkeen.bart.model; package com.dougkeen.bart.model;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; 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

@ -1,111 +1,111 @@
package com.dougkeen.bart.model; 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

@ -1,89 +1,89 @@
package com.dougkeen.bart.model; package com.dougkeen.bart.model;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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

@ -1,115 +1,115 @@
package com.dougkeen.bart.model; package com.dougkeen.bart.model;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; 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

@ -1,287 +1,286 @@
package com.dougkeen.bart.model; package com.dougkeen.bart.model;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; 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", DBRK("dbrk", "Downtown Berkeley", "Dtwn Berk", false, false, "mcar", "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,
private 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,
private 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,
private 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,
private 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

@ -1,151 +1,151 @@
package com.dougkeen.bart.model; package com.dougkeen.bart.model;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.dougkeen.bart.data.CursorUtils; import com.dougkeen.bart.data.CursorUtils;
import com.dougkeen.bart.data.RoutesColumns; import com.dougkeen.bart.data.RoutesColumns;
public class StationPair implements Parcelable { public class StationPair implements Parcelable {
public StationPair(Station origin, Station destination) { public StationPair(Station origin, Station destination) {
super(); super();
this.origin = origin; this.origin = origin;
this.destination = destination; this.destination = destination;
} }
public StationPair(Long id, Station origin, Station destination) { public StationPair(Long id, Station origin, Station destination) {
super(); super();
this.origin = origin; this.origin = origin;
this.destination = destination; this.destination = destination;
this.id = id; this.id = id;
} }
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.id = CursorUtils.getLong(cursor, RoutesColumns._ID); pair.id = CursorUtils.getLong(cursor, RoutesColumns._ID);
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);
return pair; return pair;
} }
private Long id; private Long id;
private Station origin; private Station origin;
private Station destination; private Station destination;
private String fare; private String fare;
private Long fareLastUpdated; private Long fareLastUpdated;
public Long getId() { public Long getId() {
return id; return id;
} }
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 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));
} }
public Uri getUri() { public Uri getUri() {
if (getOrigin() != null && getDestination() != null) { if (getOrigin() != null && getDestination() != null) {
return Constants.ARBITRARY_ROUTE_CONTENT_URI_ROOT.buildUpon() return Constants.ARBITRARY_ROUTE_CONTENT_URI_ROOT.buildUpon()
.appendPath(getOrigin().abbreviation) .appendPath(getOrigin().abbreviation)
.appendPath(getDestination().abbreviation).build(); .appendPath(getDestination().abbreviation).build();
} else { } else {
return null; return null;
} }
} }
@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) if (origin != other.origin)
return false; return false;
return true; return true;
} }
@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

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

View File

@ -1,122 +1,122 @@
package com.dougkeen.bart.networktasks; package com.dougkeen.bart.networktasks;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import android.util.Log; import android.util.Log;
import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.Constants;
import com.dougkeen.bart.model.Departure; import com.dougkeen.bart.model.Departure;
import com.dougkeen.bart.model.Line; import com.dougkeen.bart.model.Line;
import com.dougkeen.bart.model.RealTimeDepartures; import com.dougkeen.bart.model.RealTimeDepartures;
import com.dougkeen.bart.model.Route; 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

@ -1,46 +1,46 @@
package com.dougkeen.bart.networktasks; package com.dougkeen.bart.networktasks;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; 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

@ -1,153 +1,153 @@
package com.dougkeen.bart.networktasks; package com.dougkeen.bart.networktasks;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.List; import java.util.List;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import android.util.Xml; import android.util.Xml;
import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.Constants;
import com.dougkeen.bart.model.RealTimeDepartures; import com.dougkeen.bart.model.RealTimeDepartures;
import com.dougkeen.bart.model.Route; 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

@ -1,125 +1,125 @@
package com.dougkeen.bart.networktasks; package com.dougkeen.bart.networktasks;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import android.util.Xml; import android.util.Xml;
import com.dougkeen.bart.model.Constants; 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

@ -1,118 +1,118 @@
package com.dougkeen.bart.networktasks; package com.dougkeen.bart.networktasks;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import android.util.Xml; import android.util.Xml;
import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.Constants;
import com.dougkeen.bart.model.ScheduleInformation; 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

@ -1,38 +1,40 @@
package com.dougkeen.bart.networktasks; package com.dougkeen.bart.networktasks;
import java.io.IOException; import java.io.IOException;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.params.ConnManagerParams; import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams; 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, NetworkUtils.CONNECTION_TIMEOUT_MILLIS); HttpConnectionParams.setSoTimeout(params,
ConnManagerParams.setTimeout(params, NetworkUtils.CONNECTION_TIMEOUT_MILLIS); NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
return client; ConnManagerParams.setTimeout(params,
} NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
return client;
public static HttpResponse executeWithRecovery(final HttpUriRequest request) }
throws IOException, ClientProtocolException {
try { public static HttpResponse executeWithRecovery(final HttpUriRequest request)
return getHttpClient().execute(request); throws IOException, ClientProtocolException {
} catch (IllegalStateException e) { try {
// try again... this is a rare error return getHttpClient().execute(request);
return getHttpClient().execute(request); } catch (IllegalStateException e) {
} // try again... this is a rare error
} return getHttpClient().execute(request);
}
static final int CONNECTION_TIMEOUT_MILLIS = 10000; }
} static final int CONNECTION_TIMEOUT_MILLIS = 10000;
}

View File

@ -1,167 +1,167 @@
package com.dougkeen.bart.networktasks; package com.dougkeen.bart.networktasks;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import android.util.Log; import android.util.Log;
import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.Constants;
import com.dougkeen.bart.model.ScheduleInformation; import com.dougkeen.bart.model.ScheduleInformation;
import com.dougkeen.bart.model.ScheduleItem; 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

@ -24,7 +24,8 @@ public class AlarmBroadcastReceiver extends BroadcastReceiver {
application.setPlayAlarmRingtone(true); application.setPlayAlarmRingtone(true);
Intent targetIntent = new Intent(Intent.ACTION_VIEW, boardedDeparture.getStationPair().getUri()); Intent targetIntent = new Intent(Intent.ACTION_VIEW, boardedDeparture
.getStationPair().getUri());
targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(targetIntent); context.startActivity(targetIntent);