gt:                 View row = super.getView(position, convertView, parent);
context: /*Copyright (C) 2017 M. Steve Todd mstevetodd@gmail.com
  
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 3 of the License, or
  (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  package jmri.enginedriver;
  
  import android.annotation.SuppressLint;
  import android.content.Context;
  import android.content.Intent;
  import android.content.SharedPreferences;
  import android.gesture.GestureOverlayView;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Message;
  import android.os.SystemClock;
  import android.support.v7.app.AppCompatActivity;
  import android.support.v7.widget.Toolbar;
  import android.text.Editable;
  import android.text.TextWatcher;
  import android.util.Log;
  import android.view.GestureDetector;
  import android.view.KeyEvent;
  import android.view.Menu;
  import android.view.MenuInflater;
  import android.view.MenuItem;
  import android.view.MotionEvent;
  import android.view.VelocityTracker;
  import android.view.View;
  import android.view.View.OnTouchListener;
  import android.view.ViewGroup;
  import android.view.WindowManager;
  import android.view.inputmethod.EditorInfo;
  import android.view.inputmethod.InputMethodManager;
  import android.widget.AdapterView;
  import android.widget.ArrayAdapter;
  import android.widget.Button;
  import android.widget.EditText;
  import android.widget.ListView;
  import android.widget.SimpleAdapter;
  import android.widget.Spinner;
  import android.widget.TextView;
  import android.widget.TextView.OnEditorActionListener;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.HashMap;
  
  import jmri.enginedriver.logviewer.ui.LogViewerActivity;
  
  public class routes extends AppCompatActivity implements android.gesture.GestureOverlayView.OnGestureListener {
  
      private threaded_application mainapp;  // hold pointer to mainapp
  
      private SharedPreferences prefs;
  
      private ArrayList<HashMap<String, String>> routesFullList;
      private ArrayList<HashMap<String, String>> routes_list;
      private SimpleAdapter routes_list_adapter;
      private ArrayList<String> locationList;
      private ArrayAdapter<String> locationListAdapter;
      private static String location = null;
      private Spinner locationSpinner;
  
      private GestureDetector myGesture;
      private Menu RMenu;
  
      private Toolbar toolbar;
      private int toolbarHeight;
  
      protected View routesView;
      protected GestureOverlayView routesOverlayView;
      // these are used for gesture tracking
      private float gestureStartX = 0;
      private float gestureStartY = 0;
      protected boolean gestureInProgress = false; // gesture is in progress
      private long gestureLastCheckTime; // time in milliseconds that velocity was last checked
      private static final long gestureCheckRate = 200; // rate in milliseconds to check velocity
      private VelocityTracker mVelocityTracker;
  
      public void refresh_route_view() {
  //        Log.d("Engine_Driver", "routes: refresh_route_view()");
  
          boolean hidesystemroutes = prefs.getBoolean("hide_system_route_names_preference",
                  getResources().getBoolean(R.bool.prefHideSystemRouteNamesDefaultValue));
  
          //specify logic for sort comparison (by username)
          Comparator<HashMap<String, String>> route_comparator = new Comparator<HashMap<String, String>>() {
              @Override
              public int compare(HashMap<String, String> arg0, HashMap<String, String> arg1) {
                  return arg0.get("rt_user_name").compareTo(arg1.get("rt_user_name"));    //*** was compareToIgnoreCase
              }
          };
  
          //clear and rebuild
          routesFullList.clear();
          locationList.clear();
          if (mainapp.rt_state_names != null) {  //not allowed
              if (mainapp.rt_user_names != null) { //none defined
                  int pos = 0;
                  String del = prefs.getString("DelimiterPreference", getApplicationContext().getResources().getString(R.string.prefDelimiterDefaultValue));
                  boolean hideIfNoUserName = prefs.getBoolean("HideIfNoUserNamePreference", getResources().getBoolean(R.bool.prefHideIfNoUserNameDefaultValue));
                  for (String username : mainapp.rt_user_names) {
                      boolean hasUserName = (username != null && !username.equals(""));
                      if (hasUserName || !hideIfNoUserName) {  //skip routes without usernames if pref is set
                          //get values from global array
                          String systemname = mainapp.rt_system_names[pos];
                          String currentstate = mainapp.rt_states[pos];
                          String currentstatedesc = mainapp.rt_state_names.get(currentstate);
                          if (currentstatedesc == null) {
                              currentstatedesc = "   ???";
                          }
  
                          //put values into temp hashmap
                          HashMap<String, String> hm = new HashMap<>();
                          if (hasUserName)
                              hm.put("rt_user_name", username);
                          else
                              hm.put("rt_user_name", systemname);
                          hm.put("rt_system_name_hidden", systemname);
                          if (!hidesystemroutes) {  //check prefs for show or not show this
                              hm.put("rt_system_name", systemname);
                          }
                          hm.put("rt_current_state_desc", currentstatedesc);
                          routesFullList.add(hm);
  
                          //if location is new, add to list
                          if (del.length() > 0 && hasUserName) {
                              int delim = username.indexOf(del);
                              if (delim >= 0) {
                                  String loc = username.substring(0, delim);
                                  if (!locationList.contains(loc))
                                      locationList.add(loc);
                              }
                          }
                          //
                      }
                      pos++;
                  }
                  //              routes_list_adapter.notifyDataSetChanged();
              }
          }
          updateRouteEntry();
  
          //sort lists by username
          Collections.sort(routesFullList, route_comparator);
          Collections.sort(locationList);
          locationList.add(0, getString(R.string.location_all));   // this entry goes at the top of the list
          locationListAdapter.notifyDataSetChanged();
          if (!locationList.contains(location))
              location = getString(R.string.location_all);
          locationSpinner.setSelection(locationListAdapter.getPosition(location));
  
          filterRouteView();
      }
  
      private void filterRouteView() {
  //        Log.d("Engine_Driver", "routes: filterRouteView()");
  
          final String loc = location + prefs.getString("DelimiterPreference", getApplicationContext().getResources().getString(R.string.prefDelimiterDefaultValue));
          final boolean useAllLocations = getString(R.string.location_all).equals(location);
          routes_list.clear();
          for (HashMap<String, String> hm : routesFullList) {
              String userName = hm.get("rt_user_name");
              if (useAllLocations || userName.startsWith(loc)) {
                  @SuppressWarnings("unchecked")
                  HashMap<String, String> hmFilt = (HashMap<String, String>) hm.clone();
                  if (!useAllLocations)
                      hmFilt.put("rt_user_name", userName.substring(loc.length()));
                  routes_list.add(hmFilt);
              }
          }
          routes_list_adapter.notifyDataSetChanged();  //update the list
      }
  
      private int updateRouteEntry() {
  //        Log.d("Engine_Driver", "routes: updateRouteEntry()");
  
          Button butSet = findViewById(R.id.route_toggle);
          EditText rte = findViewById(R.id.route_entry);
          String route = rte.getText().toString().trim();
          int txtLen = route.length();
          if (mainapp.rt_state_names != null) {
              rte.setEnabled(true);
              butSet.setText(getString(R.string.set));
              // don't allow Set button if nothing entered
              if (txtLen > 0) {
                  butSet.setEnabled(true);
              } else {
                  butSet.setEnabled(false);
              }
          } else {
              rte.setEnabled(false);
              butSet.setEnabled(false);
              if (!rte.getText().toString().equals(getString(R.string.disabled)))
                  rte.setText(getString(R.string.disabled));
          }
  
          if (RMenu != null) {
              mainapp.displayEStop(RMenu);
          }
  
          return txtLen;
      }
  
      //Handle messages from the communication thread back to this thread (responses from withrottle)
      @SuppressLint("HandlerLeak")
      class routes_handler extends Handler {
  
          public void handleMessage(Message msg) {
  //            Log.d("Engine_Driver", "routes: routes_handler: handleMessage");
  
              switch (msg.what) {
                  case message_type.RESPONSE: {
                      String response_str = msg.obj.toString();
  
                      if (response_str.length() >= 3) {
                          String com1 = response_str.substring(0, 3);
                          //refresh routes if any have changed state or if route list changed
                          if ("PRA".equals(com1) || "PRL".equals(com1)) {
                              refresh_route_view();
                          }
                          //update power icon
                          if ("PPA".equals(com1)) {
                              mainapp.setPowerStateButton(RMenu);
                          }
                      }
                  }
                  break;
                  case message_type.WIT_CON_RETRY:
                      witRetry(msg.obj.toString());
                      break;
                  case message_type.WIT_CON_RECONNECT:
                      refresh_route_view();
                      break;
                  case message_type.TIME_CHANGED:
                      setActivityTitle();
                      break;
                  case message_type.RESTART_APP:
                  case message_type.RELAUNCH_APP:
                  case message_type.DISCONNECT:
                  case message_type.SHUTDOWN:
                      disconnect();
                      break;
              }
          }
      }
  
      private void witRetry(String s) {
  //        Log.d("Engine_Driver", "routes: witRetry");
  
          Intent in = new Intent().setClass(this, reconnect_status.class);
          in.putExtra("status", s);
          startActivity(in);
          connection_activity.overridePendingTransition(this, R.anim.fade_in, R.anim.fade_out);
      }
  
      public class button_listener implements View.OnClickListener {
          char whichCommand; //always '2' 
  
          public button_listener(char new_command) {
              whichCommand = new_command;
          }
  
          public void onClick(View v) {
              EditText entryv = findViewById(R.id.route_entry);
              String entrytext = entryv.getText().toString().trim();
              if (entrytext.length() > 0) {
                  mainapp.sendMsg(mainapp.comm_msg_handler, message_type.ROUTE, whichCommand + entrytext);
              }
              mainapp.buttonVibration();
          }
      }
  
      //handle click for each route's state toggle button
      public class route_state_button_listener implements View.OnClickListener {
  
          public void onClick(View v) {
              ViewGroup vg = (ViewGroup) v.getParent();  //start with the list item the button belongs to
              ViewGroup rl = (ViewGroup) vg.getChildAt(0);  //get relativelayout that holds systemname and username
              TextView snv = (TextView) rl.getChildAt(1); // get systemname text from 2nd box
              String systemname = snv.getText().toString();
              mainapp.sendMsg(mainapp.comm_msg_handler, message_type.ROUTE, '2' + systemname);  // 2=toggle
              mainapp.buttonVibration();
          }
      }
  
  
  //    @Override
  //    public boolean onTouchEvent(MotionEvent event) {
  //        return myGesture.onTouchEvent(event);
  //    }
  
  
  //    public void setTitleToIncludeThrotName() {
  //        String defaultName = getApplicationContext().getResources().getString(R.string.prefThrottleNameDefaultValue);
  //        setTitle(getApplicationContext().getResources().getString(R.string.app_name_routes) + "    |    Throttle Name: " +
  //                prefs.getString("throttle_name_preference", defaultName));
  //    }
  
      /**
       * Called when the activity is first created.
       */
      @SuppressWarnings("deprecation")
      @Override
      public void onCreate(Bundle savedInstanceState) {
  //        Log.d("Engine_Driver", "routes: onCreate");
  
          mainapp = (threaded_application) getApplication();
          prefs = getSharedPreferences("jmri.enginedriver_preferences", 0);
          mainapp.applyTheme(this);
  
          super.onCreate(savedInstanceState);
  
          if (mainapp.isForcingFinish()) {     // expedite
              return;
          }
  
  
          setContentView(R.layout.routes);
          //put pointer to this activity's handler in main app's shared variable
          mainapp.routes_msg_handler = new routes_handler();
  
          routesFullList = new ArrayList<>();
          //Set up a list adapter to allow adding the list of recent connections to the UI.
          routes_list = new ArrayList<>();
          routes_list_adapter = new SimpleAdapter(this, routes_list, R.layout.routes_item,
                  new String[]{"rt_user_name", "rt_system_name_hidden", "rt_system_name", "rt_current_state_desc"},
                  new int[]{R.id.rt_user_name, R.id.rt_system_name_hidden, R.id.rt_system_name, R.id.rt_current_state_desc}) {
              //set up listener for each state button
              @Override
              public View getView(int position, View convertView, ViewGroup parent) {
  