diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 8a7ccb0..5b189bb 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -14,7 +14,7 @@ android:targetSdkVersion="14" /> @@ -61,17 +61,11 @@ android:label="@string/system_map" > - - - - - - - favorites; + + public void saveFavorites() { + if (favorites != null) { + favoritesPersistenceContext.persist(favorites); + } + } + + public List getFavorites() { + if (favorites == null) { + favorites = favoritesPersistenceContext.restore(); + if (favorites.isEmpty()) { + // Upgrade database, in case favorites are still in there + new DatabaseHelper(this).getReadableDatabase().close(); + favorites = favoritesPersistenceContext.restore(); + } + } + return favorites; + } + + public void setFavorites(List favorites) { + this.favorites = favorites; + } + + public StationPair getFavorite(Station origin, Station destination) { + for (StationPair favorite : getFavorites()) { + if (origin.equals(favorite.getOrigin()) + && destination.equals(favorite.getDestination())) { + return favorite; + } + } + return null; + } + + public void addFavorite(StationPair favorite) { + getFavorites().add(favorite); + saveFavorites(); + } + + public void removeFavorite(StationPair favorite) { + getFavorites().remove(favorite); + saveFavorites(); + } + @Override public void onCreate() { super.onCreate(); @@ -59,12 +114,13 @@ public class BartRunnerApplication extends Application { InputStream inputStream = null; try { inputStream = new FileInputStream(cachedDepartureFile); - byte[] byteArray = IOUtils.toByteArray(inputStream); - Parcel parcel = Parcel.obtain(); + final byte[] byteArray = IOUtils.toByteArray(inputStream); + final Parcel parcel = Parcel.obtain(); parcel.unmarshall(byteArray, 0, byteArray.length); parcel.setDataPosition(0); Departure lastBoardedDeparture = Departure.CREATOR .createFromParcel(parcel); + parcel.recycle(); /* * Check if the cached one is relatively recent. If so, diff --git a/src/com/dougkeen/bart/activities/AbstractRouteSelectionFragment.java b/src/com/dougkeen/bart/activities/AbstractRouteSelectionFragment.java index 2cc9e63..630a260 100644 --- a/src/com/dougkeen/bart/activities/AbstractRouteSelectionFragment.java +++ b/src/com/dougkeen/bart/activities/AbstractRouteSelectionFragment.java @@ -29,6 +29,13 @@ public abstract class AbstractRouteSelectionFragment extends DialogFragment { mTitle = title; } + @Override + public void setArguments(Bundle args) { + super.setArguments(args); + if (args.containsKey("title")) + mTitle = args.getString("title"); + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/src/com/dougkeen/bart/activities/AddRouteDialogFragment.java b/src/com/dougkeen/bart/activities/AddRouteDialogFragment.java index 46c9fd2..bdd0843 100644 --- a/src/com/dougkeen/bart/activities/AddRouteDialogFragment.java +++ b/src/com/dougkeen/bart/activities/AddRouteDialogFragment.java @@ -1,14 +1,12 @@ package com.dougkeen.bart.activities; -import android.content.ContentValues; import android.view.View; import android.widget.CheckBox; import com.dougkeen.bart.BartRunnerApplication; import com.dougkeen.bart.R; -import com.dougkeen.bart.data.RoutesColumns; -import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.Station; +import com.dougkeen.bart.model.StationPair; public class AddRouteDialogFragment extends AbstractRouteSelectionFragment { public AddRouteDialogFragment() { @@ -16,10 +14,6 @@ public class AddRouteDialogFragment extends AbstractRouteSelectionFragment { R.string.add_route)); } - public AddRouteDialogFragment(String title) { - super(title); - } - @Override public void onStart() { super.onStart(); @@ -29,22 +23,12 @@ public class AddRouteDialogFragment extends AbstractRouteSelectionFragment { @Override protected void onOkButtonClick(Station origin, Station destination) { - ContentValues values = new ContentValues(); - values.put(RoutesColumns.FROM_STATION.string, origin.abbreviation); - values.put(RoutesColumns.TO_STATION.string, destination.abbreviation); - - getActivity().getContentResolver().insert( - Constants.FAVORITE_CONTENT_URI, values); + RoutesListActivity activity = (RoutesListActivity) getActivity(); + activity.addFavorite(new StationPair(origin, destination)); if (((CheckBox) getDialog().findViewById(R.id.return_checkbox)) .isChecked()) { - values = new ContentValues(); - values.put(RoutesColumns.FROM_STATION.string, - destination.abbreviation); - values.put(RoutesColumns.TO_STATION.string, origin.abbreviation); - - getActivity().getContentResolver().insert( - Constants.FAVORITE_CONTENT_URI, values); + activity.addFavorite(new StationPair(destination, origin)); } dismiss(); diff --git a/src/com/dougkeen/bart/activities/QuickRouteDialogFragment.java b/src/com/dougkeen/bart/activities/QuickRouteDialogFragment.java index b115506..fa78652 100644 --- a/src/com/dougkeen/bart/activities/QuickRouteDialogFragment.java +++ b/src/com/dougkeen/bart/activities/QuickRouteDialogFragment.java @@ -14,10 +14,6 @@ public class QuickRouteDialogFragment extends AbstractRouteSelectionFragment { R.string.quick_departure_lookup)); } - public QuickRouteDialogFragment(String title) { - super(title); - } - @Override protected void onOkButtonClick(Station origin, Station destination) { startActivity(new Intent(Intent.ACTION_VIEW, diff --git a/src/com/dougkeen/bart/activities/RoutesListActivity.java b/src/com/dougkeen/bart/activities/RoutesListActivity.java index fd86ae0..99e2626 100644 --- a/src/com/dougkeen/bart/activities/RoutesListActivity.java +++ b/src/com/dougkeen/bart/activities/RoutesListActivity.java @@ -3,16 +3,10 @@ package com.dougkeen.bart.activities; import java.util.Calendar; import java.util.TimeZone; -import android.content.ContentUris; -import android.content.ContentValues; import android.content.DialogInterface; import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; import android.os.Bundle; -import android.support.v4.app.LoaderManager.LoaderCallbacks; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; +import android.support.v4.app.ActivityCompat; import android.util.Log; import android.view.View; import android.widget.AdapterView; @@ -29,24 +23,24 @@ import com.actionbarsherlock.view.ActionMode; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; +import com.dougkeen.bart.BartRunnerApplication; import com.dougkeen.bart.R; import com.dougkeen.bart.controls.Ticker; import com.dougkeen.bart.controls.Ticker.TickSubscriber; -import com.dougkeen.bart.data.CursorUtils; import com.dougkeen.bart.data.FavoritesArrayAdapter; -import com.dougkeen.bart.data.RoutesColumns; import com.dougkeen.bart.model.Alert; import com.dougkeen.bart.model.Alert.AlertList; import com.dougkeen.bart.model.Constants; -import com.dougkeen.bart.model.Station; import com.dougkeen.bart.model.StationPair; import com.dougkeen.bart.networktasks.AlertsClient; import com.dougkeen.bart.networktasks.ElevatorClient; import com.dougkeen.bart.networktasks.GetRouteFareTask; import com.googlecode.androidannotations.annotations.AfterViews; +import com.googlecode.androidannotations.annotations.App; import com.googlecode.androidannotations.annotations.Background; import com.googlecode.androidannotations.annotations.Click; import com.googlecode.androidannotations.annotations.EActivity; +import com.googlecode.androidannotations.annotations.InstanceState; import com.googlecode.androidannotations.annotations.ItemClick; import com.googlecode.androidannotations.annotations.ItemLongClick; import com.googlecode.androidannotations.annotations.UiThread; @@ -54,24 +48,25 @@ import com.googlecode.androidannotations.annotations.ViewById; import com.googlecode.androidannotations.annotations.rest.RestService; @EActivity(R.layout.main) -public class RoutesListActivity extends SActivity implements - LoaderCallbacks, TickSubscriber { +public class RoutesListActivity extends SActivity implements TickSubscriber { private static final String NO_DELAYS_REPORTED = "No delays reported"; - private static final int FAVORITES_LOADER_ID = 0; - private static final TimeZone PACIFIC_TIME = TimeZone .getTimeZone("America/Los_Angeles"); - private Uri mCurrentlySelectedUri; + @InstanceState + StationPair mCurrentlySelectedStationPair; - private Station mCurrentlySelectedOrigin; - private Station mCurrentlySelectedDestination; + @InstanceState + String mCurrentAlerts; private ActionMode mActionMode; private FavoritesArrayAdapter mRoutesAdapter; + @App + BartRunnerApplication app; + @RestService AlertsClient alertsClient; @@ -89,16 +84,16 @@ public class RoutesListActivity extends SActivity implements @Click(R.id.quickLookupButton) void quickLookupButtonClick() { - DialogFragment dialog = new QuickRouteDialogFragment( - getString(R.string.quick_departure_lookup)); + DialogFragment dialog = new QuickRouteDialogFragment(); dialog.show(getSupportFragmentManager().beginTransaction()); } @ItemClick(android.R.id.list) void listItemClicked(StationPair item) { - startActivity(new Intent(Intent.ACTION_VIEW, - ContentUris.withAppendedId(Constants.FAVORITE_CONTENT_URI, - item.getId()))); + Intent intent = new Intent(RoutesListActivity.this, + ViewDeparturesActivity.class); + intent.putExtra(Constants.STATION_PAIR_EXTRA, item); + startActivity(intent); } @ItemLongClick(android.R.id.list) @@ -107,11 +102,7 @@ public class RoutesListActivity extends SActivity implements mActionMode.finish(); } - mCurrentlySelectedUri = ContentUris.withAppendedId( - Constants.FAVORITE_CONTENT_URI, item.getId()); - - mCurrentlySelectedOrigin = item.getOrigin(); - mCurrentlySelectedDestination = item.getDestination(); + mCurrentlySelectedStationPair = item; startContextualActionMode(); } @@ -121,9 +112,7 @@ public class RoutesListActivity extends SActivity implements setTitle(R.string.favorite_routes); mRoutesAdapter = new FavoritesArrayAdapter(this, - R.layout.favorite_listing); - - getSupportLoaderManager().initLoader(FAVORITES_LOADER_ID, null, this); + R.layout.favorite_listing, app.getFavorites()); setListAdapter(mRoutesAdapter); @@ -132,6 +121,9 @@ public class RoutesListActivity extends SActivity implements if (mCurrentAlerts != null) { showAlertMessage(mCurrentAlerts); } + + startEtdListeners(); + refreshFares(); } /** Called when the activity is first created. */ @@ -140,58 +132,14 @@ public class RoutesListActivity extends SActivity implements super.onCreate(savedInstanceState); if (savedInstanceState != null) { - if (savedInstanceState.getString("currentlySelectedOrigin") != null) { - mCurrentlySelectedOrigin = Station - .getByAbbreviation(savedInstanceState - .getString("currentlySelectedOrigin")); - } - if (savedInstanceState.getString("currentlySelectedDestination") != null) { - mCurrentlySelectedDestination = Station - .getByAbbreviation(savedInstanceState - .getString("currentlySelectedDestination")); - } - if (savedInstanceState.getParcelable("currentlySelectedUri") != null) { - mCurrentlySelectedUri = (Uri) savedInstanceState - .getParcelable("currentlySelectedUri"); - } if (savedInstanceState.getBoolean("hasActionMode")) { startContextualActionMode(); } - mCurrentAlerts = savedInstanceState.getString("currentAlerts"); } Ticker.getInstance().addSubscriber(this, getApplicationContext()); } - @Override - public Loader onCreateLoader(int id, Bundle args) { - return new CursorLoader(this, Constants.FAVORITE_CONTENT_URI, - new String[] { RoutesColumns._ID.string, - RoutesColumns.FROM_STATION.string, - RoutesColumns.TO_STATION.string, - RoutesColumns.FARE.string, - RoutesColumns.FARE_LAST_UPDATED.string, - RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.string, - RoutesColumns.AVERAGE_TRIP_LENGTH.string }, null, null, - RoutesColumns._ID.string); - } - - @Override - public void onLoadFinished(Loader loader, Cursor cursor) { - if (cursor.getCount() == 0) { - ((TextView) findViewById(android.R.id.empty)) - .setText(R.string.empty_favorites_list_message); - } - mRoutesAdapter.updateFromCursor(cursor); - refreshFares(cursor); - findViewById(R.id.progress).setVisibility(View.GONE); - } - - @Override - public void onLoaderReset(Loader loader) { - // Nothing to do - } - private AdapterView getListView() { return listView; } @@ -205,70 +153,59 @@ public class RoutesListActivity extends SActivity implements getListView().setAdapter(mRoutesAdapter); } - private void refreshFares(Cursor cursor) { - if (cursor.moveToFirst()) { - do { - final Station orig = Station.getByAbbreviation(CursorUtils - .getString(cursor, RoutesColumns.FROM_STATION)); - final Station dest = Station.getByAbbreviation(CursorUtils - .getString(cursor, RoutesColumns.TO_STATION)); - final Long id = CursorUtils.getLong(cursor, RoutesColumns._ID); - final Long lastUpdateMillis = CursorUtils.getLong(cursor, - RoutesColumns.FARE_LAST_UPDATED); + void addFavorite(StationPair pair) { + mRoutesAdapter.add(pair); + } - Calendar now = Calendar.getInstance(); - Calendar lastUpdate = Calendar.getInstance(); - lastUpdate.setTimeInMillis(lastUpdateMillis); + private void refreshFares() { + for (int i = getListAdapter().getCount() - 1; i >= 0; i--) { + final StationPair stationPair = getListAdapter().getItem(i); - now.setTimeZone(PACIFIC_TIME); - lastUpdate.setTimeZone(PACIFIC_TIME); + Calendar now = Calendar.getInstance(); + Calendar lastUpdate = Calendar.getInstance(); + lastUpdate.setTimeInMillis(stationPair.getFareLastUpdated()); - // Update every day - if (now.get(Calendar.DAY_OF_YEAR) != lastUpdate - .get(Calendar.DAY_OF_YEAR)) { - GetRouteFareTask fareTask = new GetRouteFareTask() { - @Override - public void onResult(String fare) { - ContentValues values = new ContentValues(); - values.put(RoutesColumns.FARE.string, fare); - values.put(RoutesColumns.FARE_LAST_UPDATED.string, - System.currentTimeMillis()); + now.setTimeZone(PACIFIC_TIME); + lastUpdate.setTimeZone(PACIFIC_TIME); - getContentResolver() - .update(ContentUris.withAppendedId( - Constants.FAVORITE_CONTENT_URI, id), - values, null, null); - } + // Update every day + if (now.get(Calendar.DAY_OF_YEAR) != lastUpdate + .get(Calendar.DAY_OF_YEAR) + || now.get(Calendar.YEAR) != lastUpdate.get(Calendar.YEAR)) { + GetRouteFareTask fareTask = new GetRouteFareTask() { + @Override + public void onResult(String fare) { + stationPair.setFare(fare); + stationPair.setFareLastUpdated(System + .currentTimeMillis()); + getListAdapter().notifyDataSetChanged(); + } - @Override - public void onError(Exception exception) { - // Ignore... we can do this later - } - }; - fareTask.execute(new GetRouteFareTask.Params(orig, dest)); - } - } while (cursor.moveToNext()); + @Override + public void onError(Exception exception) { + // Ignore... we can do this later + } + }; + fareTask.execute(new GetRouteFareTask.Params(stationPair + .getOrigin(), stationPair.getDestination())); + } } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - if (mCurrentlySelectedOrigin != null) - outState.putString("currentlySelectedOrigin", - mCurrentlySelectedOrigin.abbreviation); - if (mCurrentlySelectedDestination != null) - outState.putString("currentlySelectedDestination", - mCurrentlySelectedDestination.abbreviation); - outState.putParcelable("currentlySelectedUri", mCurrentlySelectedUri); outState.putBoolean("hasActionMode", mActionMode != null); - outState.putString("currentAlerts", mCurrentAlerts); } @Override protected void onResume() { super.onResume(); Ticker.getInstance().startTicking(this); + startEtdListeners(); + } + + private void startEtdListeners() { if (mRoutesAdapter != null && !mRoutesAdapter.isEmpty() && !mRoutesAdapter.areEtdListenersActive()) { mRoutesAdapter.setUpEtdListeners(); @@ -287,6 +224,8 @@ public class RoutesListActivity extends SActivity implements protected void onStop() { super.onStop(); Ticker.getInstance().stopTicking(this); + app.saveFavorites(); + } @Override @@ -314,13 +253,11 @@ public class RoutesListActivity extends SActivity implements private MenuItem elevatorMenuItem; private View origElevatorActionView; - private String mCurrentAlerts; - public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.add_favorite_menu_button) { - new AddRouteDialogFragment(getString(R.string.add_route)) - .show(getSupportFragmentManager().beginTransaction()); + new AddRouteDialogFragment().show(getSupportFragmentManager() + .beginTransaction()); return true; } else if (itemId == R.id.view_system_map_button) { startActivity(new Intent(this, ViewMapActivity.class)); @@ -393,7 +330,7 @@ public class RoutesListActivity extends SActivity implements @UiThread void resetElevatorMenuGraphic() { - invalidateOptionsMenu(); + ActivityCompat.invalidateOptionsMenu(this); elevatorMenuItem.setActionView(origElevatorActionView); } @@ -407,8 +344,9 @@ public class RoutesListActivity extends SActivity implements private void startContextualActionMode() { mActionMode = startActionMode(new RouteActionMode()); - mActionMode.setTitle(mCurrentlySelectedOrigin.name); - mActionMode.setSubtitle("to " + mCurrentlySelectedDestination.name); + mActionMode.setTitle(mCurrentlySelectedStationPair.getOrigin().name); + mActionMode.setSubtitle("to " + + mCurrentlySelectedStationPair.getDestination().name); } private final class RouteActionMode implements ActionMode.Callback { @@ -426,8 +364,11 @@ public class RoutesListActivity extends SActivity implements @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == R.id.view) { - startActivity(new Intent(Intent.ACTION_VIEW, - mCurrentlySelectedUri)); + Intent intent = new Intent(RoutesListActivity.this, + ViewDeparturesActivity.class); + intent.putExtra(Constants.STATION_PAIR_EXTRA, + mCurrentlySelectedStationPair); + startActivity(intent); mode.finish(); return true; } else if (item.getItemId() == R.id.delete) { @@ -439,11 +380,9 @@ public class RoutesListActivity extends SActivity implements new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - getContentResolver().delete( - mCurrentlySelectedUri, null, null); - mCurrentlySelectedUri = null; - mCurrentlySelectedOrigin = null; - mCurrentlySelectedDestination = null; + getListAdapter().remove( + mCurrentlySelectedStationPair); + mCurrentlySelectedStationPair = null; mActionMode.finish(); dialog.dismiss(); } diff --git a/src/com/dougkeen/bart/activities/ViewDeparturesActivity.java b/src/com/dougkeen/bart/activities/ViewDeparturesActivity.java index eed5231..bc44b84 100644 --- a/src/com/dougkeen/bart/activities/ViewDeparturesActivity.java +++ b/src/com/dougkeen/bart/activities/ViewDeparturesActivity.java @@ -9,7 +9,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; -import android.database.Cursor; import android.media.MediaPlayer; import android.media.RingtoneManager; import android.net.Uri; @@ -18,9 +17,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.Parcelable; import android.os.Vibrator; -import android.support.v4.app.LoaderManager.LoaderCallbacks; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; import android.text.format.DateFormat; import android.text.util.Linkify; import android.util.Log; @@ -44,27 +40,21 @@ import com.dougkeen.bart.controls.SwipeHelper; import com.dougkeen.bart.controls.Ticker; import com.dougkeen.bart.controls.YourTrainLayout; import com.dougkeen.bart.data.DepartureArrayAdapter; -import com.dougkeen.bart.data.RoutesColumns; import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.Departure; -import com.dougkeen.bart.model.Station; import com.dougkeen.bart.model.StationPair; import com.dougkeen.bart.services.BoardedDepartureService; import com.dougkeen.bart.services.EtdService; import com.dougkeen.bart.services.EtdService.EtdServiceBinder; import com.dougkeen.bart.services.EtdService.EtdServiceListener; +import com.dougkeen.bart.services.EtdService_; import com.dougkeen.util.Observer; import com.dougkeen.util.WakeLocker; public class ViewDeparturesActivity extends SActivity implements EtdServiceListener { - private static final int LOADER_ID = 123; - - private Uri mUri; - - private Station mOrigin; - private Station mDestination; + private StationPair mStationPair; private Departure mSelectedDeparture; @@ -89,64 +79,8 @@ public class ViewDeparturesActivity extends SActivity implements final Intent intent = getIntent(); - String action = intent.getAction(); - - if (Intent.ACTION_VIEW.equals(action)) { - mUri = intent.getData(); - } - - final Uri uri = mUri; - final BartRunnerApplication bartRunnerApplication = (BartRunnerApplication) getApplication(); - if (savedInstanceState != null - && savedInstanceState.containsKey("origin") - && savedInstanceState.containsKey("destination")) { - mOrigin = Station.getByAbbreviation(savedInstanceState - .getString("origin")); - mDestination = Station.getByAbbreviation(savedInstanceState - .getString("destination")); - setListTitle(); - } else { - getSupportLoaderManager().initLoader(LOADER_ID, null, - new LoaderCallbacks() { - @Override - public Loader onCreateLoader(int id, Bundle args) { - return new CursorLoader( - ViewDeparturesActivity.this, uri, - new String[] { - RoutesColumns.FROM_STATION.string, - RoutesColumns.TO_STATION.string }, - null, null, null); - } - - @Override - public void onLoadFinished(Loader loader, - Cursor cursor) { - if (!cursor.moveToFirst()) { - Log.wtf(Constants.TAG, - "Couldn't find Route record for the current Activity"); - } - mOrigin = Station.getByAbbreviation(cursor - .getString(0)); - mDestination = Station.getByAbbreviation(cursor - .getString(1)); - setListTitle(); - if (mBound && mEtdService != null) - mEtdService.registerListener( - ViewDeparturesActivity.this, false); - refreshBoardedDeparture(false); - - getSupportLoaderManager().destroyLoader(LOADER_ID); - } - - @Override - public void onLoaderReset(Loader loader) { - // ignore - } - }); - } - mEmptyView = (TextView) findViewById(android.R.id.empty); mEmptyView.setText(R.string.departure_wait_message); @@ -155,6 +89,43 @@ public class ViewDeparturesActivity extends SActivity implements mDeparturesAdapter = new DepartureArrayAdapter(this, R.layout.departure_listing); + setListAdapter(mDeparturesAdapter); + final ListView listView = getListView(); + listView.setEmptyView(findViewById(android.R.id.empty)); + listView.setOnItemClickListener(mListItemClickListener); + listView.setOnItemLongClickListener(mListItemLongClickListener); + + mMissingDepartureText = findViewById(R.id.missingDepartureText); + mMissingDepartureText.setVisibility(View.VISIBLE); + + mYourTrainSection = (YourTrainLayout) findViewById(R.id.yourTrainSection); + mYourTrainSection.setOnClickListener(mYourTrainSectionClickListener); + mSwipeHelper = new SwipeHelper(mYourTrainSection, null, + new SwipeHelper.OnDismissCallback() { + @Override + public void onDismiss(View view, Object token) { + dismissYourTrainSelection(); + if (mActionMode != null) { + mActionMode.finish(); + } + } + }); + mYourTrainSection.setOnTouchListener(mSwipeHelper); + + if (savedInstanceState != null + && savedInstanceState.containsKey("stationPair")) { + mStationPair = savedInstanceState.getParcelable("stationPair"); + setListTitle(); + } else { + mStationPair = intent.getExtras().getParcelable( + Constants.STATION_PAIR_EXTRA); + setListTitle(); + if (mBound && mEtdService != null) + mEtdService + .registerListener(ViewDeparturesActivity.this, false); + refreshBoardedDeparture(false); + } + if (savedInstanceState != null) { if (savedInstanceState.containsKey("departures")) { for (Parcelable departure : savedInstanceState @@ -178,29 +149,6 @@ public class ViewDeparturesActivity extends SActivity implements startYourTrainActionMode(); } } - setListAdapter(mDeparturesAdapter); - final ListView listView = getListView(); - listView.setEmptyView(findViewById(android.R.id.empty)); - listView.setOnItemClickListener(mListItemClickListener); - listView.setOnItemLongClickListener(mListItemLongClickListener); - - mMissingDepartureText = findViewById(R.id.missingDepartureText); - mMissingDepartureText.setVisibility(View.VISIBLE); - - mYourTrainSection = (YourTrainLayout) findViewById(R.id.yourTrainSection); - mYourTrainSection.setOnClickListener(mYourTrainSectionClickListener); - mSwipeHelper = new SwipeHelper(mYourTrainSection, null, - new SwipeHelper.OnDismissCallback() { - @Override - public void onDismiss(View view, Object token) { - dismissYourTrainSelection(); - if (mActionMode != null) { - mActionMode.finish(); - } - } - }); - mYourTrainSection.setOnTouchListener(mSwipeHelper); - refreshBoardedDeparture(false); getSupportActionBar().setHomeButtonEnabled(true); @@ -297,8 +245,9 @@ public class ViewDeparturesActivity extends SActivity implements } private void setListTitle() { - ((TextView) findViewById(R.id.listTitle)).setText(mOrigin.name + " to " - + mDestination.name); + ((TextView) findViewById(R.id.listTitle)) + .setText(mStationPair.getOrigin().name + " to " + + mStationPair.getDestination().name); } private ListView getListView() { @@ -399,7 +348,7 @@ public class ViewDeparturesActivity extends SActivity implements @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - if (mOrigin != null || mDestination != null) { + if (mStationPair != null) { /* * If origin or destination are null, this thing was never * initialized in the first place, so there's really nothing to save @@ -415,15 +364,14 @@ public class ViewDeparturesActivity extends SActivity implements isDepartureActionModeActive()); outState.putBoolean("hasYourTrainActionMode", isYourTrainActionModeActive()); - outState.putString("origin", mOrigin.abbreviation); - outState.putString("destination", mDestination.abbreviation); + outState.putParcelable("stationPair", mStationPair); } } @Override protected void onStart() { super.onStart(); - bindService(new Intent(this, EtdService.class), mConnection, + bindService(EtdService_.intent(this).get(), mConnection, Context.BIND_AUTO_CREATE); Ticker.getInstance().startTicking(this); } @@ -459,10 +407,8 @@ public class ViewDeparturesActivity extends SActivity implements public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == android.R.id.home) { - Intent intent = new Intent(Intent.ACTION_VIEW, - Constants.FAVORITE_CONTENT_URI); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); + RoutesListActivity_.intent(this) + .flags(Intent.FLAG_ACTIVITY_CLEAR_TOP).start(); return true; } else if (itemId == R.id.view_on_bart_site_button) { startActivity(new Intent( @@ -471,9 +417,9 @@ public class ViewDeparturesActivity extends SActivity implements + DateFormat.format("h:mmaa", System.currentTimeMillis()) + "&orig=" - + mOrigin.abbreviation + + mStationPair.getOrigin().abbreviation + "&dest=" - + mDestination.abbreviation))); + + mStationPair.getDestination().abbreviation))); return true; } else if (itemId == R.id.view_system_map_button) { startActivity(new Intent(this, ViewMapActivity.class)); @@ -508,13 +454,16 @@ public class ViewDeparturesActivity extends SActivity implements private void setBoardedDeparture(Departure selectedDeparture) { final BartRunnerApplication application = (BartRunnerApplication) getApplication(); - selectedDeparture.setPassengerDestination(mDestination); + selectedDeparture + .setPassengerDestination(mStationPair.getDestination()); application.setBoardedDeparture(selectedDeparture); refreshBoardedDeparture(true); // Start the notification service - startService(new Intent(ViewDeparturesActivity.this, - BoardedDepartureService.class)); + final Intent intent = new Intent(ViewDeparturesActivity.this, + BoardedDepartureService.class); + intent.putExtra("departure", selectedDeparture); + startService(intent); } private void startDepartureActionMode() { @@ -815,9 +764,7 @@ public class ViewDeparturesActivity extends SActivity implements @Override public StationPair getStationPair() { - if (mOrigin == null || mDestination == null) - return null; - return new StationPair(mOrigin, mDestination); + return mStationPair; } private void hideYourTrainSection() { @@ -846,4 +793,4 @@ public class ViewDeparturesActivity extends SActivity implements private Departure getBoardedDeparture() { return ((BartRunnerApplication) getApplication()).getBoardedDeparture(); } -} +} \ No newline at end of file diff --git a/src/com/dougkeen/bart/data/BartContentProvider.java b/src/com/dougkeen/bart/data/BartContentProvider.java deleted file mode 100644 index dd5239a..0000000 --- a/src/com/dougkeen/bart/data/BartContentProvider.java +++ /dev/null @@ -1,271 +0,0 @@ -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 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(); - 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; - } -} diff --git a/src/com/dougkeen/bart/data/CursorUtils.java b/src/com/dougkeen/bart/data/CursorUtils.java index 6f3edc7..d99246e 100644 --- a/src/com/dougkeen/bart/data/CursorUtils.java +++ b/src/com/dougkeen/bart/data/CursorUtils.java @@ -20,4 +20,8 @@ public final class CursorUtils { public static final Long getLong(Cursor cursor, RoutesColumns column) { return cursor.getLong(cursor.getColumnIndex(column.string)); } + + public static final Integer getInteger(Cursor cursor, RoutesColumns column) { + return cursor.getInt(cursor.getColumnIndex(column.string)); + } } diff --git a/src/com/dougkeen/bart/data/DatabaseHelper.java b/src/com/dougkeen/bart/data/DatabaseHelper.java index 383aba1..14a739b 100644 --- a/src/com/dougkeen/bart/data/DatabaseHelper.java +++ b/src/com/dougkeen/bart/data/DatabaseHelper.java @@ -1,31 +1,32 @@ 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; + +import com.dougkeen.bart.BartRunnerApplication; +import com.dougkeen.bart.model.StationPair; public class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "bart.dougkeen.db"; - private static final int DATABASE_VERSION = 4; + private static final int DATABASE_VERSION = 6; public static final String FAVORITES_TABLE_NAME = "Favorites"; + private BartRunnerApplication app; + public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); + app = (BartRunnerApplication) context.getApplicationContext(); } @Override public void onCreate(SQLiteDatabase db) { - createFavoritesTable(db); } private void createFavoritesTable(SQLiteDatabase db) { @@ -45,54 +46,24 @@ public class DatabaseHelper extends SQLiteOpenHelper { try { createFavoritesTable(db); - List columns = getColumns(db, FAVORITES_TABLE_NAME); + Cursor query = db.query(FAVORITES_TABLE_NAME, RoutesColumns.all(), + null, null, null, null, null); - db.execSQL("ALTER TABLE " + FAVORITES_TABLE_NAME - + " RENAME TO temp_" + FAVORITES_TABLE_NAME); + List favorites = new ArrayList(); - createFavoritesTable(db); + while (query.moveToNext()) { + favorites.add(StationPair.createFromCursor(query)); + } - columns.retainAll(getColumns(db, FAVORITES_TABLE_NAME)); + query.close(); - 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)); + new FavoritesPersistence(app).persist(favorites); - db.execSQL("DROP TABLE temp_" + FAVORITES_TABLE_NAME); + db.execSQL("DROP TABLE " + FAVORITES_TABLE_NAME); db.setTransactionSuccessful(); } finally { db.endTransaction(); } } - - public static List getColumns(SQLiteDatabase db, String tableName) { - List ar = null; - Cursor c = null; - try { - c = db.rawQuery("select * from " + tableName + " limit 1", null); - if (c != null) { - ar = new ArrayList(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 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(); - } } diff --git a/src/com/dougkeen/bart/data/FavoritesArrayAdapter.java b/src/com/dougkeen/bart/data/FavoritesArrayAdapter.java index 700a3bd..a65614c 100644 --- a/src/com/dougkeen/bart/data/FavoritesArrayAdapter.java +++ b/src/com/dougkeen/bart/data/FavoritesArrayAdapter.java @@ -9,9 +9,7 @@ import org.apache.commons.lang3.StringUtils; import android.app.Activity; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.ServiceConnection; -import android.database.Cursor; import android.os.IBinder; import android.view.LayoutInflater; import android.view.View; @@ -32,6 +30,7 @@ import com.dougkeen.bart.model.TextProvider; import com.dougkeen.bart.services.EtdService; import com.dougkeen.bart.services.EtdService.EtdServiceBinder; import com.dougkeen.bart.services.EtdService.EtdServiceListener; +import com.dougkeen.bart.services.EtdService_; public class FavoritesArrayAdapter extends ArrayAdapter { @@ -82,10 +81,11 @@ public class FavoritesArrayAdapter extends ArrayAdapter { return !mEtdListeners.isEmpty(); } - public FavoritesArrayAdapter(Context context, int textViewResourceId) { - super(context, textViewResourceId); + public FavoritesArrayAdapter(Context context, int textViewResourceId, + List objects) { + super(context, textViewResourceId, objects); mHostActivity = (Activity) context; - mHostActivity.bindService(new Intent(mHostActivity, EtdService.class), + mHostActivity.bindService(EtdService_.intent(mHostActivity).get(), mConnection, Context.BIND_AUTO_CREATE); } @@ -118,42 +118,6 @@ public class FavoritesArrayAdapter extends ArrayAdapter { clearEtdListeners(); } - public void updateFromCursor(Cursor cursor) { - if (!cursor.moveToFirst()) { - clear(); - } - for (int i = 0; i < getCount(); i++) { - StationPair adapterItem = getItem(i); - if (cursor.isAfterLast()) { - while (i < getCount()) { - remove(getItem(i)); - } - } else { - StationPair cursorItem = StationPair.createFromCursor(cursor); - while (!cursorItem.equals(adapterItem)) { - remove(adapterItem); - if (i < getCount()) { - adapterItem = getItem(i); - } else { - break; - } - } - if (cursorItem.equals(adapterItem) - && !cursorItem.fareEquals(adapterItem)) { - adapterItem.setFare(cursorItem.getFare()); - adapterItem.setFareLastUpdated(cursorItem - .getFareLastUpdated()); - notifyDataSetChanged(); - } - cursor.moveToNext(); - } - } - while (!cursor.isAfterLast()) { - add(StationPair.createFromCursor(cursor)); - cursor.moveToNext(); - } - } - @Override public View getView(int position, View convertView, ViewGroup parent) { View view; diff --git a/src/com/dougkeen/bart/data/FavoritesPersistence.java b/src/com/dougkeen/bart/data/FavoritesPersistence.java new file mode 100644 index 0000000..1a8b8bc --- /dev/null +++ b/src/com/dougkeen/bart/data/FavoritesPersistence.java @@ -0,0 +1,63 @@ +package com.dougkeen.bart.data; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.IOUtils; + +import android.content.Context; +import android.util.Log; + +import com.dougkeen.bart.BartRunnerApplication; +import com.dougkeen.bart.model.StationPair; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.googlecode.androidannotations.annotations.EBean; + +@EBean +public class FavoritesPersistence { + private static final String TAG = "FavoritesPersistence"; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + private BartRunnerApplication app; + + public FavoritesPersistence(Context context) { + app = (BartRunnerApplication) context.getApplicationContext(); + } + + public void persist(List favorites) { + FileOutputStream outputStream = null; + try { + outputStream = app + .openFileOutput("favorites", Context.MODE_PRIVATE); + objectMapper.writeValue(outputStream, favorites); + } catch (Exception e) { + Log.e(TAG, "Could not write favorites file", e); + } finally { + IOUtils.closeQuietly(outputStream); + } + } + + public List restore() { + for (String file : app.fileList()) { + if ("favorites".equals(file)) { + FileInputStream inputStream = null; + try { + inputStream = app.openFileInput("favorites"); + return objectMapper.readValue(inputStream, + new TypeReference>() { + }); + } catch (Exception e) { + Log.e(TAG, "Could not read favorites file", e); + } finally { + IOUtils.closeQuietly(inputStream); + } + } + } + + return new ArrayList(); + } +} diff --git a/src/com/dougkeen/bart/data/RoutesColumns.java b/src/com/dougkeen/bart/data/RoutesColumns.java index 5d63e48..b3228bb 100644 --- a/src/com/dougkeen/bart/data/RoutesColumns.java +++ b/src/com/dougkeen/bart/data/RoutesColumns.java @@ -1,14 +1,11 @@ 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); + _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) { @@ -24,4 +21,13 @@ public enum RoutesColumns { protected String getColumnDef() { return string + " " + sqliteType + (nullable ? "" : " NOT NULL"); } + + public static String[] all() { + final RoutesColumns[] values = RoutesColumns.values(); + String[] returnArray = new String[values.length]; + for (int i = values.length - 1; i >= 0; i--) { + returnArray[i] = values[i].string; + } + return returnArray; + } } diff --git a/src/com/dougkeen/bart/model/Constants.java b/src/com/dougkeen/bart/model/Constants.java index c780c14..b11ce37 100644 --- a/src/com/dougkeen/bart/model/Constants.java +++ b/src/com/dougkeen/bart/model/Constants.java @@ -17,4 +17,5 @@ public class Constants { 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"; + public static final String STATION_PAIR_EXTRA = "StationPair"; } diff --git a/src/com/dougkeen/bart/model/StationPair.java b/src/com/dougkeen/bart/model/StationPair.java index c38a0f1..c1fcd79 100644 --- a/src/com/dougkeen/bart/model/StationPair.java +++ b/src/com/dougkeen/bart/model/StationPair.java @@ -3,27 +3,23 @@ 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; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; public class StationPair implements Parcelable { - public StationPair(Station origin, Station destination) { + @JsonCreator + public StationPair(@JsonProperty("origin") Station origin, + @JsonProperty("destination") 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); } @@ -34,22 +30,22 @@ public class StationPair implements Parcelable { 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); + pair.averageTripLength = CursorUtils.getInteger(cursor, + RoutesColumns.AVERAGE_TRIP_LENGTH); + pair.averageTripSampleCount = CursorUtils.getInteger(cursor, + RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT); return pair; } - private Long id; private Station origin; private Station destination; private String fare; - private Long fareLastUpdated; - - public Long getId() { - return id; - } + private long fareLastUpdated; + private int averageTripLength; + private int averageTripSampleCount; public Station getOrigin() { return origin; @@ -67,29 +63,35 @@ public class StationPair implements Parcelable { this.fare = fare; } - public Long getFareLastUpdated() { + public long getFareLastUpdated() { return fareLastUpdated; } - public void setFareLastUpdated(Long fareLastUpdated) { + public void setFareLastUpdated(long fareLastUpdated) { this.fareLastUpdated = fareLastUpdated; } + public int getAverageTripLength() { + return averageTripLength; + } + + public void setAverageTripLength(int averageTripLength) { + this.averageTripLength = averageTripLength; + } + + public int getAverageTripSampleCount() { + return averageTripSampleCount; + } + + public void setAverageTripSampleCount(int averageTripSampleCount) { + this.averageTripSampleCount = averageTripSampleCount; + } + 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; diff --git a/src/com/dougkeen/bart/services/BoardedDepartureService.java b/src/com/dougkeen/bart/services/BoardedDepartureService.java index c7c766d..62d3a98 100644 --- a/src/com/dougkeen/bart/services/BoardedDepartureService.java +++ b/src/com/dougkeen/bart/services/BoardedDepartureService.java @@ -89,7 +89,7 @@ public class BoardedDepartureService extends Service implements mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper, this); - bindService(new Intent(this, EtdService.class), mConnection, + bindService(EtdService_.intent(this).get(), mConnection, Context.BIND_AUTO_CREATE); mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); diff --git a/src/com/dougkeen/bart/services/EtdService.java b/src/com/dougkeen/bart/services/EtdService.java index d990025..427cacf 100644 --- a/src/com/dougkeen/bart/services/EtdService.java +++ b/src/com/dougkeen/bart/services/EtdService.java @@ -10,20 +10,15 @@ import java.util.WeakHashMap; import org.apache.commons.lang3.math.NumberUtils; import android.app.Service; -import android.content.ContentValues; import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; import android.os.Handler; import android.os.IBinder; -import android.support.v4.content.CursorLoader; import android.util.Log; import com.dougkeen.bart.BartRunnerApplication; import com.dougkeen.bart.R; -import com.dougkeen.bart.data.RoutesColumns; import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.Departure; import com.dougkeen.bart.model.RealTimeDepartures; @@ -33,7 +28,9 @@ import com.dougkeen.bart.model.Station; import com.dougkeen.bart.model.StationPair; import com.dougkeen.bart.networktasks.GetRealTimeDeparturesTask; import com.dougkeen.bart.networktasks.GetScheduleInformationTask; +import com.googlecode.androidannotations.annotations.EService; +@EService public class EtdService extends Service { private IBinder mBinder; @@ -106,19 +103,13 @@ public class EtdService extends Service { private class EtdServiceEngine { private static final int UNCERTAINTY_THRESHOLD = 17; - private Uri mUri; - private final StationPair mStationPair; private boolean mIgnoreDepartureDirection = false; private boolean mPendingEtdRequest = false; - private int mAverageTripLength; - private int mAverageTripSampleCount; - - // We'll only use the keys - private WeakHashMap mListeners; + private Map mListeners; private boolean mLimitToFirstNonDeparted = true; @@ -134,24 +125,9 @@ public class EtdService extends Service { public EtdServiceEngine(final StationPair route) { mStationPair = route; - mListeners = new WeakHashMap(); + mListeners = new HashMap(); mRunnableQueue = new Handler(); mLatestDepartures = new ArrayList(); - - mUri = Constants.ARBITRARY_ROUTE_CONTENT_URI_ROOT.buildUpon() - .appendPath(mStationPair.getOrigin().abbreviation) - .appendPath(mStationPair.getDestination().abbreviation) - .build(); - - Cursor cursor = new CursorLoader(EtdService.this, mUri, - new String[] { RoutesColumns.AVERAGE_TRIP_LENGTH.string, - RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.string }, - null, null, null).loadInBackground(); - if (cursor.moveToFirst()) { - mAverageTripLength = cursor.getInt(0); - mAverageTripSampleCount = cursor.getInt(1); - } - cursor.close(); } protected void registerListener(EtdServiceListener listener, @@ -238,8 +214,7 @@ public class EtdService extends Service { }; mGetDeparturesTask = task; Log.v(Constants.TAG, "Fetching data from server"); - task.execute(new StationPair(mStationPair.getOrigin(), mStationPair - .getDestination())); + task.execute(mStationPair); notifyListenersOfRequestStart(); } @@ -271,8 +246,7 @@ public class EtdService extends Service { }; Log.i(Constants.TAG, "Fetching data from server"); mGetScheduleInformationTask = task; - task.execute(new StationPair(mStationPair.getOrigin(), mStationPair - .getDestination())); + task.execute(mStationPair); } protected void applyScheduleInformation(ScheduleInformation result) { @@ -363,7 +337,8 @@ public class EtdService extends Service { departure.setEstimatedTripTime(localAverageLength); } else if (!departure.hasEstimatedTripTime()) { // Otherwise just assume the global average - departure.setEstimatedTripTime(mAverageTripLength); + departure.setEstimatedTripTime(mStationPair + .getAverageTripLength()); } } else if (departure.getRequiresTransfer() && !departure.hasAnyArrivalEstimate()) { @@ -381,20 +356,16 @@ public class EtdService extends Service { // Update global average if (mLatestScheduleInfo.getTripCountForAverage() > 0) { - int newAverageSampleCount = mAverageTripSampleCount + int newAverageSampleCount = mStationPair + .getAverageTripSampleCount() + mLatestScheduleInfo.getTripCountForAverage(); - int newAverage = (mAverageTripLength * mAverageTripSampleCount + localAverageLength + int newAverage = (mStationPair.getAverageTripLength() + * mStationPair.getAverageTripSampleCount() + localAverageLength * mLatestScheduleInfo.getTripCountForAverage()) / newAverageSampleCount; - ContentValues contentValues = new ContentValues(); - contentValues.put(RoutesColumns.AVERAGE_TRIP_LENGTH.string, - newAverage); - contentValues.put( - RoutesColumns.AVERAGE_TRIP_SAMPLE_COUNT.string, - newAverageSampleCount); - - getContentResolver().update(mUri, contentValues, null, null); + mStationPair.setAverageTripLength(newAverage); + mStationPair.setAverageTripSampleCount(newAverageSampleCount); } /*