/* * ItinerarySelectionActionBarActivity.java * Last modified on 05-13-2014 10:31-0400 by brianhmayo * * Copyright (c) 2014 SEPTA. All rights reserved. */ package org.septa.android.app.activities.schedules; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Looper; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.widget.AdapterView; import android.widget.Toast; import org.septa.android.app.R; import org.septa.android.app.activities.BaseAnalyticsActionBarActivity; import org.septa.android.app.activities.GeocoderActivity; import org.septa.android.app.adapters.schedules.ItinerarySelection_ListViewItem_ArrayAdapter; import org.septa.android.app.databases.SEPTADatabase; import org.septa.android.app.models.RouteTypes; import org.septa.android.app.models.SortOrder; import org.septa.android.app.models.StopModel; import org.septa.android.app.utilities.Constants; import java.util.ArrayList; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; import static org.septa.android.app.models.RouteTypes.valueOf; public class SchedulesStopsSelectionActionBarActivity extends BaseAnalyticsActionBarActivity implements AdapterView.OnItemClickListener, StickyListHeadersListView.OnHeaderClickListener, StickyListHeadersListView.OnStickyHeaderOffsetChangedListener, StickyListHeadersListView.OnStickyHeaderChangedListener, View.OnTouchListener, View.OnClickListener, LocationListener { private static final String TAG = SchedulesStopsSelectionActionBarActivity.class.getName(); private static final int REQUEST_CODE_GECODER = 1000; private ItinerarySelection_ListViewItem_ArrayAdapter mAdapter; private boolean fadeHeader = true; private RouteTypes travelType; private String routeShortName; private StickyListHeadersListView stickyList; private LocationManager locationManager; private Menu optionsMenu; private SortOrder sortOrder = SortOrder.DEFAULT; private Location returnedLocation; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.itineraryselection); String actionBarTitleText = getIntent().getStringExtra(getString(R.string.actionbar_titletext_key)); String iconImageNameSuffix = getIntent().getStringExtra(getString(R.string.actionbar_iconimage_imagenamesuffix_key)); String resourceName = getString(R.string.actionbar_iconimage_imagename_base).concat(iconImageNameSuffix); if(getIntent().hasExtra(getString(R.string.schedules_stopselection_sort_order))) { sortOrder = (SortOrder) getIntent().getSerializableExtra(getString(R.string.schedules_stopselection_sort_order)); } int id = getResources().getIdentifier(resourceName, "drawable", getPackageName()); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setTitle("| " + actionBarTitleText); getSupportActionBar().setIcon(id); // get the start or destination string from the extra intent string if it exists final String schedulesItineraryStopSelectionStartOrDestinationString = getIntent().getStringExtra(getString(R.string.schedules_stopselection_startordestination)); if (schedulesItineraryStopSelectionStartOrDestinationString != null) { getSupportActionBar().setTitle("| Select "+schedulesItineraryStopSelectionStartOrDestinationString); } else { getSupportActionBar().setTitle("| Select Start"); } travelType = valueOf(getIntent().getStringExtra(getString(R.string.schedules_itinerary_travelType))); routeShortName = getIntent().getStringExtra(getString(R.string.schedules_itinerary_routeShortName)); Log.d("f", "got the travel type as "+travelType.name()); mAdapter = new ItinerarySelection_ListViewItem_ArrayAdapter(this, travelType, routeShortName); stickyList = (StickyListHeadersListView) findViewById(R.id.list); stickyList.setOnItemClickListener(this); stickyList.setOnHeaderClickListener(this); stickyList.setOnStickyHeaderChangedListener(this); stickyList.setOnStickyHeaderOffsetChangedListener(this); stickyList.setEmptyView(findViewById(R.id.empty)); stickyList.setDrawingListUnderStickyHeader(true); stickyList.setAreHeadersSticky(true); stickyList.setAdapter(mAdapter); stickyList.setOnTouchListener(this); stickyList.setFastScrollEnabled(true); stickyList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { StopModel stop = (StopModel)mAdapter.getItem(position); Intent returnIntent = new Intent(); returnIntent.putExtra("direction_id", stop.getDirectionId()); returnIntent.putExtra("stop_name", stop.getStopName()); returnIntent.putExtra("stop_id", stop.getStopId()); returnIntent.putExtra("selection_mode", schedulesItineraryStopSelectionStartOrDestinationString); if(sortOrder != SortOrder.DEFAULT) { returnIntent.putExtra(getString(R.string.schedules_stopselection_sort_order), sortOrder); } SchedulesStopsSelectionActionBarActivity.this.setResult(Activity.RESULT_OK, returnIntent); SchedulesStopsSelectionActionBarActivity.this.finish(); } }); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); DirectionHeaderLoader directionHeaderLoader = new DirectionHeaderLoader(routeShortName); directionHeaderLoader.execute(travelType); View headerView = findViewById(R.id.headerview_include); headerView.findViewById(R.id.headerview_textview_current_location).setOnClickListener(this); headerView.findViewById(R.id.headerview_textview_enter_address).setOnClickListener(this); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(REQUEST_CODE_GECODER == requestCode && resultCode == Activity.RESULT_OK) { Location addressLocation = data.getParcelableExtra(Constants.KEY_LOCATION); returnedLocation = addressLocation; sortByLocations(addressLocation); } } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); } @Override protected void onStop() { super.onStop(); locationManager.removeUpdates(this); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_sort, menu); optionsMenu = menu; return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_sort_123: sortByName(); break; case R.id.menu_sort_abc: sortBySequence(); break; default: return super.onOptionsItemSelected(item); } return true; } private void sortByName() { mAdapter.sortByName(); sortOrder = SortOrder.NAME; updateSortOptions(); } private void sortBySequence() { mAdapter.sortByStopSequence(); sortOrder = SortOrder.SEQUENCE; updateSortOptions(); } public void updateSortOptions() { MenuItem sortSequence = optionsMenu.findItem(R.id.menu_sort_123); MenuItem sortName = optionsMenu.findItem(R.id.menu_sort_abc); if(sortName != null && sortSequence != null) { switch (sortOrder) { case SEQUENCE: sortName.setVisible(false); sortSequence.setVisible(true); onPrepareOptionsMenu(optionsMenu); break; default: sortName.setVisible(true); sortSequence.setVisible(false); onPrepareOptionsMenu(optionsMenu); break; } } } public void removeSortOptions() { if(optionsMenu != null) { MenuItem sortStop = optionsMenu.findItem(R.id.menu_sort_123); MenuItem sortName = optionsMenu.findItem(R.id.menu_sort_abc); if (sortName != null && sortStop != null) { sortName.setVisible(false); sortStop.setVisible(false); onPrepareOptionsMenu(optionsMenu); } } } @Override public void onItemClick(AdapterView<?> parent, View view, int position,long id) { } @Override public void onHeaderClick(StickyListHeadersListView l, View header, int itemPosition, long headerId, boolean currentlySticky) { } @Override @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void onStickyHeaderOffsetChanged(StickyListHeadersListView l, View header, int offset) { if (fadeHeader && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { header.setAlpha(1 - (offset / (float) header.getMeasuredHeight())); } } @Override public void onStickyHeaderChanged(StickyListHeadersListView l, View header, int itemPosition, long headerId) { } @Override public boolean onTouch(View v, MotionEvent event) { v.setOnTouchListener(null); return false; } @Override public void onClick(View view) { switch (view.getId()) { case R.id.headerview_textview_current_location: getUserLocation(); break; case R.id.headerview_textview_enter_address: Intent intent = new Intent(this, GeocoderActivity.class); startActivityForResult(intent, REQUEST_CODE_GECODER); break; } } private void getUserLocation() { Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); locationManager.removeUpdates(this); if(userLocation == null && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { Toast.makeText(this, getString(R.string.error_location_disabled), Toast.LENGTH_SHORT).show(); } else if(userLocation != null) { Log.i(TAG, "Using cached location: " + String.valueOf(userLocation)); sortByLocations(userLocation); } else { locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, this, Looper.myLooper()); } } private void sortByLocations(Location userLocation) { if(userLocation != null && mAdapter != null) { sortOrder = SortOrder.LOCATION; returnedLocation = userLocation; mAdapter.sortByLocation(userLocation); removeSortOptions(); } } @Override public void onLocationChanged(Location location) { Log.i(TAG, "Location: " + location); sortByLocations(location); } @Override public void onStatusChanged(String s, int i, Bundle bundle) { Log.i(TAG, "Provider: " + s + " Status: " + i); } @Override public void onProviderEnabled(String s) { Log.i(TAG, "Enabled: " + s); } @Override public void onProviderDisabled(String s) { Log.i(TAG, "Disabled: " + s); } private class StopsLoader extends AsyncTask<RouteTypes, Integer, Boolean> { String routeShortName; ArrayList<StopModel> stopModelListDirection0 = new ArrayList<StopModel>(); ArrayList<StopModel> stopModelListDirection1 = new ArrayList<StopModel>(); public StopsLoader(String routeShortName) { this.routeShortName = routeShortName; } private void loadTrips(RouteTypes routeType) { SEPTADatabase septaDatabase = new SEPTADatabase(SchedulesStopsSelectionActionBarActivity.this); SQLiteDatabase database = septaDatabase.getReadableDatabase(); // special rule if the routeShortName is MFO or BSO, then the type is actually a BUS and not MFL or BSL. if (routeShortName.equals("MFO") || routeShortName.equals("BSO")) { routeType = RouteTypes.BUS; } String queryString = null; switch (routeType) { case RAIL: { Log.d("f", "type is rail, loading the trips"); queryString = "SELECT stop_id, stop_name, null as direction_id, wheelchair_boarding, null as stop_sequence, stop_lat, stop_lon FROM stops_rail ORDER BY stop_name"; break; } case BUS: { Log.d("f", "type is bus, loading the trips"); queryString = "SELECT stop_id, stop_name, direction_id, wheelchair_boarding, stop_sequence, s.stop_lat, s.stop_lon FROM stopNameLookUpTable NATURAL JOIN stops_bus s WHERE route_short_name=\"%%route_short_name%%\" ORDER BY stop_name"; queryString = queryString.replace("%%route_short_name%%", routeShortName); break; } case TROLLEY: { Log.d("f", "type is trolley, loading the trips"); queryString = "SELECT stop_id, stop_name, direction_id, wheelchair_boarding, stop_sequence, stop_lat, stop_lon FROM stopNameLookUpTable NATURAL JOIN stops_bus s WHERE route_short_name=\"%%route_short_name%%\" ORDER BY stop_name"; queryString = queryString.replace("%%route_short_name%%", routeShortName); break; } case BSL: { Log.d("f", "type is bsl, loading the trips"); queryString = "SELECT stop_times_BSL.stop_id, stops_bus.stop_name, direction_id, stops_bus.wheelchair_boarding, stop_sequence, stop_lat, stop_lon FROM trips_BSL JOIN stop_times_BSL ON trips_BSL.trip_id=stop_times_BSL.trip_id NATURAL JOIN stops_bus GROUP BY stop_times_BSL.stop_id ORDER BY stops_bus.stop_name;"; break; } case MFL: { Log.d("f", "type is mfl, loading the trips with shortname as "+routeShortName); queryString = "SELECT stop_times_MFL.stop_id, stops_bus.stop_name, direction_id, stops_bus.wheelchair_boarding, stop_sequence, stop_lat, stop_lon FROM trips_MFL JOIN stop_times_MFL ON trips_MFL.trip_id=stop_times_MFL.trip_id NATURAL JOIN stops_bus GROUP BY stop_times_MFL.stop_id ORDER BY stops_bus.stop_name;"; break; } case NHSL: { Log.d("f", "type is nhsl, loading the trips"); queryString = "SELECT stop_times_NHSL.stop_id, stops_bus.stop_name, direction_id, stops_bus.wheelchair_boarding, stop_sequence, stop_lat, stop_lon FROM trips_NHSL JOIN stop_times_NHSL ON trips_NHSL.trip_id=stop_times_NHSL.trip_id NATURAL JOIN stops_bus GROUP BY stop_times_NHSL.stop_id ORDER BY stops_bus.stop_name;"; break; } } Cursor cursor = database.rawQuery(queryString, null); if (cursor != null) { if (cursor.moveToFirst()) { do { StopModel stopModel = new StopModel(cursor.getString(0), cursor.getString(1), cursor.getInt(4), (cursor.getInt(3) == 1) ? true : false, cursor.getString(5), cursor.getString(6)); switch (routeType) { // in the case of RAIL, the direction is always 0 case RAIL: { stopModelListDirection0.add(stopModel); break; } // in the case of BUS and TROLLEY, the direction will be read from the selected row case BUS: case TROLLEY: { if (cursor.getInt(2) == 0) { stopModelListDirection0.add(stopModel); } else { stopModelListDirection1.add(stopModel); } break; } // in the case of BSL, MFL, and NHSL, stops will be shown for both directions case BSL: case MFL: case NHSL: { stopModelListDirection0.add(stopModel); stopModelListDirection1.add(stopModel); break; } } } while (cursor.moveToNext()); } cursor.close(); } else { Log.d("ii", "cursor is null"); } database.close(); } @Override protected Boolean doInBackground(RouteTypes... params) { RouteTypes routeType = params[0]; loadTrips(routeType); return false; } @Override protected void onPostExecute(Boolean b) { super.onPostExecute(b); stickyList.setFastScrollEnabled(false); mAdapter.setTripDataForDirection0(stopModelListDirection0); mAdapter.setTripDataForDirection1(stopModelListDirection1); stickyList.setFastScrollEnabled(true); switch (sortOrder) { case SEQUENCE: sortBySequence(); break; case LOCATION: sortByLocations(returnedLocation); break; default: break; } } } private class DirectionHeaderLoader extends AsyncTask<RouteTypes, Integer, Boolean> { String routeShortName; RouteTypes routeType; String[] directionHeaderLabels = new String[]{"Dir0","Dir1"}; public DirectionHeaderLoader(String routeShortName) { this.routeShortName = routeShortName; } private void loadDirectionHeaders(RouteTypes routeType) { this.routeType = routeType; SEPTADatabase septaDatabase = new SEPTADatabase(SchedulesStopsSelectionActionBarActivity.this); SQLiteDatabase database = septaDatabase.getReadableDatabase(); String queryString = null; switch (routeType) { case RAIL: case BUS: case BSL: case MFL: case NHSL: case TROLLEY: { Log.d("f", "setting querystring with route short name as "+routeShortName); queryString = "SELECT dircode, Route, DirectionDescription FROM bus_stop_directions WHERE Route=\"%%route_short_name%%\" ORDER BY dircode"; queryString = queryString.replace("%%route_short_name%%", routeShortName); break; } } Cursor cursor = null; if (queryString != null) { cursor = database.rawQuery(queryString, null); } if (cursor != null) { if (cursor.moveToFirst()) { do { if (cursor.getInt(0) == 0) { Log.d("f", "direction is 0 will set text to be "+cursor.getString(2)); directionHeaderLabels[0] = cursor.getString(2); } else { Log.d("f", "direction is 1 will set text to be "+cursor.getString(2)); directionHeaderLabels[1] = cursor.getString(2); } } while (cursor.moveToNext()); } cursor.close(); } else { Log.d("z", "cursor is null"); } database.close(); } @Override protected Boolean doInBackground(RouteTypes... params) { RouteTypes routeType = params[0]; loadDirectionHeaders(routeType); return false; } @Override protected void onPostExecute(Boolean b) { super.onPostExecute(b); mAdapter.setDirectionHeadingLabels(directionHeaderLabels); StopsLoader stopsLoader = new StopsLoader(routeShortName); stopsLoader.execute(routeType); } } }