diff --git a/src/it/reyboz/bustorino/backend/GTTStopsFetcher.java b/src/it/reyboz/bustorino/backend/GTTStopsFetcher.java
index 89836af..1b2df98 100644
--- a/src/it/reyboz/bustorino/backend/GTTStopsFetcher.java
+++ b/src/it/reyboz/bustorino/backend/GTTStopsFetcher.java
@@ -1,191 +1,191 @@
 /*
 	BusTO (backend components)
     Copyright (C) 2016 Ludovico Pavesi
 
     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, see <http://www.gnu.org/licenses/>.
  */
 
 package it.reyboz.bustorino.backend;
 
 import androidx.annotation.NonNull;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.net.URL;
 import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
 public class GTTStopsFetcher implements StopsFinderByName  {
     @Override @NonNull
     public List<Stop> FindByName(String name, AtomicReference<Result> res) {
         URL url;
         // sorting an ArrayList should be faster than a LinkedList and the API is limited to 15 results
         List<Stop> s = new ArrayList<>(15);
         List<Stop> s2 = new ArrayList<>(15);
         String fullname;
         String content;
         String bacino;
         String localita;
         Route.Type type;
         JSONArray json;
         int howManyStops, i;
         JSONObject thisstop;
 
         if(name.length() < 3) {
             res.set(Result.QUERY_TOO_SHORT);
             return s;
         }
 
         try {
-            url = new URL("http://www.gtt.to.it/cms/components/com_gtt/views/palinejson/view.html.php?term=" + URLEncoder.encode(name, "utf-8"));
+            url = new URL("https://www.gtt.to.it/cms/index.php?option=com_gtt&view=palinejson&term=" + URLEncoder.encode(name, "utf-8"));
         } catch (Exception e) {
             res.set(Result.PARSER_ERROR);
             return s;
         }
 
         content = networkTools.queryURL(url, res);
         if(content == null) {
             return s;
         }
 
         try {
             json = new JSONArray(content);
         } catch(JSONException e) {
             if(content.contains("[]")) {
                 // when no results are found, server returns a PHP Warning and an empty array. In case they fix the warning, we're looking for the array.
                 res.set(Result.EMPTY_RESULT_SET);
             } else {
                 res.set(Result.PARSER_ERROR);
             }
             return s;
         }
 
         howManyStops = json.length();
         if(howManyStops == 0) {
             res.set(Result.EMPTY_RESULT_SET);
             return s;
         }
 
         try {
             for(i = 0; i < howManyStops; i++) {
                 thisstop = json.getJSONObject(i);
                 fullname = thisstop.getString("data");
                 String ID = thisstop.getString("value");
 
                 try {
                     localita = thisstop.getString("localita");
                     if(localita.equals("[MISSING]")) {
                         localita = null;
                     }
                 } catch(JSONException e) {
                     localita = null;
                 }
                 /*
                 if(localita == null || localita.length() == 0) {
                     localita = db.getLocationFromID(ID);
                 }
                 //TODO: find località by ContentProvider
                 */
 
                 try {
                     bacino = thisstop.getString("bacino");
                 } catch (JSONException ignored) {
                     bacino = "U";
                 }
 
                 if(fullname.startsWith("Metro ")) {
                     type = Route.Type.METRO;
                 } else if(fullname.length() >= 6 && fullname.startsWith("S00")) {
                     type = Route.Type.RAILWAY;
                 } else if(fullname.startsWith("ST")) {
                     type = Route.Type.RAILWAY;
                 } else {
                     type = FiveTNormalizer.decodeType("", bacino);
                 }
                 //TODO: refactor using content provider
                 s.add(new Stop(fullname, ID, localita, type,null));
 
             }
         } catch (JSONException e) {
             res.set(Result.PARSER_ERROR);
             return s;
         }
 
         if(s.size() < 1) {
             // shouldn't happen but prevents the next part from catching fire
             res.set(Result.EMPTY_RESULT_SET);
             return s;
         }
 
         Collections.sort(s);
 
         // the next loop won't work with less than 2 items
         if(s.size() < 2) {
             res.set(Result.OK);
             return s;
         }
 
         /* There are some duplicate stops returned by this API.
          * Long distance buses have stop IDs with 5 digits. Always. They are zero-padded if there
          * aren't enough. E.g. stop 631 becomes 00631.
          *
          * Unfortunately you can't use padded stops to query any API.
          * Fortunately, unpadded stops return both normal and long distance bus timetables.
          * FiveTNormalizer is already removing padding (there may be some padded stops for which the
          * API doesn't return an unpadded equivalent), here we'll remove duplicates by skipping
          * padded stops, which also never have a location.
          *
          * I had to draw a finite state machine on a piece of paper to understand how to implement
          * this loop.
          */
         for(i = 1; i < howManyStops; ) {
             Stop current = s.get(i);
             Stop previous = s.get(i-1);
 
             // same stop: let's see which one to keep...
             if(current.ID.equals(previous.ID)) {
                 if(previous.location == null) {
                     // previous one is useless: discard it, increment
                     i++;
                 } else if(current.location == null) {
                     // this one is useless: add previous and skip one
                     s2.add(previous);
                     i += 2;
                 } else {
                     // they aren't really identical: to err on the side of caution, keep them both.
                     s2.add(previous);
                     i++;
                 }
             } else {
                 // different: add previous, increment
                 s2.add(previous);
                 i++;
             }
         }
 
         // unless the last one was garbage (i would be howManyStops+1 in that case), add it
         if(i == howManyStops) {
             s2.add(s.get(i-1));
         }
 
         res.set(Result.OK);
         return s2;
     }
 
 }
diff --git a/src/it/reyboz/bustorino/fragments/FragmentHelper.java b/src/it/reyboz/bustorino/fragments/FragmentHelper.java
index f7e21cd..af7572f 100644
--- a/src/it/reyboz/bustorino/fragments/FragmentHelper.java
+++ b/src/it/reyboz/bustorino/fragments/FragmentHelper.java
@@ -1,270 +1,271 @@
 /*
 	BusTO (fragments)
     Copyright (C) 2018 Fabio Mazza
 
     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, see <http://www.gnu.org/licenses/>.
  */
 package it.reyboz.bustorino.fragments;
 
 
 import android.content.Context;
 
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentTransaction;
 import android.util.Log;
 import android.widget.Toast;
 
 import it.reyboz.bustorino.R;
 import it.reyboz.bustorino.backend.Fetcher;
 import it.reyboz.bustorino.backend.Palina;
 import it.reyboz.bustorino.backend.Stop;
 import it.reyboz.bustorino.backend.utils;
 import it.reyboz.bustorino.middleware.*;
 
 import java.lang.ref.WeakReference;
 import java.util.List;
 
 /**
  * Helper class to manage the fragments and their needs
  */
 public class FragmentHelper {
     //GeneralActivity act;
     private final FragmentListenerMain listenerMain;
     private final WeakReference<FragmentManager> managerWeakRef;
     private Stop lastSuccessfullySearchedBusStop;
     //support for multiple frames
     private final int secondaryFrameLayout;
     private final int primaryFrameLayout;
     private final Context context;
     public static final int NO_FRAME = -3;
     private static final String DEBUG_TAG = "BusTO FragmHelper";
     private WeakReference<AsyncDataDownload> lastTaskRef;
     private boolean shouldHaltAllActivities=false;
 
 
     public FragmentHelper(FragmentListenerMain listener, FragmentManager framan, Context context, int mainFrame) {
         this(listener,framan, context,mainFrame,NO_FRAME);
     }
 
     public FragmentHelper(FragmentListenerMain listener, FragmentManager fraMan, Context context, int primaryFrameLayout, int secondaryFrameLayout) {
         this.listenerMain = listener;
         this.managerWeakRef = new WeakReference<>(fraMan);
         this.primaryFrameLayout = primaryFrameLayout;
         this.secondaryFrameLayout = secondaryFrameLayout;
         this.context = context.getApplicationContext();
     }
 
     /**
      * Get the last successfully searched bus stop or NULL
      *
      * @return the stop
      */
     public Stop getLastSuccessfullySearchedBusStop() {
         return lastSuccessfullySearchedBusStop;
     }
 
     public void setLastSuccessfullySearchedBusStop(Stop stop) {
         this.lastSuccessfullySearchedBusStop = stop;
     }
 
     public void setLastTaskRef(WeakReference<AsyncDataDownload> lastTaskRef) {
         this.lastTaskRef = lastTaskRef;
     }
 
     /**
      * Called when you need to create a fragment for a specified Palina
      * @param p the Stop that needs to be displayed
      */
     public void createOrUpdateStopFragment(Palina p, boolean addToBackStack){
         boolean sameFragment;
         ArrivalsFragment arrivalsFragment;
 
         if(managerWeakRef.get()==null || shouldHaltAllActivities) {
             //SOMETHING WENT VERY WRONG
             Log.e(DEBUG_TAG, "We are asked for a new stop but we can't show anything");
             return;
         }
 
         FragmentManager fm = managerWeakRef.get();
 
         if(fm.findFragmentById(primaryFrameLayout) instanceof ArrivalsFragment) {
             arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(primaryFrameLayout);
             //Log.d(DEBUG_TAG, "Arrivals are for fragment with same stop?");
             assert arrivalsFragment != null;
             sameFragment = arrivalsFragment.isFragmentForTheSameStop(p);
         } else {
             sameFragment = false;
             Log.d(DEBUG_TAG, "We aren't showing an ArrivalsFragment");
 
         }
         setLastSuccessfullySearchedBusStop(p);
 
         if(!sameFragment) {
             //set the String to be displayed on the fragment
             String displayName = p.getStopDisplayName();
             String displayStuff;
 
             if (displayName != null && displayName.length() > 0) {
                 arrivalsFragment = ArrivalsFragment.newInstance(p.ID,displayName);
             } else {
                 arrivalsFragment = ArrivalsFragment.newInstance(p.ID);
             }
             String probableTag = ResultListFragment.getFragmentTag(p);
             attachFragmentToContainer(fm,arrivalsFragment,new AttachParameters(probableTag, true, addToBackStack));
         } else {
             Log.d("BusTO", "Same bus stop, accessing existing fragment");
             arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(primaryFrameLayout);
         }
         // DO NOT CALL `setListAdapter` ever on arrivals fragment
         arrivalsFragment.updateFragmentData(p);
         // enable fragment auto refresh
         arrivalsFragment.setReloadOnResume(true);
 
         listenerMain.hideKeyboard();
         toggleSpinner(false);
     }
 
     /**
      * Called when you need to display the results of a search of stops
      * @param resultList the List of stops found
      * @param query String queried
      */
     public void createStopListFragment(List<Stop> resultList, String query, boolean addToBackStack){
         listenerMain.hideKeyboard();
         StopListFragment listfragment = StopListFragment.newInstance(query);
         if(managerWeakRef.get()==null || shouldHaltAllActivities) {
             //SOMETHING WENT VERY WRONG
             Log.e(DEBUG_TAG, "We are asked for a new stop but we can't show anything");
             return;
         }
         attachFragmentToContainer(managerWeakRef.get(),listfragment,
                 new AttachParameters("search_"+query, false,addToBackStack));
         listfragment.setStopList(resultList);
+        listenerMain.readyGUIfor(FragmentKind.STOPS);
         toggleSpinner(false);
 
     }
 
     /**
      * Wrapper for toggleSpinner in Activity
      * @param on new status of spinner system
      */
     public void toggleSpinner(boolean on){
         listenerMain.toggleSpinner(on);
     }
 
     /**
      * Attach a new fragment to a cointainer
      * @param fm the FragmentManager
      * @param fragment the Fragment
      * @param parameters attach parameters
      */
     protected void attachFragmentToContainer(FragmentManager fm,Fragment fragment, AttachParameters parameters){
         if(shouldHaltAllActivities) //nothing to do
             return;
         FragmentTransaction ft = fm.beginTransaction();
         int frameID;
         if(parameters.attachToSecondaryFrame && secondaryFrameLayout!=NO_FRAME)
            // ft.replace(secondaryFrameLayout,fragment,tag);
             frameID = secondaryFrameLayout;
         else frameID = primaryFrameLayout;
         switch (parameters.transaction){
             case REPLACE:
                 ft.replace(frameID,fragment,parameters.tag);
 
         }
         if (parameters.addToBackStack)
             ft.addToBackStack("state_"+parameters.tag);
         ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
         if(!fm.isDestroyed() && !shouldHaltAllActivities)
             ft.commit();
         //fm.executePendingTransactions();
     }
 
     public synchronized void setBlockAllActivities(boolean shouldI) {
         this.shouldHaltAllActivities = shouldI;
     }
 
     public void stopLastRequestIfNeeded(){
         if(lastTaskRef == null) return;
         AsyncDataDownload task = lastTaskRef.get();
         if(task!=null){
             task.cancel(false);
         }
     }
 
     /**
      * Wrapper to show the errors/status that happened
      * @param res result from Fetcher
      */
     public void showErrorMessage(Fetcher.Result res){
         //TODO: implement a common set of errors for all fragments
         switch (res){
             case OK:
                 break;
             case CLIENT_OFFLINE:
                 showToastMessage(R.string.network_error, true);
                 break;
             case SERVER_ERROR:
                 if (utils.isConnected(context)) {
                     showToastMessage(R.string.parsing_error, true);
                 } else {
                     showToastMessage(R.string.network_error, true);
                 }
             case PARSER_ERROR:
             default:
                 showShortToast(R.string.internal_error);
                 break;
             case QUERY_TOO_SHORT:
                 showShortToast(R.string.query_too_short);
                 break;
             case EMPTY_RESULT_SET:
                 showShortToast(R.string.no_bus_stop_have_this_name);
                 break;
         }
     }
 
     public void showToastMessage(int messageID, boolean short_lenght) {
         final int length = short_lenght ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG;
         if (context != null)
         Toast.makeText(context, messageID, length).show();
     }
     private void showShortToast(int messageID){
         showToastMessage(messageID, true);
     }
 
     enum Transaction{
         REPLACE,
     }
     static final class AttachParameters {
         String tag;
         boolean attachToSecondaryFrame;
         Transaction transaction;
         boolean addToBackStack;
 
         public AttachParameters(String tag, boolean attachToSecondaryFrame, Transaction transaction, boolean addToBackStack) {
             this.tag = tag;
             this.attachToSecondaryFrame = attachToSecondaryFrame;
             this.transaction = transaction;
             this.addToBackStack = addToBackStack;
         }
 
         public AttachParameters(String tag, boolean attachToSecondaryFrame, boolean addToBackStack) {
             this.tag = tag;
             this.attachToSecondaryFrame = attachToSecondaryFrame;
             this.addToBackStack = addToBackStack;
             this.transaction = Transaction.REPLACE;
         }
     }
 }
diff --git a/src/it/reyboz/bustorino/fragments/MainScreenFragment.java b/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
index 50828b5..6f76a9c 100644
--- a/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
+++ b/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
@@ -1,717 +1,724 @@
 
 package it.reyboz.bustorino.fragments;
 
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.location.Criteria;
 import android.location.Location;
 import android.os.Build;
 import android.os.Bundle;
 
 import androidx.activity.result.ActivityResultCallback;
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appcompat.widget.AppCompatImageButton;
 import androidx.core.app.ActivityCompat;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentTransaction;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
 import android.os.Handler;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ImageButton;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import com.google.android.material.floatingactionbutton.FloatingActionButton;
 import com.google.zxing.integration.android.IntentIntegrator;
 
 import java.util.Map;
 
 import it.reyboz.bustorino.R;
 import it.reyboz.bustorino.backend.*;
 import it.reyboz.bustorino.middleware.AppLocationManager;
 import it.reyboz.bustorino.middleware.AsyncDataDownload;
 import it.reyboz.bustorino.util.LocationCriteria;
 import it.reyboz.bustorino.util.Permissions;
 
 import static it.reyboz.bustorino.util.Permissions.LOCATION_PERMISSIONS;
 import static it.reyboz.bustorino.util.Permissions.LOCATION_PERMISSION_GIVEN;
 
 
 /**
  * A simple {@link Fragment} subclass.
  * Use the {@link MainScreenFragment#newInstance} factory method to
  * create an instance of this fragment.
  */
 public class MainScreenFragment extends BaseFragment implements  FragmentListenerMain{
 
 
     private static final String OPTION_SHOW_LEGEND = "show_legend";
     private static final String SAVED_FRAGMENT="saved_fragment";
 
     private static final String DEBUG_TAG = "BusTO - MainFragment";
 
     public final static String FRAGMENT_TAG = "MainScreenFragment";
 
     /// UI ELEMENTS //
     private ImageButton addToFavorites;
     private FragmentHelper fragmentHelper;
     private SwipeRefreshLayout swipeRefreshLayout;
     private EditText busStopSearchByIDEditText;
     private EditText busStopSearchByNameEditText;
     private ProgressBar progressBar;
     private TextView howDoesItWorkTextView;
     private Button hideHintButton;
     private MenuItem actionHelpMenuItem;
     private FloatingActionButton floatingActionButton;
 
     private boolean setupOnAttached = true;
     private boolean suppressArrivalsReload = false;
     //private Snackbar snackbar;
     /*
      * Search mode
      */
     private static final int SEARCH_BY_NAME = 0;
     private static final int SEARCH_BY_ID = 1;
     private static final int SEARCH_BY_ROUTE = 2; // TODO: implement this -- https://gitpull.it/T12
     private int searchMode;
     //private ImageButton addToFavorites;
     private final ArrivalsFetcher[] arrivalsFetchers = new ArrivalsFetcher[]{new FiveTAPIFetcher(), new GTTJSONFetcher(), new FiveTScraperFetcher()};
     //// HIDDEN BUT IMPORTANT ELEMENTS ////
     FragmentManager fragMan;
     Handler mainHandler;
     private final Runnable refreshStop = new Runnable() {
         public void run() {
             if(getContext() == null) return;
             if (fragMan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) {
                 ArrivalsFragment fragment = (ArrivalsFragment) fragMan.findFragmentById(R.id.resultFrame);
                 if (fragment == null){
                     //we create a new fragment, which is WRONG
                     new AsyncDataDownload(fragmentHelper, arrivalsFetchers,getContext()).execute();
                 } else{
                     String stopName = fragment.getStopID();
 
                     new AsyncDataDownload(fragmentHelper, fragment.getCurrentFetchersAsArray(), getContext()).execute(stopName);
                 }
             } else //we create a new fragment, which is WRONG
                 new AsyncDataDownload(fragmentHelper, arrivalsFetchers, getContext()).execute();
         }
     };
 
     /// LOCATION STUFF ///
     boolean pendingNearbyStopsRequest = false;
     boolean locationPermissionGranted, locationPermissionAsked = false;
     AppLocationManager locationManager;
 
 
     private final LocationCriteria cr = new LocationCriteria(2000, 10000);
     //Location
     private AppLocationManager.LocationRequester requester = new AppLocationManager.LocationRequester() {
         @Override
         public void onLocationChanged(Location loc) {
 
         }
 
         @Override
         public void onLocationStatusChanged(int status) {
 
             if(status == AppLocationManager.LOCATION_GPS_AVAILABLE && !isNearbyFragmentShown()){
                 //request Stops
                 pendingNearbyStopsRequest = false;
                 if (getContext()!= null)
                     mainHandler.post(new NearbyStopsRequester(getContext(), cr));
             }
         }
 
         @Override
         public long getLastUpdateTimeMillis() {
             return 50;
         }
 
         @Override
         public LocationCriteria getLocationCriteria() {
             return cr;
         }
 
         @Override
         public void onLocationProviderAvailable() {
             //Log.w(DEBUG_TAG, "pendingNearbyStopRequest: "+pendingNearbyStopsRequest);
             if(!isNearbyFragmentShown() && getContext()!=null){
                 pendingNearbyStopsRequest = false;
                 mainHandler.post(new NearbyStopsRequester(getContext(), cr));
             }
         }
 
         @Override
         public void onLocationDisabled() {
 
         }
     };
     private final ActivityResultLauncher<String[]> requestPermissionLauncher =
             registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
                 @Override
                 public void onActivityResult(Map<String, Boolean> result) {
                     if(result==null || result.get(Manifest.permission.ACCESS_COARSE_LOCATION) == null
                     ||result.get(Manifest.permission.ACCESS_FINE_LOCATION) ) return;
 
                     if(result.get(Manifest.permission.ACCESS_COARSE_LOCATION) && result.get(Manifest.permission.ACCESS_FINE_LOCATION)){
                         locationPermissionGranted = true;
                         Log.w(DEBUG_TAG, "Starting position");
                         if (mListener!= null && getContext()!=null){
                             if (locationManager==null)
                                 locationManager = AppLocationManager.getInstance(getContext());
                             locationManager.addLocationRequestFor(requester);
                         }
                     }
                 }
             });
 
 
     //// ACTIVITY ATTACHED (LISTENER ///
     private CommonFragmentListener mListener;
 
     private String pendingStopID = null;
 
     public MainScreenFragment() {
         // Required empty public constructor
     }
 
 
     public static MainScreenFragment newInstance() {
         MainScreenFragment fragment = new MainScreenFragment();
         Bundle args = new Bundle();
         //args.putString(ARG_PARAM1, param1);
         //args.putString(ARG_PARAM2, param2);
         fragment.setArguments(args);
         return fragment;
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         if (getArguments() != null) {
             //do nothing
         }
     }
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
         // Inflate the layout for this fragment
         View root = inflater.inflate(R.layout.fragment_main_screen, container, false);
         addToFavorites = (ImageButton) root.findViewById(R.id.addToFavorites);
         busStopSearchByIDEditText = root.findViewById(R.id.busStopSearchByIDEditText);
         busStopSearchByNameEditText = root.findViewById(R.id.busStopSearchByNameEditText);
         progressBar = root.findViewById(R.id.progressBar);
         howDoesItWorkTextView = root.findViewById(R.id.howDoesItWorkTextView);
         hideHintButton = root.findViewById(R.id.hideHintButton);
         swipeRefreshLayout = root.findViewById(R.id.listRefreshLayout);
         floatingActionButton = root.findViewById(R.id.floatingActionButton);
         busStopSearchByIDEditText.setSelectAllOnFocus(true);
         busStopSearchByIDEditText
                 .setOnEditorActionListener((v, actionId, event) -> {
                     // IME_ACTION_SEARCH alphabetical option
                     if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                         onSearchClick(v);
                         return true;
                     }
                     return false;
                 });
         busStopSearchByNameEditText
                 .setOnEditorActionListener((v, actionId, event) -> {
                     // IME_ACTION_SEARCH alphabetical option
                     if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                         onSearchClick(v);
                         return true;
                     }
                     return false;
                 });
 
         swipeRefreshLayout
                 .setOnRefreshListener(() -> mainHandler.post(refreshStop));
         swipeRefreshLayout.setColorSchemeResources(R.color.blue_500, R.color.orange_500);
 
         floatingActionButton.setOnClickListener((this::onToggleKeyboardLayout));
         hideHintButton.setOnClickListener(this::onHideHint);
 
         AppCompatImageButton qrButton = root.findViewById(R.id.QRButton);
         qrButton.setOnClickListener(this::onQRButtonClick);
 
         AppCompatImageButton searchButton = root.findViewById(R.id.searchButton);
         searchButton.setOnClickListener(this::onSearchClick);
 
         // Fragment stuff
         fragMan = getChildFragmentManager();
         fragMan.addOnBackStackChangedListener(() -> Log.d("BusTO Main Fragment", "BACK STACK CHANGED"));
 
         fragmentHelper = new FragmentHelper(this, getChildFragmentManager(), getContext(), R.id.resultFrame);
         setSearchModeBusStopID();
 
 
         cr.setAccuracy(Criteria.ACCURACY_FINE);
         cr.setAltitudeRequired(false);
         cr.setBearingRequired(false);
         cr.setCostAllowed(true);
         cr.setPowerRequirement(Criteria.NO_REQUIREMENT);
 
        locationManager = AppLocationManager.getInstance(getContext());
 
         Log.d(DEBUG_TAG, "OnCreateView, savedInstanceState null: "+(savedInstanceState==null));
 
 
 
         return root;
     }
 
     @Override
     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         Log.d(DEBUG_TAG, "onViewCreated, SwipeRefreshLayout visible: "+(swipeRefreshLayout.getVisibility()==View.VISIBLE));
         Log.d(DEBUG_TAG, "Setup on attached: "+setupOnAttached);
         //Restore instance state
         if (savedInstanceState!=null){
             Fragment fragment = getChildFragmentManager().getFragment(savedInstanceState, SAVED_FRAGMENT);
             if (fragment!=null){
                 getChildFragmentManager().beginTransaction().add(R.id.resultFrame, fragment).commit();
                 setupOnAttached = false;
             }
         }
         if (getChildFragmentManager().findFragmentById(R.id.resultFrame)!= null){
             swipeRefreshLayout.setVisibility(View.VISIBLE);
         }
     }
 
     @Override
     public void onSaveInstanceState(@NonNull Bundle outState) {
         super.onSaveInstanceState(outState);
         Fragment fragment = getChildFragmentManager().findFragmentById(R.id.resultFrame);
         if (fragment!=null)
         getChildFragmentManager().putFragment(outState, SAVED_FRAGMENT, fragment);
         fragmentHelper.setBlockAllActivities(true);
     }
 
     public void setSuppressArrivalsReload(boolean value){
        suppressArrivalsReload = value;
         // we have to suppress the reloading of the (possible) ArrivalsFragment
         /*if(value) {
             Fragment fragment = getChildFragmentManager().findFragmentById(R.id.resultFrame);
             if (fragment instanceof ArrivalsFragment) {
                 ArrivalsFragment frag = (ArrivalsFragment) fragment;
                 frag.setReloadOnResume(false);
             }
         }
 
          */
     }
 
     /**
      * Cancel the reload of the arrival times
      * because we are going to pop the fragment
      */
     public void cancelReloadArrivalsIfNeeded(){
         if(getContext()==null) return; //we are not attached
 
         //Fragment fr = getChildFragmentManager().findFragmentById(R.id.resultFrame);
         fragmentHelper.stopLastRequestIfNeeded();
         toggleSpinner(false);
     }
 
 
     @Override
     public void onAttach(@NonNull Context context) {
         super.onAttach(context);
         Log.d(DEBUG_TAG, "OnAttach called, setupOnAttach: "+setupOnAttached);
         mainHandler = new Handler();
         if (context instanceof CommonFragmentListener) {
             mListener = (CommonFragmentListener) context;
         } else {
             throw new RuntimeException(context
                     + " must implement CommonFragmentListener");
         }
         if (setupOnAttached) {
             if (pendingStopID==null)
             //We want the nearby bus stops!
             mainHandler.post(new NearbyStopsRequester(context, cr));
             else{
                 ///TODO: if there is a stop displayed, we need to hold the update
             }
 
             setupOnAttached = false;
         }
 
 
     }
     @Override
     public void onDetach() {
         super.onDetach();
         mListener = null;
     //    setupOnAttached = true;
     }
 
 
     @Override
     public void onResume() {
 
         final Context con = getContext();
         Log.w(DEBUG_TAG, "OnResume called");
         if (con != null) {
             if(locationManager==null)
                 locationManager = AppLocationManager.getInstance(con);
 
             if(Permissions.locationPermissionGranted(con)){
                 Log.d(DEBUG_TAG, "Location permission OK");
                 if(!locationManager.isRequesterRegistered(requester))
                     locationManager.addLocationRequestFor(requester);
             } else if(shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)){
                 //we have already asked for the location, and we should show an explanation in order
                 // to ask again (TODO)
                 //do nothing
             } else{
                 //request permission
                 requestPermissionLauncher.launch(Permissions.LOCATION_PERMISSIONS);
             }
         }
         else {
             Log.w(DEBUG_TAG, "Context is null at onResume");
         }
         super.onResume();
         // if we have a pending stopID request, do it
         Log.d(DEBUG_TAG, "Pending stop ID for arrivals: "+pendingStopID);
         //this is the second time we are attaching this fragment
         Log.d(DEBUG_TAG, "Waiting for new stop request: "+ suppressArrivalsReload);
         if (suppressArrivalsReload){
             // we have to suppress the reloading of the (possible) ArrivalsFragment
             Fragment fragment = getChildFragmentManager().findFragmentById(R.id.resultFrame);
             if (fragment instanceof ArrivalsFragment){
                 ArrivalsFragment frag = (ArrivalsFragment) fragment;
                 frag.setReloadOnResume(false);
             }
             suppressArrivalsReload = false;
         }
         if(pendingStopID!=null){
             requestArrivalsForStopID(pendingStopID);
             pendingStopID = null;
         }
         mListener.readyGUIfor(FragmentKind.MAIN_SCREEN_FRAGMENT);
 
         fragmentHelper.setBlockAllActivities(false);
     }
 
     @Override
     public void onPause() {
         //mainHandler = null;
         locationManager.removeLocationRequestFor(requester);
         super.onPause();
         fragmentHelper.setBlockAllActivities(true);
         fragmentHelper.stopLastRequestIfNeeded();
     }
 
 
     /*
     GUI METHODS
      */
     /**
      * QR scan button clicked
      *
      * @param v View QRButton clicked
      */
     public void onQRButtonClick(View v) {
         IntentIntegrator integrator = new IntentIntegrator(getActivity());
         integrator.initiateScan();
     }
     public void onHideHint(View v) {
 
         hideHints();
         setOption(OPTION_SHOW_LEGEND, false);
     }
     /**
      * OK this is pure shit
      *
      * @param v View clicked
      */
     public void onSearchClick(View v) {
         final StopsFinderByName[] stopsFinderByNames = new StopsFinderByName[]{new GTTStopsFetcher(), new FiveTStopsFetcher()};
         if (searchMode == SEARCH_BY_ID) {
             String busStopID = busStopSearchByIDEditText.getText().toString();
             requestArrivalsForStopID(busStopID);
         } else { // searchMode == SEARCH_BY_NAME
             String query = busStopSearchByNameEditText.getText().toString();
-            //new asyncWgetBusStopSuggestions(query, stopsDB, StopsFindersByNameRecursionHelper);
-            if(getContext()!=null)
-                new AsyncDataDownload(fragmentHelper, stopsFinderByNames, getContext()).execute(query);
+            query = query.trim();
+            if(getContext()!=null) {
+                if (query.length() < 1) {
+                    Toast.makeText(getContext(), R.string.insert_bus_stop_name_error, Toast.LENGTH_SHORT).show();
+                } else if(query.length()< 3){
+                    Toast.makeText(getContext(), R.string.query_too_short, Toast.LENGTH_SHORT).show();
+                }
+                else
+                    new AsyncDataDownload(fragmentHelper, stopsFinderByNames, getContext()).execute(query);
+            }
         }
     }
 
     public void onToggleKeyboardLayout(View v) {
 
         if (searchMode == SEARCH_BY_NAME) {
             setSearchModeBusStopID();
             if (busStopSearchByIDEditText.requestFocus()) {
                 showKeyboard();
             }
         } else { // searchMode == SEARCH_BY_ID
             setSearchModeBusStopName();
             if (busStopSearchByNameEditText.requestFocus()) {
                 showKeyboard();
             }
         }
 
     }
     @Override
     public void enableRefreshLayout(boolean yes) {
         swipeRefreshLayout.setEnabled(yes);
     }
 
     ////////////////////////////////////// GUI HELPERS /////////////////////////////////////////////
     public void showKeyboard() {
         if(getActivity() == null) return;
         InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
         View view = searchMode == SEARCH_BY_ID ? busStopSearchByIDEditText : busStopSearchByNameEditText;
         imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
     }
 
     private void setSearchModeBusStopID() {
         searchMode = SEARCH_BY_ID;
         busStopSearchByNameEditText.setVisibility(View.GONE);
         busStopSearchByNameEditText.setText("");
         busStopSearchByIDEditText.setVisibility(View.VISIBLE);
         floatingActionButton.setImageResource(R.drawable.alphabetical);
     }
 
     private void setSearchModeBusStopName() {
         searchMode = SEARCH_BY_NAME;
         busStopSearchByIDEditText.setVisibility(View.GONE);
         busStopSearchByIDEditText.setText("");
         busStopSearchByNameEditText.setVisibility(View.VISIBLE);
         floatingActionButton.setImageResource(R.drawable.numeric);
     }
     protected boolean isNearbyFragmentShown(){
         Fragment fragment = getChildFragmentManager().findFragmentByTag(NearbyStopsFragment.FRAGMENT_TAG);
         return (fragment!= null && fragment.isVisible());
     }
 
     /**
      * Having that cursor at the left of the edit text makes me cancer.
      *
      * @param busStopID bus stop ID
      */
     private void setBusStopSearchByIDEditText(String busStopID) {
         busStopSearchByIDEditText.setText(busStopID);
         busStopSearchByIDEditText.setSelection(busStopID.length());
     }
 
     private void showHints() {
         howDoesItWorkTextView.setVisibility(View.VISIBLE);
         hideHintButton.setVisibility(View.VISIBLE);
         //actionHelpMenuItem.setVisible(false);
     }
 
     private void hideHints() {
         howDoesItWorkTextView.setVisibility(View.GONE);
         hideHintButton.setVisibility(View.GONE);
         //actionHelpMenuItem.setVisible(true);
     }
 
     @Override
     public void toggleSpinner(boolean enable) {
         if (enable) {
             //already set by the RefreshListener when needed
             //swipeRefreshLayout.setRefreshing(true);
             progressBar.setVisibility(View.VISIBLE);
         } else {
             swipeRefreshLayout.setRefreshing(false);
             progressBar.setVisibility(View.GONE);
         }
     }
 
 
     private void prepareGUIForBusLines() {
         swipeRefreshLayout.setEnabled(true);
         swipeRefreshLayout.setVisibility(View.VISIBLE);
         //actionHelpMenuItem.setVisible(true);
     }
 
     private void prepareGUIForBusStops() {
         swipeRefreshLayout.setEnabled(false);
         swipeRefreshLayout.setVisibility(View.VISIBLE);
         //actionHelpMenuItem.setVisible(false);
     }
 
     void showNearbyStopsFragment(){
         swipeRefreshLayout.setVisibility(View.VISIBLE);
         NearbyStopsFragment fragment = NearbyStopsFragment.newInstance(NearbyStopsFragment.TYPE_STOPS);
         Fragment oldFrag = fragMan.findFragmentById(R.id.resultFrame);
         FragmentTransaction ft = fragMan.beginTransaction();
         if (oldFrag != null)
             ft.remove(oldFrag);
         ft.add(R.id.resultFrame, fragment, NearbyStopsFragment.FRAGMENT_TAG);
         ft.commit();
     }
 
 
     @Override
     public void showFloatingActionButton(boolean yes) {
         mListener.showFloatingActionButton(yes);
     }
 
     /**
      * This provides a temporary fix to make the transition
      * to a single asynctask go smoother
      *
      * @param fragmentType the type of fragment created
      */
     @Override
     public void readyGUIfor(FragmentKind fragmentType) {
 
         hideKeyboard();
 
         //if we are getting results, already, stop waiting for nearbyStops
         if (pendingNearbyStopsRequest && (fragmentType == FragmentKind.ARRIVALS || fragmentType == FragmentKind.STOPS)) {
             locationManager.removeLocationRequestFor(requester);
             pendingNearbyStopsRequest = false;
         }
 
         if (fragmentType == null) Log.e("ActivityMain", "Problem with fragmentType");
         else
             switch (fragmentType) {
                 case ARRIVALS:
                     prepareGUIForBusLines();
                     if (getOption(OPTION_SHOW_LEGEND, true)) {
                         showHints();
                     }
                     break;
                 case STOPS:
                     prepareGUIForBusStops();
                     break;
                 default:
                     Log.d(DEBUG_TAG, "Fragment type is unknown");
                     return;
             }
         // Shows hints
 
 
     }
 
     @Override
     public void showMapCenteredOnStop(Stop stop) {
         if(mListener!=null) mListener.showMapCenteredOnStop(stop);
     }
 
     /**
      * Main method for stops requests
      * @param ID the Stop ID
      */
     @Override
     public void requestArrivalsForStopID(String ID) {
         if (!isResumed()){
             //defer request
             pendingStopID = ID;
             Log.d(DEBUG_TAG, "Deferring update for stop "+ID);
             return;
         }
         final boolean delayedRequest = !(pendingStopID==null);
         final FragmentManager framan = getChildFragmentManager();
         if (getContext()==null){
             Log.e(DEBUG_TAG, "Asked for arrivals with null context");
             return;
         }
         if (ID == null || ID.length() <= 0) {
             // we're still in UI thread, no need to mess with Progress
             showToastMessage(R.string.insert_bus_stop_number_error, true);
             toggleSpinner(false);
         } else  if (framan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) {
             ArrivalsFragment fragment = (ArrivalsFragment) framan.findFragmentById(R.id.resultFrame);
             if (fragment != null && fragment.getStopID() != null && fragment.getStopID().equals(ID)){
                 // Run with previous fetchers
                 //fragment.getCurrentFetchers().toArray()
                 new AsyncDataDownload(fragmentHelper,fragment.getCurrentFetchersAsArray(), getContext()).execute(ID);
             } else{
                 new AsyncDataDownload(fragmentHelper, arrivalsFetchers, getContext()).execute(ID);
             }
         }
         else {
             new AsyncDataDownload(fragmentHelper,arrivalsFetchers, getContext()).execute(ID);
             Log.d(DEBUG_TAG, "Started search for arrivals of stop " + ID);
         }
     }
     /////////// LOCATION METHODS //////////
 
     /*
     private void startStopRequest(String provider) {
         Log.d(DEBUG_TAG, "Provider " + provider + " got enabled");
         if (locmgr != null && mainHandler != null && pendingNearbyStopsRequest && locmgr.getProvider(provider).meetsCriteria(cr)) {
 
         }
     }
 
      */
 
     /**
      * Run location requests separately and asynchronously
      */
     class NearbyStopsRequester implements Runnable {
         Context appContext;
         Criteria cr;
 
         public NearbyStopsRequester(Context appContext, Criteria criteria) {
             this.appContext = appContext.getApplicationContext();
             this.cr = criteria;
         }
 
         @Override
         public void run() {
             if(isNearbyFragmentShown()) {
                 //nothing to do
                 Log.w(DEBUG_TAG, "launched nearby fragment request but we already are showing");
                 return;
             }
 
             final boolean isOldVersion = Build.VERSION.SDK_INT < Build.VERSION_CODES.M;
             final boolean noPermission = ActivityCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                     ActivityCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED;
 
             //if we don't have the permission, we have to ask for it, if we haven't
             // asked too many times before
             if (noPermission) {
                 if (!isOldVersion) {
                     pendingNearbyStopsRequest = true;
                     //Permissions.assertLocationPermissions(appContext,getActivity());
                     requestPermissionLauncher.launch(LOCATION_PERMISSIONS);
                     Log.w(DEBUG_TAG, "Cannot get position: Asking permission, noPositionFromSys: " + noPermission);
                     return;
                 } else {
                     Toast.makeText(appContext, "Asked for permission position too many times", Toast.LENGTH_LONG).show();
                 }
             } else setOption(LOCATION_PERMISSION_GIVEN, true);
 
             AppLocationManager appLocationManager = AppLocationManager.getInstance(appContext);
             final boolean haveProviders = appLocationManager.anyLocationProviderMatchesCriteria(cr);
             if (haveProviders
                     && fragmentHelper.getLastSuccessfullySearchedBusStop() == null
                     && !fragMan.isDestroyed()) {
                 //Go ahead with the request
                 Log.d("mainActivity", "Recreating stop fragment");
                 showNearbyStopsFragment();
                 pendingNearbyStopsRequest = false;
             } else if(!haveProviders){
                 Log.e(DEBUG_TAG, "NO PROVIDERS FOR POSITION");
             }
 
         }
     }
 
 }
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/middleware/AsyncDataDownload.java b/src/it/reyboz/bustorino/middleware/AsyncDataDownload.java
index b3f5b09..bac7eab 100644
--- a/src/it/reyboz/bustorino/middleware/AsyncDataDownload.java
+++ b/src/it/reyboz/bustorino/middleware/AsyncDataDownload.java
@@ -1,363 +1,382 @@
 /*
 	BusTO (middleware)
     Copyright (C) 2018 Fabio Mazza
 
     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, see <http://www.gnu.org/licenses/>.
  */
 package it.reyboz.bustorino.middleware;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.SQLException;
 import android.net.Uri;
 import android.os.AsyncTask;
 
 import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+
 import android.util.Log;
+import android.widget.Toast;
 
+import it.reyboz.bustorino.R;
 import it.reyboz.bustorino.backend.*;
 import it.reyboz.bustorino.data.AppDataProvider;
 import it.reyboz.bustorino.data.NextGenDB;
 import it.reyboz.bustorino.fragments.FragmentHelper;
 import it.reyboz.bustorino.data.NextGenDB.Contract.*;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.Calendar;
 
 /**
  * This should be used to download data, but not to display it
  */
 public class AsyncDataDownload extends AsyncTask<String, Fetcher.Result,Object>{
 
     private static final String TAG = "BusTO-DataDownload";
     private static final String DEBUG_TAG = TAG;
     private boolean failedAll = false;
 
     private final AtomicReference<Fetcher.Result> res;
     private final RequestType t;
     private String query;
     WeakReference<FragmentHelper> helperRef;
     private final ArrayList<Thread> otherActivities = new ArrayList<>();
     private final Fetcher[] theFetchers;
     private Context context;
     private final boolean replaceFragment;
 
 
     public AsyncDataDownload(FragmentHelper fh, @NonNull Fetcher[] fetchers, Context context) {
         RequestType type;
         helperRef = new WeakReference<>(fh);
         fh.setLastTaskRef(new WeakReference<>(this));
         res = new AtomicReference<>();
         this.context = context.getApplicationContext();
         this.replaceFragment = true;
 
         theFetchers = fetchers;
         if (theFetchers.length < 1){
             throw new IllegalArgumentException("You have to put at least one Fetcher, idiot!");
         }
         if (theFetchers[0] instanceof ArrivalsFetcher){
             type = RequestType.ARRIVALS;
         } else if (theFetchers[0] instanceof StopsFinderByName){
             type = RequestType.STOPS;
         } else{
             type = null;
         }
         t = type;
 
     }
 
     @Override
     protected Object doInBackground(String... params) {
         RecursionHelper<Fetcher> r = new RecursionHelper<>(theFetchers);
         boolean success=false;
         Object result;
         FragmentHelper fh = helperRef.get();
+        ArrayList<Fetcher.Result> results = new ArrayList<>(theFetchers.length);
         //If the FragmentHelper is null, that means the activity doesn't exist anymore
         if (fh == null){
             return null;
         }
 
         //Log.d(TAG,"refresh layout reference is: "+fh.isRefreshLayoutReferenceTrue());
         while(r.valid()) {
             if(this.isCancelled()) {
                 return null;
             }
             //get the data from the fetcher
             switch (t){
                 case ARRIVALS:
                     ArrivalsFetcher f = (ArrivalsFetcher) r.getAndMoveForward();
                     Log.d(TAG,"Using the ArrivalsFetcher: "+f.getClass());
 
                     Stop lastSearchedBusStop = fh.getLastSuccessfullySearchedBusStop();
                     Palina p;
                     String stopID;
                     if(params.length>0)
                         stopID=params[0]; //(it's a Palina)
                     else if(lastSearchedBusStop!=null)
                         stopID = lastSearchedBusStop.ID; //(it's a Palina)
                     else {
                         publishProgress(Fetcher.Result.QUERY_TOO_SHORT);
                         return null;
                     }
                     //Skip the FiveTAPIFetcher for the Metro Stops because it shows incomprehensible arrival times
                     try {
                         if (f instanceof FiveTAPIFetcher && Integer.parseInt(stopID) >= 8200)
                             continue;
                     } catch (NumberFormatException ex){
                         Log.e(DEBUG_TAG, "The stop number is not a valid integer, expect failures");
                     }
                     p= f.ReadArrivalTimesAll(stopID,res);
                     publishProgress(res.get());
                     //if (res.get()!= Fetcher.Result.OK)
                     Log.d(DEBUG_TAG, "Arrivals fetcher: "+f+"\n\tProgress: "+res.get());
 
 
                     if(f instanceof FiveTAPIFetcher){
                         AtomicReference<Fetcher.Result> gres = new AtomicReference<>();
                         List<Route> branches = ((FiveTAPIFetcher) f).getDirectionsForStop(stopID,gres);
                         Log.d(DEBUG_TAG, "FiveTArrivals fetcher: "+f+"\n\tDetails req: "+gres.get());
                         if(gres.get() == Fetcher.Result.OK){
                             p.addInfoFromRoutes(branches);
                             Thread t = new Thread(new BranchInserter(branches, context));
                             t.start();
                             otherActivities.add(t);
 
                         }
                         //put updated values into Database
                     }
 
                     if(lastSearchedBusStop != null && res.get()== Fetcher.Result.OK) {
                         // check that we don't have the same stop
                         if(lastSearchedBusStop.ID.equals(p.ID)) {
                             // searched and it's the same
                             String sn = lastSearchedBusStop.getStopDisplayName();
                             if(sn != null) {
                                 // "merge" Stop over Palina and we're good to go
                                 p.mergeNameFrom(lastSearchedBusStop);
                             }
                         }
                     }
                     p.mergeDuplicateRoutes(0);
                     if(p.queryAllRoutes().size() == 0)
                         //skip the rest and go to the next fetcher
                         continue;
                     result = p;
                     //TODO: find a way to avoid overloading the user with toasts
                     break;
                 case STOPS:
                     StopsFinderByName finder = (StopsFinderByName) r.getAndMoveForward();
 
                     List<Stop> resultList= finder.FindByName(params[0], this.res); //it's a List<Stop>
                     Log.d(TAG,"Using the StopFinderByName: "+finder.getClass());
                     query =params[0];
                     result = resultList; //dummy result
+                    Log.d(DEBUG_TAG, "Result: "+res.get()+", "+resultList.size()+" stops");
                     break;
                 default:
                     result = null;
             }
             //find if it went well
+            results.add(res.get());
             if(res.get()== Fetcher.Result.OK) {
                 //wait for other threads to finish
                 for(Thread t: otherActivities){
                     try {
                         t.join();
                     } catch (InterruptedException e) {
                         //do nothing
                     }
                 }
                 return result;
             }
 
         }
+        boolean emptyResults = true;
+        for (Fetcher.Result re: results){
+            if (!re.equals(Fetcher.Result.EMPTY_RESULT_SET)) {
+                emptyResults = false;
+                break;
+            }
+        }
+        if(emptyResults){
+            if(t==RequestType.STOPS)
+                publishProgress(Fetcher.Result.EMPTY_RESULT_SET);
+        }
         //at this point, we are sure that the result has been negative
         failedAll=true;
 
         return null;
     }
 
     @Override
     protected void onProgressUpdate(Fetcher.Result... values) {
         FragmentHelper fh = helperRef.get();
         if (fh!=null)
         for (Fetcher.Result r : values){
             //TODO: make Toast
             fh.showErrorMessage(r);
         }
         else {
             Log.w(TAG,"We had to show some progress but activity was destroyed");
         }
     }
 
     @Override
     protected void onPostExecute(Object o) {
         FragmentHelper fh = helperRef.get();
 
         if(failedAll || o == null || fh == null){
             //everything went bad
             if(fh!=null) fh.toggleSpinner(false);
             cancel(true);
             //TODO: send message here
             return;
         }
 
         if(isCancelled()) return;
 
         switch (t){
             case ARRIVALS:
                 Palina palina = (Palina) o;
                 fh.createOrUpdateStopFragment(palina, replaceFragment);
                 break;
             case STOPS:
                 //this should never be a problem
                 if(!(o instanceof List<?>)){
                     throw new IllegalStateException();
                 }
                 List<?> list = (List<?>) o;
                 if (list.size() ==0) return;
                 Object firstItem = list.get(0);
                 if(!(firstItem instanceof Stop)) return;
                 ArrayList<Stop> stops = new ArrayList<>();
                 for(Object x: list){
                     if(x instanceof Stop) stops.add((Stop) x);
+                    //Log.d(DEBUG_TAG, "Parsing Stop: "+x);
                 }
                 if(list.size() != stops.size()){
                     Log.w(DEBUG_TAG, "Wrong stop list size:\n incoming: "+
                             list.size()+" out: "+stops.size());
                 }
                 //List<Stop> stopList = (List<Stop>) list;
                 if(query!=null && !isCancelled()) {
                     fh.createStopListFragment(stops,query, replaceFragment);
                 } else Log.e(TAG,"QUERY NULL, COULD NOT CREATE FRAGMENT");
                 break;
             case DBUPDATE:
                 break;
         }
     }
 
     @Override
     protected void onCancelled() {
         FragmentHelper fh = helperRef.get();
         if (fh!=null) fh.toggleSpinner(false);
     }
 
     @Override
     protected void onPreExecute() {
         FragmentHelper fh = helperRef.get();
         if (fh!=null) fh.toggleSpinner(true);
     }
 
 
     public enum RequestType {
         ARRIVALS,STOPS,DBUPDATE
     }
 
     public static class BranchInserter implements Runnable{
         private final List<Route> routesToInsert;
 
         private final Context context;
         //private final NextGenDB nextGenDB;
 
         public BranchInserter(List<Route> routesToInsert,@NonNull Context con) {
             this.routesToInsert = routesToInsert;
             this.context = con.getApplicationContext();
             //nextGenDB = new NextGenDB(context);
         }
 
         @Override
         public void run() {
             final NextGenDB nextGenDB = new NextGenDB(context);
             //ContentValues[] values = new ContentValues[routesToInsert.size()];
             ArrayList<ContentValues> branchesValues = new ArrayList<>(routesToInsert.size()*4);
             ArrayList<ContentValues> connectionsVals = new ArrayList<>(routesToInsert.size()*4);
             long starttime,endtime;
             for (Route r:routesToInsert){
                 //if it has received an interrupt, stop
                 if(Thread.interrupted()) return;
                 //otherwise, build contentValues
                 final ContentValues cv = new ContentValues();
                 cv.put(BranchesTable.COL_BRANCHID,r.branchid);
                 cv.put(LinesTable.COLUMN_NAME,r.getName());
                 cv.put(BranchesTable.COL_DIRECTION,r.destinazione);
                 cv.put(BranchesTable.COL_DESCRIPTION,r.description);
                 for (int day :r.serviceDays) {
                     switch (day){
                         case Calendar.MONDAY:
                             cv.put(BranchesTable.COL_LUN,1);
                             break;
                         case Calendar.TUESDAY:
                             cv.put(BranchesTable.COL_MAR,1);
                             break;
                         case Calendar.WEDNESDAY:
                             cv.put(BranchesTable.COL_MER,1);
                             break;
                         case Calendar.THURSDAY:
                             cv.put(BranchesTable.COL_GIO,1);
                             break;
                         case Calendar.FRIDAY:
                             cv.put(BranchesTable.COL_VEN,1);
                             break;
                         case Calendar.SATURDAY:
                             cv.put(BranchesTable.COL_SAB,1);
                             break;
                         case Calendar.SUNDAY:
                             cv.put(BranchesTable.COL_DOM,1);
                             break;
                     }
                 }
                 if(r.type!=null) cv.put(BranchesTable.COL_TYPE, r.type.getCode());
                 cv.put(BranchesTable.COL_FESTIVO, r.festivo.getCode());
 
                 //values[routesToInsert.indexOf(r)] = cv;
                 branchesValues.add(cv);
                 if(r.getStopsList() != null)
                     for(int i=0; i<r.getStopsList().size();i++){
                         String stop = r.getStopsList().get(i);
                         final ContentValues connVal = new ContentValues();
                         connVal.put(ConnectionsTable.COLUMN_STOP_ID,stop);
                         connVal.put(ConnectionsTable.COLUMN_ORDER,i);
                         connVal.put(ConnectionsTable.COLUMN_BRANCH,r.branchid);
 
                         //add to global connVals
                         connectionsVals.add(connVal);
                 }
             }
             starttime = System.currentTimeMillis();
             ContentResolver cr = context.getContentResolver();
             try {
                 cr.bulkInsert(Uri.parse("content://" + AppDataProvider.AUTHORITY + "/branches/"), branchesValues.toArray(new ContentValues[0]));
                 endtime = System.currentTimeMillis();
                 Log.d("DataDownload", "Inserted branches, took " + (endtime - starttime) + " ms");
             } catch (SQLException exc){
                 Log.e("AsyncDataDownload","Inserting data: some error happened, aborting the database insert");
                 exc.printStackTrace();
                 return;
             }
 
             if (connectionsVals.size()>0) {
                 starttime = System.currentTimeMillis();
                 ContentValues[] valArr = connectionsVals.toArray(new ContentValues[0]);
                 Log.d("DataDownloadInsert", "inserting " + valArr.length + " connections");
                 int rows = nextGenDB.insertBatchContent(valArr, ConnectionsTable.TABLE_NAME);
                 endtime = System.currentTimeMillis();
                 Log.d("DataDownload", "Inserted connections found, took " + (endtime - starttime) + " ms, inserted " + rows + " rows");
             }
             nextGenDB.close();
         }
     }
 }