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="cancel_alarm">Cancel alarm</string>
<string name="set_alarm">Set alarm</string>
<string name="leaving">Leaving</string>
</resources>

View File

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

View File

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

View File

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

View File

@ -86,8 +86,8 @@ public class SwipeHelper implements View.OnTouchListener {
private float mTranslationX;
/**
* The callback interface used by {@link SwipeHelper} to inform its
* client about a successful dismissal of the view for which it was created.
* The callback interface used by {@link SwipeHelper} to inform its client
* about a successful dismissal of the view for which it was created.
*/
public interface OnDismissCallback {
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,20 +1,20 @@
package com.dougkeen.bart.model;
import android.net.Uri;
public class Constants {
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 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 FAVORITE_CONTENT_ITEM_TYPE = "vnd.android.cursor.item/com.dougkeen.bart.favorite";
public static final Uri FAVORITE_CONTENT_URI = Uri.parse("content://"
+ AUTHORITY + "/favorites");
public static final Uri ARBITRARY_ROUTE_CONTENT_URI_ROOT = Uri
.parse("content://" + AUTHORITY + "/route");
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 API_KEY = "5LD9-IAYI-TRAT-MHHW";
public static final String ACTION_ALARM = "com.dougkeen.action.ALARM";
}
package com.dougkeen.bart.model;
import android.net.Uri;
public class Constants {
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 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 FAVORITE_CONTENT_ITEM_TYPE = "vnd.android.cursor.item/com.dougkeen.bart.favorite";
public static final Uri FAVORITE_CONTENT_URI = Uri.parse("content://"
+ AUTHORITY + "/favorites");
public static final Uri ARBITRARY_ROUTE_CONTENT_URI_ROOT = Uri
.parse("content://" + AUTHORITY + "/route");
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 API_KEY = "5LD9-IAYI-TRAT-MHHW";
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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public enum Line {
RED(false, Station.MLBR, Station.SBRN, Station.SSAN, Station.COLM,
Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station._12TH, Station._19TH,
Station.MCAR, Station.ASHB, Station.DBRK, Station.NBRK,
Station.PLZA, Station.DELN, Station.RICH),
ORANGE(false, Station.FRMT, Station.UCTY, Station.SHAY, Station.HAYW,
Station.BAYF, Station.SANL, Station.COLS, Station.FTVL,
Station.LAKE, Station._12TH, Station._19TH, Station.MCAR,
Station.ASHB, Station.DBRK, Station.NBRK, Station.PLZA,
Station.DELN, Station.RICH),
YELLOW(false, Station.MLBR, Station.SFIA, Station.SBRN, Station.SSAN,
Station.COLM, Station.DALY, Station.BALB, Station.GLEN,
Station._24TH, Station._16TH, Station.CIVC, Station.POWL,
Station.MONT, Station.EMBR, Station.WOAK, Station._12TH,
Station._19TH, Station.MCAR, Station.ROCK, Station.ORIN,
Station.LAFY, Station.WCRK, Station.PHIL, Station.CONC,
Station.NCON, Station.PITT),
BLUE(true, Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station.LAKE, Station.FTVL,
Station.COLS, Station.SANL, Station.BAYF, Station.CAST,
Station.WDUB, Station.DUBL),
GREEN(true, Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station.LAKE, Station.FTVL,
Station.COLS, Station.SANL, Station.BAYF, Station.HAYW,
Station.SHAY, Station.UCTY, Station.FRMT),
YELLOW_ORANGE_SCHEDULED_TRANSFER(YELLOW, ORANGE, Station.MLBR,
Station.SFIA, Station.SBRN, Station.SSAN, Station.COLM,
Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station.ASHB, Station.DBRK,
Station.NBRK, Station.PLZA, Station.DELN, Station.RICH);
public final List<Station> stations;
protected final boolean directionMayInvert;
protected final boolean requiresTransfer;
protected final Line transferLine1;
protected final Line transferLine2;
private Line(boolean directionMayInvert, Station... stationArray) {
this.requiresTransfer = false;
this.directionMayInvert = directionMayInvert;
stations = Arrays.asList(stationArray);
this.transferLine1 = null;
this.transferLine2 = null;
}
private Line(Line transferLine1, Line transferLine2,
Station... stationArray) {
this.requiresTransfer = true;
this.directionMayInvert = false;
stations = Arrays.asList(stationArray);
this.transferLine1 = transferLine1;
this.transferLine2 = transferLine2;
}
private Line(boolean directionMayInvert, Line transferLine1,
Line transferLine2, Station... stationArray) {
this.requiresTransfer = true;
this.directionMayInvert = directionMayInvert;
stations = Arrays.asList(stationArray);
this.transferLine1 = transferLine1;
this.transferLine2 = transferLine2;
}
public static Collection<Line> getLinesForStation(Station station) {
Collection<Line> lines = new ArrayList<Line>();
for (Line line : Line.values()) {
if (line.stations.contains(station)) {
lines.add(line);
}
}
return lines;
}
public static Collection<Line> getLinesWithStations(Station station1, Station station2) {
Collection<Line> lines = new ArrayList<Line>();
for (Line line : Line.values()) {
if (line.stations.contains(station1) && line.stations.contains(station2)) {
lines.add(line);
}
}
return lines;
}
public static Set<Station> getPotentialDestinations(Station station) {
Set<Station> destinations = new TreeSet<Station>();
for (Line line : getLinesForStation(station)) {
destinations.addAll(line.stations);
}
destinations.remove(station);
return destinations;
}
}
package com.dougkeen.bart.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public enum Line {
RED(false, Station.MLBR, Station.SBRN, Station.SSAN, Station.COLM,
Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station._12TH, Station._19TH,
Station.MCAR, Station.ASHB, Station.DBRK, Station.NBRK,
Station.PLZA, Station.DELN, Station.RICH),
ORANGE(false, Station.FRMT, Station.UCTY, Station.SHAY, Station.HAYW,
Station.BAYF, Station.SANL, Station.COLS, Station.FTVL,
Station.LAKE, Station._12TH, Station._19TH, Station.MCAR,
Station.ASHB, Station.DBRK, Station.NBRK, Station.PLZA,
Station.DELN, Station.RICH),
YELLOW(false, Station.MLBR, Station.SFIA, Station.SBRN, Station.SSAN,
Station.COLM, Station.DALY, Station.BALB, Station.GLEN,
Station._24TH, Station._16TH, Station.CIVC, Station.POWL,
Station.MONT, Station.EMBR, Station.WOAK, Station._12TH,
Station._19TH, Station.MCAR, Station.ROCK, Station.ORIN,
Station.LAFY, Station.WCRK, Station.PHIL, Station.CONC,
Station.NCON, Station.PITT),
BLUE(true, Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station.LAKE, Station.FTVL,
Station.COLS, Station.SANL, Station.BAYF, Station.CAST,
Station.WDUB, Station.DUBL),
GREEN(true, Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station.LAKE, Station.FTVL,
Station.COLS, Station.SANL, Station.BAYF, Station.HAYW,
Station.SHAY, Station.UCTY, Station.FRMT),
YELLOW_ORANGE_SCHEDULED_TRANSFER(YELLOW, ORANGE, Station.MLBR,
Station.SFIA, Station.SBRN, Station.SSAN, Station.COLM,
Station.DALY, Station.BALB, Station.GLEN, Station._24TH,
Station._16TH, Station.CIVC, Station.POWL, Station.MONT,
Station.EMBR, Station.WOAK, Station.ASHB, Station.DBRK,
Station.NBRK, Station.PLZA, Station.DELN, Station.RICH);
public final List<Station> stations;
protected final boolean directionMayInvert;
protected final boolean requiresTransfer;
protected final Line transferLine1;
protected final Line transferLine2;
private Line(boolean directionMayInvert, Station... stationArray) {
this.requiresTransfer = false;
this.directionMayInvert = directionMayInvert;
stations = Arrays.asList(stationArray);
this.transferLine1 = null;
this.transferLine2 = null;
}
private Line(Line transferLine1, Line transferLine2,
Station... stationArray) {
this.requiresTransfer = true;
this.directionMayInvert = false;
stations = Arrays.asList(stationArray);
this.transferLine1 = transferLine1;
this.transferLine2 = transferLine2;
}
private Line(boolean directionMayInvert, Line transferLine1,
Line transferLine2, Station... stationArray) {
this.requiresTransfer = true;
this.directionMayInvert = directionMayInvert;
stations = Arrays.asList(stationArray);
this.transferLine1 = transferLine1;
this.transferLine2 = transferLine2;
}
public static Collection<Line> getLinesForStation(Station station) {
Collection<Line> lines = new ArrayList<Line>();
for (Line line : Line.values()) {
if (line.stations.contains(station)) {
lines.add(line);
}
}
return lines;
}
public static Collection<Line> getLinesWithStations(Station station1,
Station station2) {
Collection<Line> lines = new ArrayList<Line>();
for (Line line : Line.values()) {
if (line.stations.contains(station1)
&& line.stations.contains(station2)) {
lines.add(line);
}
}
return lines;
}
public static Set<Station> getPotentialDestinations(Station station) {
Set<Station> destinations = new TreeSet<Station>();
for (Line line : getLinesForStation(station)) {
destinations.addAll(line.stations);
}
destinations.remove(station);
return destinations;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,151 +1,151 @@
package com.dougkeen.bart.model;
import org.apache.commons.lang3.ObjectUtils;
import android.database.Cursor;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import com.dougkeen.bart.data.CursorUtils;
import com.dougkeen.bart.data.RoutesColumns;
public class StationPair implements Parcelable {
public StationPair(Station origin, Station destination) {
super();
this.origin = origin;
this.destination = destination;
}
public StationPair(Long id, Station origin, Station destination) {
super();
this.origin = origin;
this.destination = destination;
this.id = id;
}
public StationPair(Parcel in) {
readFromParcel(in);
}
public static StationPair createFromCursor(Cursor cursor) {
StationPair pair = new StationPair(
Station.getByAbbreviation(CursorUtils.getString(cursor,
RoutesColumns.FROM_STATION)),
Station.getByAbbreviation(CursorUtils.getString(cursor,
RoutesColumns.TO_STATION)));
pair.id = CursorUtils.getLong(cursor, RoutesColumns._ID);
pair.fare = CursorUtils.getString(cursor, RoutesColumns.FARE);
pair.fareLastUpdated = CursorUtils.getLong(cursor,
RoutesColumns.FARE_LAST_UPDATED);
return pair;
}
private Long id;
private Station origin;
private Station destination;
private String fare;
private Long fareLastUpdated;
public Long getId() {
return id;
}
public Station getOrigin() {
return origin;
}
public Station getDestination() {
return destination;
}
public String getFare() {
return fare;
}
public void setFare(String fare) {
this.fare = fare;
}
public Long getFareLastUpdated() {
return fareLastUpdated;
}
public void setFareLastUpdated(Long fareLastUpdated) {
this.fareLastUpdated = fareLastUpdated;
}
public boolean isBetweenStations(Station station1, Station station2) {
return (origin.equals(station1) && destination.equals(station2))
|| (origin.equals(station2) && destination.equals(station1));
}
public Uri getUri() {
if (getOrigin() != null && getDestination() != null) {
return Constants.ARBITRARY_ROUTE_CONTENT_URI_ROOT.buildUpon()
.appendPath(getOrigin().abbreviation)
.appendPath(getDestination().abbreviation).build();
} else {
return null;
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((destination == null) ? 0 : destination.hashCode());
result = prime * result + ((origin == null) ? 0 : origin.hashCode());
return result;
}
public boolean fareEquals(StationPair other) {
if (other == null)
return false;
return ObjectUtils.equals(getFare(), other.getFare())
&& ObjectUtils.equals(getFareLastUpdated(),
other.getFareLastUpdated());
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
StationPair other = (StationPair) obj;
if (destination != other.destination)
return false;
if (origin != other.origin)
return false;
return true;
}
@Override
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(origin.abbreviation);
dest.writeString(destination.abbreviation);
}
private void readFromParcel(Parcel in) {
origin = Station.getByAbbreviation(in.readString());
destination = Station.getByAbbreviation(in.readString());
}
public static final Parcelable.Creator<StationPair> CREATOR = new Parcelable.Creator<StationPair>() {
public StationPair createFromParcel(Parcel in) {
return new StationPair(in);
}
public StationPair[] newArray(int size) {
return new StationPair[size];
}
};
package com.dougkeen.bart.model;
import org.apache.commons.lang3.ObjectUtils;
import android.database.Cursor;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import com.dougkeen.bart.data.CursorUtils;
import com.dougkeen.bart.data.RoutesColumns;
public class StationPair implements Parcelable {
public StationPair(Station origin, Station destination) {
super();
this.origin = origin;
this.destination = destination;
}
public StationPair(Long id, Station origin, Station destination) {
super();
this.origin = origin;
this.destination = destination;
this.id = id;
}
public StationPair(Parcel in) {
readFromParcel(in);
}
public static StationPair createFromCursor(Cursor cursor) {
StationPair pair = new StationPair(
Station.getByAbbreviation(CursorUtils.getString(cursor,
RoutesColumns.FROM_STATION)),
Station.getByAbbreviation(CursorUtils.getString(cursor,
RoutesColumns.TO_STATION)));
pair.id = CursorUtils.getLong(cursor, RoutesColumns._ID);
pair.fare = CursorUtils.getString(cursor, RoutesColumns.FARE);
pair.fareLastUpdated = CursorUtils.getLong(cursor,
RoutesColumns.FARE_LAST_UPDATED);
return pair;
}
private Long id;
private Station origin;
private Station destination;
private String fare;
private Long fareLastUpdated;
public Long getId() {
return id;
}
public Station getOrigin() {
return origin;
}
public Station getDestination() {
return destination;
}
public String getFare() {
return fare;
}
public void setFare(String fare) {
this.fare = fare;
}
public Long getFareLastUpdated() {
return fareLastUpdated;
}
public void setFareLastUpdated(Long fareLastUpdated) {
this.fareLastUpdated = fareLastUpdated;
}
public boolean isBetweenStations(Station station1, Station station2) {
return (origin.equals(station1) && destination.equals(station2))
|| (origin.equals(station2) && destination.equals(station1));
}
public Uri getUri() {
if (getOrigin() != null && getDestination() != null) {
return Constants.ARBITRARY_ROUTE_CONTENT_URI_ROOT.buildUpon()
.appendPath(getOrigin().abbreviation)
.appendPath(getDestination().abbreviation).build();
} else {
return null;
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((destination == null) ? 0 : destination.hashCode());
result = prime * result + ((origin == null) ? 0 : origin.hashCode());
return result;
}
public boolean fareEquals(StationPair other) {
if (other == null)
return false;
return ObjectUtils.equals(getFare(), other.getFare())
&& ObjectUtils.equals(getFareLastUpdated(),
other.getFareLastUpdated());
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
StationPair other = (StationPair) obj;
if (destination != other.destination)
return false;
if (origin != other.origin)
return false;
return true;
}
@Override
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(origin.abbreviation);
dest.writeString(destination.abbreviation);
}
private void readFromParcel(Parcel in) {
origin = Station.getByAbbreviation(in.readString());
destination = Station.getByAbbreviation(in.readString());
}
public static final Parcelable.Creator<StationPair> CREATOR = new Parcelable.Creator<StationPair>() {
public StationPair createFromParcel(Parcel in) {
return new StationPair(in);
}
public StationPair[] newArray(int size) {
return new StationPair[size];
}
};
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,118 +1,118 @@
package com.dougkeen.bart.networktasks;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.xml.sax.SAXException;
import android.os.AsyncTask;
import android.util.Log;
import android.util.Xml;
import com.dougkeen.bart.model.Constants;
import com.dougkeen.bart.model.ScheduleInformation;
import com.dougkeen.bart.model.StationPair;
public abstract class GetScheduleInformationTask extends
AsyncTask<StationPair, Integer, ScheduleInformation> {
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";
private final static int MAX_ATTEMPTS = 5;
private Exception mException;
@Override
protected ScheduleInformation doInBackground(StationPair... paramsArray) {
// Always expect one param
StationPair params = paramsArray[0];
if (!isCancelled()) {
return getScheduleFromNetwork(params, 0);
} else {
return null;
}
}
private ScheduleInformation getScheduleFromNetwork(StationPair params,
int attemptNumber) {
String xml = null;
try {
String url = String.format(SCHED_URL,
params.getOrigin().abbreviation,
params.getDestination().abbreviation);
HttpUriRequest request = new HttpGet(url);
if (isCancelled()) {
return null;
}
ScheduleContentHandler handler = new ScheduleContentHandler(
params.getOrigin(), params.getDestination());
HttpResponse response = NetworkUtils.executeWithRecovery(request);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new IOException("Server returned "
+ response.getStatusLine().toString());
}
StringWriter writer = new StringWriter();
IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8");
xml = writer.toString();
if (xml.length() == 0) {
throw new IOException("Server returned blank xml document");
}
Xml.parse(xml, handler);
final ScheduleInformation schedule = handler.getSchedule();
return schedule;
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
} catch (IOException e) {
if (attemptNumber < MAX_ATTEMPTS - 1) {
try {
Log.w(Constants.TAG,
"Attempt to contact server failed... retrying in 3s",
e);
Thread.sleep(3000);
} catch (InterruptedException interrupt) {
// Ignore... just go on to next attempt
}
return getScheduleFromNetwork(params, attemptNumber + 1);
} else {
mException = new Exception("Could not contact BART system", e);
return null;
}
} catch (SAXException e) {
mException = new Exception(
"Could not understand response from BART system: " + xml, e);
return null;
}
}
@Override
protected void onPostExecute(ScheduleInformation result) {
if (result != null) {
onResult(result);
} else {
onError(mException);
}
}
public abstract void onResult(ScheduleInformation result);
public abstract void onError(Exception exception);
}
package com.dougkeen.bart.networktasks;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.xml.sax.SAXException;
import android.os.AsyncTask;
import android.util.Log;
import android.util.Xml;
import com.dougkeen.bart.model.Constants;
import com.dougkeen.bart.model.ScheduleInformation;
import com.dougkeen.bart.model.StationPair;
public abstract class GetScheduleInformationTask extends
AsyncTask<StationPair, Integer, ScheduleInformation> {
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";
private final static int MAX_ATTEMPTS = 5;
private Exception mException;
@Override
protected ScheduleInformation doInBackground(StationPair... paramsArray) {
// Always expect one param
StationPair params = paramsArray[0];
if (!isCancelled()) {
return getScheduleFromNetwork(params, 0);
} else {
return null;
}
}
private ScheduleInformation getScheduleFromNetwork(StationPair params,
int attemptNumber) {
String xml = null;
try {
String url = String.format(SCHED_URL,
params.getOrigin().abbreviation,
params.getDestination().abbreviation);
HttpUriRequest request = new HttpGet(url);
if (isCancelled()) {
return null;
}
ScheduleContentHandler handler = new ScheduleContentHandler(
params.getOrigin(), params.getDestination());
HttpResponse response = NetworkUtils.executeWithRecovery(request);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new IOException("Server returned "
+ response.getStatusLine().toString());
}
StringWriter writer = new StringWriter();
IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8");
xml = writer.toString();
if (xml.length() == 0) {
throw new IOException("Server returned blank xml document");
}
Xml.parse(xml, handler);
final ScheduleInformation schedule = handler.getSchedule();
return schedule;
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
} catch (IOException e) {
if (attemptNumber < MAX_ATTEMPTS - 1) {
try {
Log.w(Constants.TAG,
"Attempt to contact server failed... retrying in 3s",
e);
Thread.sleep(3000);
} catch (InterruptedException interrupt) {
// Ignore... just go on to next attempt
}
return getScheduleFromNetwork(params, attemptNumber + 1);
} else {
mException = new Exception("Could not contact BART system", e);
return null;
}
} catch (SAXException e) {
mException = new Exception(
"Could not understand response from BART system: " + xml, e);
return null;
}
}
@Override
protected void onPostExecute(ScheduleInformation result) {
if (result != null) {
onResult(result);
} else {
onError(mException);
}
}
public abstract void onResult(ScheduleInformation result);
public abstract void onError(Exception exception);
}

View File

@ -1,38 +1,40 @@
package com.dougkeen.bart.networktasks;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
public class NetworkUtils {
public static HttpClient getHttpClient() {
HttpClient client = new DefaultHttpClient();
final HttpParams params = client.getParams();
HttpConnectionParams.setConnectionTimeout(params,
NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
HttpConnectionParams.setSoTimeout(params, NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
ConnManagerParams.setTimeout(params, NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
return client;
}
public static HttpResponse executeWithRecovery(final HttpUriRequest request)
throws IOException, ClientProtocolException {
try {
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;
}
package com.dougkeen.bart.networktasks;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
public class NetworkUtils {
public static HttpClient getHttpClient() {
HttpClient client = new DefaultHttpClient();
final HttpParams params = client.getParams();
HttpConnectionParams.setConnectionTimeout(params,
NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
HttpConnectionParams.setSoTimeout(params,
NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
ConnManagerParams.setTimeout(params,
NetworkUtils.CONNECTION_TIMEOUT_MILLIS);
return client;
}
public static HttpResponse executeWithRecovery(final HttpUriRequest request)
throws IOException, ClientProtocolException {
try {
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;
}

View File

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

View File

@ -24,7 +24,8 @@ public class AlarmBroadcastReceiver extends BroadcastReceiver {
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);
context.startActivity(targetIntent);