package com.echo5bravo.govre.UI; import java.util.ArrayList; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.graphics.drawable.AnimationDrawable; import android.os.Bundle; import android.preference.PreferenceManager; import android.view.View; import android.widget.AdapterView; import android.widget.GridView; import android.widget.ImageView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; import com.echo5bravo.govre.ADAPTERS.ScheduleGridAdapter; import com.echo5bravo.govre.BLL.BusinessCalDates; import com.echo5bravo.govre.BLL.BusinessSchedule; import com.echo5bravo.govre.BLL.BusinessStation; import com.echo5bravo.govre.DAL.BusinessBaseCalDates; import com.echo5bravo.govre.INFO.CalDates; import com.echo5bravo.govre.INFO.Device; import com.echo5bravo.govre.INFO.Schedule; import com.echo5bravo.govre.INFO.Station; import com.echo5bravo.govre.UTILS.Common; import com.echo5bravo.govre.R; public class ActivityTabStationSchedule extends Activity { private static final String TAG = ActivityTabStationSchedule.class.getSimpleName(); private String UserSelectedStationId = ""; private Integer uLINE = 0; private Integer uHEADING = 0; private ScheduleGridAdapter mAdapter; private ArrayList<String> listScheduleItem; //What you want the user to see private ArrayList<Integer> listScheduleIcon; //Graphic you want the user to see private ArrayList<String> listHiddenDepartureTime; //Clean Time of Departure private ArrayList<String> listScheduleHiddenToast; //Test you want the user to Not see but Toast Message private ArrayList<String> listScheduleHiddenSelectedRow; //Station Row Selected by User ArrayList<Schedule> mySchedule; ArrayList<CalDates> myCalDates; ArrayList<Station> myStationStops; ArrayList<Schedule> currentTrains; ArrayList<Schedule> evalSchedule; ArrayList<Station> evalStations; String TodaysScheduleType; private GridView gridView; private ScheduledExecutorService scheduleTaskExecutorScheduleUpdate; private ScheduledExecutorService scheduleTaskExecutorUpdateSpinner; private Context context; private ImageView spinner; private AnimationDrawable spinnerAnim; private boolean spinnerOn; private ImageView imgNoSignal; private boolean noSignalOn; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(R.style.Theme_BlueMoon); this.setContentView(R.layout.tab_station_schedules); context = this; spinner = (ImageView) findViewById(R.id.splashSpinner); spinner.setVisibility(View.INVISIBLE); //Added this to test Layout spinnerAnim = (AnimationDrawable) spinner.getBackground(); imgNoSignal = (ImageView) findViewById(R.id.imgNoSignal); //LOAD BUNDLE VALUES Bundle state = getIntent().getExtras(); UserSelectedStationId = state.getString("UserSelectedStationId"); uLINE = state.getInt("LINE"); uHEADING = state.getInt("HEADING"); // Set custom adapter to gridview gridView = (GridView) findViewById(R.id.gridView1); } @Override protected void onStart(){ super.onStart(); //Log.d(TAG, "OnStart Called"); scheduleTaskExecutorScheduleUpdate = Executors.newSingleThreadScheduledExecutor(); // This schedule a task to run every 59 seconds: scheduleTaskExecutorScheduleUpdate.scheduleAtFixedRate(new Runnable() { public void run() { spinnerOn = true; //Local Local Collection Variables //Get Alerts on separate thread (Requires Network) if (Device.isDeviceOnline(context.getApplicationContext())){ noSignalOn = false; //TODO: Add realtime info to GridView //doRefreshGTFSFeeds(); //LoadVechicles(); //LoadUpdates(); } else { noSignalOn = true; } LoadStationStops(); LoadCalDates(); TodaysScheduleType = Common.TodaysScheduleType(context, myCalDates, true); //Special Condition: Always display the "REGULAR" schedule //on Holidays or Weekends so users can plan if (TodaysScheduleType.equals("NOSCHEDULEWKND") | TodaysScheduleType.equals("NOSCHEDULE")) TodaysScheduleType = "REGULAR"; LoadSchedule(); BuildGrid(); // Update the UI Thread runOnUiThread(new Runnable() { public void run() { // Update ListView updateGridView(); spinnerOn = false; } }); } }, 0, 59, TimeUnit.SECONDS); //scheduleTaskExecutorUpdateSpinner = Executors.newSingleThreadScheduledExecutor(); scheduleTaskExecutorUpdateSpinner = Executors.newScheduledThreadPool(4); // This schedule a task to run every second: scheduleTaskExecutorUpdateSpinner.scheduleAtFixedRate(new Runnable() { public void run() { // Update the UI Thread runOnUiThread(new Runnable() { public void run() { if (spinnerOn){ spinnerAnim.start(); spinner.setVisibility(View.VISIBLE); } else { spinnerAnim.stop(); spinner.setVisibility(View.INVISIBLE); } if (noSignalOn){ //imgNoSignal.setVisibility(View.VISIBLE); imgNoSignal.setVisibility(View.INVISIBLE); } else { imgNoSignal.setVisibility(View.INVISIBLE); } // Update ListView updateGridView(); } }); } }, 0, 500, TimeUnit.MILLISECONDS); } private void LoadStationStops(){ //Current Station Collection myStationStops = BusinessStation.getAllStations(this); } private void LoadSchedule(){ //Current Schedule Collection mySchedule = BusinessSchedule.getAllSchedules(this, TodaysScheduleType, true); } private void LoadCalDates(){ //Current CalDates Collection //myCalDates = BusinessBaseCalDates.getAllCalDates(this); myCalDates = BusinessCalDates.getAllCalDates(this); } /*private void LoadVechicles(){ //Current Station Collection myVehicles = BusinessVehicle.getAllVehicles(context); } private void LoadUpdates(){ //Current Station Collection myUpdates = BusinessUpdate.getAllUpdates(context); }*/ private void updateGridView(){ if (mySchedule != null && myCalDates != null && myStationStops != null){ if (gridView.getAdapter() == null){ // prepared arraylist and passed it to the Adapter class mAdapter = new ScheduleGridAdapter(this, listScheduleItem, listScheduleIcon, listScheduleHiddenToast, listScheduleHiddenSelectedRow, listHiddenDepartureTime); gridView.setAdapter(mAdapter); // Implement On Item click listener gridView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { Toast.makeText(ActivityTabStationSchedule.this, mAdapter.getItem(position), Toast.LENGTH_SHORT).show(); } }); } else { gridView.invalidate(); ((ScheduleGridAdapter)gridView.getAdapter()).refill(this, listScheduleItem, listScheduleIcon, listScheduleHiddenToast, listScheduleHiddenSelectedRow, listHiddenDepartureTime); } } } private void BuildGrid(){ listScheduleItem = new ArrayList<String>(); listHiddenDepartureTime = new ArrayList<String>(); listScheduleHiddenToast = new ArrayList<String>(); listScheduleHiddenSelectedRow = new ArrayList<String>(); listScheduleIcon = new ArrayList<Integer>(); currentTrains = new ArrayList<Schedule>(); int colCounter = 1; int NORTH = uHEADING; //1 = NORTH 0 = SOUTH int LINE = uLINE; //Fredericksburg = 2 and Manassas = 4 int rowCount = 1; int colCount = 1; int scheduleUpperBound = 0; //Used to track the upperbound of our array String sImgStation = ""; int imageStationResource; //ListItems to be bound to GridView listScheduleItem.add("TRAIN"); listHiddenDepartureTime.add(""); listScheduleHiddenToast.add("Row of VRE Trains"); listScheduleHiddenSelectedRow.add("false"); listScheduleIcon.add(R.drawable.clear_spacer); boolean scheduleExists = false; boolean selectedStation = false; //Load User's Time format preference SharedPreferences getPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); String timeformat = getPrefs.getString("listTimeFormat", "12"); try{ //////////////////////////////////////////////////////////////// // STEP 1: CREATE HEADER ROW, DISPLAY ONLY THE TRAINS /////////////////////////////////////////////////////////////// for (Station eachStop : myStationStops) { rowCount++; //One Row fore every Station Stop for (Schedule eachSchedule : mySchedule) { if(eachSchedule.TRIP_DIRECTION_ID() == NORTH && eachSchedule.ROUTE_ID() == LINE && eachSchedule.SCHEDULE_STOP_ID().equals(eachStop.STATION_ID())){ //If 1st Column, enter the default values String sImgTrain = "drawable/map_train_green_" + eachSchedule.TRIP_SHORT_NAME().toLowerCase(); int imageResource = getResources().getIdentifier(sImgTrain, null, getPackageName()); listScheduleItem.add("M-F"); listHiddenDepartureTime.add(""); listScheduleHiddenToast.add("Train Number: " + eachSchedule.TRIP_SHORT_NAME()); listScheduleHiddenSelectedRow.add("false"); listScheduleIcon.add(imageResource); //Collect all Trains, this will be used to check the schedule in Step2 currentTrains.add(eachSchedule); colCount++; //One Column for every Train } } break; } //IMPORTANT: Set Grid column count Use colCount gridView.setNumColumns(colCount); //////////////////////////////////////////////////////////////// // STEP 2: Create a collection of all Stations for the Line // bing reported on. The Stations should be FRED or MANASSAS /////////////////////////////////////////////////////////////// evalStations = new ArrayList<Station>(); for (Station eachStop : myStationStops) { for (Schedule eachSchedule : mySchedule) { if(eachSchedule.TRIP_DIRECTION_ID() == NORTH && eachSchedule.ROUTE_ID() == LINE && eachSchedule.SCHEDULE_STOP_ID().equals(eachStop.STATION_ID())){ eachSchedule.STATION_ABBREVIATION(eachStop.ABBREVIATION()); eachSchedule.STATION_STOP_NAME(eachStop.STATION_STOP_NAME()); evalStations.add(eachStop); break; } } } //////////////////////////////////////////////////////////////// // STEP 3: From STEP 1, loop through all Stations for this Line /////////////////////////////////////////////////////////////// for (Station eachStop : evalStations) { evalSchedule = new ArrayList<Schedule>(); //////////////////////////////////////////////////////////////// // STEP 4: From STEP 1, loop through all Schedules /////////////////////////////////////////////////////////////// for (Schedule eachSchedule : mySchedule) { if(eachSchedule.TRIP_DIRECTION_ID() == NORTH && eachSchedule.ROUTE_ID() == LINE && eachSchedule.SCHEDULE_STOP_ID().equals(eachStop.STATION_ID())){ eachSchedule.STATION_ABBREVIATION(eachStop.ABBREVIATION()); eachSchedule.STATION_STOP_NAME(eachStop.STATION_STOP_NAME()); evalSchedule.add(eachSchedule); } } //////////////////////////////////////////////////////////////// // STEP 5: Loop through All known Trains. This is done because // not all of the trains stop at all the stations. This // means that there will not be a schedule record to // evaluate. So we force the loop of current trains and // if the train does not have a match in the inner loop // of schedules, then we know to skip that station and // add an artificial filler // //EXAMPLES: Fredericksburg NORTH Train 300 Skips: // Quantico // Rippon // Lorton // Springfield // // These positions in the grid will be substituted // with a "--" character. /////////////////////////////////////////////////////////////// //Verify All trains are present for the current station schedule for (Schedule eachTrain : currentTrains) { if (eachStop.STATION_ID().toUpperCase().equals(UserSelectedStationId)) selectedStation = true; else selectedStation = false; for (Schedule eachSchedule : evalSchedule){ if (eachSchedule.TRIP_SHORT_NAME().equals(eachTrain.TRIP_SHORT_NAME())){ scheduleExists = true; //This is the 1st Column, Add the Station Abbreviation 1st, then the 1st Train if (colCounter == 1){ //Create a nice Station Icon instead of Name sImgStation = "drawable/station_" + eachSchedule.SCHEDULE_STOP_ID().toLowerCase(); imageStationResource = getResources().getIdentifier(sImgStation, null, getPackageName()); listScheduleItem.add(""); listHiddenDepartureTime.add(""); listScheduleHiddenToast.add("Station: " + eachSchedule.STATION_STOP_NAME()); listScheduleHiddenSelectedRow.add(String.valueOf(selectedStation)); listScheduleIcon.add(imageStationResource); //All other columns enter the Departure Time listScheduleItem.add(Common.FormatTime(eachSchedule.SCHEDULE_DEPARTURE_TIME(), timeformat)); listHiddenDepartureTime.add(eachSchedule.SCHEDULE_DEPARTURE_TIME()); listScheduleHiddenToast.add("Train: " + eachSchedule.TRIP_SHORT_NAME() + " Arrive/Departs " + eachSchedule.STATION_STOP_NAME() + " @" + Common.FormatTime(eachSchedule.SCHEDULE_DEPARTURE_TIME(), timeformat)); listScheduleHiddenSelectedRow.add(String.valueOf(selectedStation)); listScheduleIcon.add(R.drawable.clear_spacer); colCounter++; } else { //All other columns enter the Departure Time listScheduleItem.add(Common.FormatTime(eachSchedule.SCHEDULE_DEPARTURE_TIME(), timeformat)); listHiddenDepartureTime.add(eachSchedule.SCHEDULE_DEPARTURE_TIME()); listScheduleHiddenToast.add("Train: " + eachSchedule.TRIP_SHORT_NAME() + " Arrive/Departs " + eachSchedule.STATION_STOP_NAME() + " @" + Common.FormatTime(eachSchedule.SCHEDULE_DEPARTURE_TIME(), timeformat)); listScheduleHiddenSelectedRow.add(String.valueOf(selectedStation)); listScheduleIcon.add(R.drawable.clear_spacer); colCounter++; if (colCounter==colCount) colCounter=1; //ResetCounter } } } //The Schedule didn't exist for the train, add a empty placeholder if (scheduleExists == false){ if (colCounter == 1){ //Create a nice Station Icon instead of Name sImgStation = "drawable/station_" + eachStop.STATION_ID().toLowerCase(); imageStationResource = getResources().getIdentifier(sImgStation, null, getPackageName()); listScheduleItem.add(""); listHiddenDepartureTime.add(""); listScheduleHiddenToast.add("Station: " + eachStop.STATION_STOP_NAME()); listScheduleHiddenSelectedRow.add(String.valueOf(selectedStation)); listScheduleIcon.add(imageStationResource); //All other columns enter the Departure Time listScheduleItem.add("--"); listHiddenDepartureTime.add(""); listScheduleHiddenToast.add("No Stop for " + eachTrain.TRIP_SHORT_NAME() + " at Station " + eachStop.STATION_STOP_NAME()); listScheduleHiddenSelectedRow.add(String.valueOf(selectedStation)); listScheduleIcon.add(R.drawable.clear_spacer); colCounter++; } else { //All other columns enter the Departure Time listScheduleItem.add("--"); listHiddenDepartureTime.add(""); listScheduleHiddenToast.add("No Stop for " + eachTrain.TRIP_SHORT_NAME() + " at Station " + eachStop.STATION_STOP_NAME()); listScheduleHiddenSelectedRow.add(String.valueOf(selectedStation)); listScheduleIcon.add(R.drawable.clear_spacer); colCounter++; if (colCounter==colCount) colCounter=1; //ResetCounter } } else { scheduleExists = false; //Reset; } } } } catch(Exception ex) { ex.toString(); } } /* * Remember our current location if we have one. */ @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); /* * Save UI state changes to the savedInstanceState. * This bundle will be passed to onCreate if the process is * killed and restarted. */ if (UserSelectedStationId != null) outState.putString("UserSelectedStationId", UserSelectedStationId.toString()); if (uLINE != null) outState.putInt("LINE", uLINE); if (uHEADING != null) outState.putInt("HEADING", uHEADING); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // Restore UI state from the savedInstanceState. // This bundle has also been passed to onCreate. UserSelectedStationId = savedInstanceState.getString("UserSelectedStationId"); uLINE = savedInstanceState.getInt("LINE"); uHEADING = savedInstanceState.getInt("HEADING"); } /* * Register for the updates when Activity is in foreground */ @Override protected void onResume() { super.onResume(); /* When Activity restored, fetch the current mOldTrainLineFilterValue * this is used in the updateStationList() method to toggle between setting * a New instance of an adapter vs updating the current adapter in the * event the user changes their Train Line preference. * * Using the Editor object by the "onStop()" event to make the preference * change, this will maintain state of our value even if the app is killed */ } @Override protected void onStop(){ super.onStop(); /* Before the Activity stops, save the current mOldTrainLineFilterValue * this is used in the updateStationList() method to toggle between setting * a New instance of an adapter vs updating the current adapter in the * event the user changes their Train Line preference. * * Using the Editor object to make the preference change, this will maintain * state of our value even if the app is killed * */ scheduleTaskExecutorScheduleUpdate.shutdown(); scheduleTaskExecutorUpdateSpinner.shutdown(); //Stop Progress Spinner spinnerAnim.stop(); spinner.setVisibility(View.INVISIBLE); } }