diff --git a/AndroidManifest.xml b/AndroidManifest.xml
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -22,7 +22,7 @@
         android:label="@string/app_name"
         android:theme="@style/AppTheme.NoActionBar">
         <activity
-                android:name=".ActivityMain"
+                android:name=".ActivityPrincipal"
                 android:label="@string/app_name"
                 android:screenOrientation="portrait"
                 android:windowSoftInputMode="adjustResize">
@@ -68,7 +68,7 @@
         <activity
                 android:name=".ActivityAbout"
                 android:label="@string/about"
-                android:parentActivityName=".ActivityMain"
+                android:parentActivityName=".ActivityPrincipal"
                 android:theme="@style/AboutTheme">
 
             <!-- API < 16: -->
@@ -99,8 +99,10 @@
                 android:value=".ActivityMain"/>
         </activity>
 
-        <activity android:name=".ActivityPrincipal"
-            android:label="Principal" >
+        <activity
+                android:name=".ActivityMain"
+                android:screenOrientation="portrait"
+                android:label="@string/app_name" >
         </activity>
 
         <provider
@@ -122,11 +124,11 @@
         <activity
                 android:name=".ActivitySettings"
                 android:label="@string/title_activity_settings"
-                android:parentActivityName=".ActivityMain"
+                android:parentActivityName=".ActivityPrincipal"
                 android:theme="@style/AppTheme">
             <meta-data
                     android:name="android.support.PARENT_ACTIVITY"
-                    android:value="it.reyboz.bustorino.ActivityMain"/>
+                    android:value="it.reyboz.bustorino.ActivityPrincipal"/>
         </activity>
     </application>
 
diff --git a/build.gradle b/build.gradle
--- a/build.gradle
+++ b/build.gradle
@@ -8,7 +8,7 @@
 
     dependencies {
 
-        classpath 'com.android.tools.build:gradle:4.0.2'
+        classpath 'com.android.tools.build:gradle:4.1.3'
     }
     ext {
         //libraries versions
@@ -92,7 +92,7 @@
         implementation "androidx.work:work-runtime:$work_version"
 
 
-        implementation 'com.google.android.material:material:1.3.0'
+        implementation "com.google.android.material:material:1.3.0"
 
 
         implementation 'org.jsoup:jsoup:1.13.1'
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Thu Oct 01 23:03:06 CEST 2020
+#Sat Apr 24 16:03:07 CEST 2021
 distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
 distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
+zipStoreBase=GRADLE_USER_HOME
diff --git a/res/layout/nav_header.xml b/res/layout/nav_header.xml
--- a/res/layout/nav_header.xml
+++ b/res/layout/nav_header.xml
@@ -1,19 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:orientation="vertical" android:layout_width="match_parent"
+    android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@color/grey_100"
+    android:background="@color/teal_300"
+    android:gravity="bottom"
+    android:minHeight="120dp"
+    android:orientation="vertical"
     android:padding="16dp"
-    android:theme="@style/ThemeOverlay.AppCompat.Dark"
-    android:gravity="bottom">
-
+    android:theme="@style/ThemeOverlay.AppCompat.Dark">
+    <!--
     <ImageView
         android:id="@+id/nav_img"
         android:layout_width="match_parent"
         android:layout_height="100dp"
         android:minHeight="40dp"
         app:srcCompat="@drawable/ic_mars2020" />
+        -->
 
     <TextView
 
@@ -21,10 +24,10 @@
 
         android:layout_height="wrap_content"
 
-        android:text="@string/app_name"
+        android:text="@string/app_name_full"
 
         android:textAppearance="@style/ThemeOverlay.AppCompat.Light"
-        android:textSize="20sp"
- />
+        android:textColor="#FFFFFF"
+        android:textSize="20sp" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -102,7 +102,7 @@
     <string name="settings_group_database">Gestione del database</string>
     <string name="settings_reset_database">Comincia aggiornamento manuale del database</string>
 
-
+    <string name="enable_position_message_map">Consenti l\'accesso alla posizione per mostrarla sulla mappa</string>
     <string name="enableGpsText">Abilitare il GPS</string>
     <string name="settings_search_radius">Raggio di ricerca</string>
     <string name="settings_experimental">Funzionalità sperimentali</string>
@@ -134,10 +134,11 @@
     <string name="too_many_permission_asks">Chiesto troppe volte per il permesso %1$s</string>
     <string name="permission_storage_maps_msg">Non si può usare questa funzionalità senza il permesso di archivio</string>
     <string name="storage_permission">di archivio</string>
-    <string name="message_crash">L\'app è andata in crash. Invia il report agli sviluppatori toccando OK.
-        \n Il report potrebbe contenere informazioni sulla tua configurazione del telefono, o sullo stato al momento del crash.
-        \n Tutte le informazioni sensibili nel report verranno utilizzate solo per scopi diagnostici dagli sviluppatori, e non verranno mai pubblicate e/o divulgate.</string>
-    <string name="acra_email_message">L\'applicazione è crashata, e il crash report è stato messo negli allegati. Se vuoi, descrivi cosa stavi facendo prima del crash: \n</string>
+    <string name="message_crash">Un bug ha fatto crashare l\'app!
+        \nPremi \"OK\" per inviare il report agli sviluppatori via email, così potranno scovare e risolvere il tuo bug!
+        \nIl report contiene piccole informazioni non sensibili sulla configurazione del tuo telefono e sullo stato dell\'app al momento del crash.
+    </string>
+    <string name="acra_email_message">L\'applicazione è crashata, e il crash report è stato messo negli allegati. Se vuoi, descrivi cosa stavi facendo prima che si interrompesse: \n</string>
     <string name="nav_arrivals_text">Arrivi</string>
     <string name="nav_map_text">Mappa</string>
     <string name="nav_favorites_text">Preferiti</string>
@@ -145,5 +146,7 @@
     <string name="drawer_close">Chiudi drawer</string>
     <string name="experiments">Esperimenti</string>
     <string name="donate_now">Offrici un caffè</string>
+    <string name="map">Mappa</string>
+    <string name="stop_search_view_title">Ricerca fermate</string>
 
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -14,5 +14,6 @@
     <color name="accent">#009688</color>-->
     <color name="metro_red">#DE0908</color>
     <color name="blue_extraurbano">#2060DD</color>
+    <color name="white">#FFFFFF</color>
 
 </resources>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2,6 +2,7 @@
 <resources>
 
     <string name="app_name" translatable="false">BusTO</string>
+    <string name="app_name_full" translatable="false">Libre BusTO</string>
     <string name="app_name_debug" translatable="false">BusTO Debug</string>
     <string name="app_description">You\'re using the latest in technology when it comes to respecting your privacy.
     </string>
@@ -115,6 +116,7 @@
     <string name="settings_group_database">Database management</string>
     <string name="settings_reset_database">Launch manual database update</string>
 
+    <string name="enable_position_message_map">Allow access to position to show it on the map</string>
     <string name="enableGpsText">Please enable GPS</string>
     <string name="database_update_message">Database update in progress&#8230;</string>
     <string name="bus_arriving_at">is arriving at</string>
@@ -147,10 +149,9 @@
     <string name="too_many_permission_asks">Asked for %1$s permission too many times</string>
     <string name="permission_storage_maps_msg">Cannot use the map with the storage permission!</string>
     <string name="storage_permission">storage</string>
-    <string name="message_crash">The application has crashed. If you want, you can send the send the report via email to
-        the developers by pressing \"OK\".
-        \n Note that sensitive information may be contained in the report, and if so, it will be only used for
-        diagnostic purposes by the developers, and never published.
+    <string name="message_crash">The application has crashed because you encountered a bug.
+        \nIf you want, you can help the developers by sending the crash report via email.
+        \nNote that no sensitive data is contained in the report, just small bits of info on your phone and app configuration/state.
     </string>
     <string name="acra_email_message">The application crashed and the crash report is in the attachments. Please
         describe what you were doing before the crash: \n
@@ -162,4 +163,6 @@
     <string name="drawer_close">Close navigation drawer</string>
     <string name="experiments">Experiments</string>
     <string name="donate_now">Buy us a coffee</string>
+    <string name="map">Map</string>
+    <string name="stop_search_view_title">Search by stop</string>
 </resources>
diff --git a/src/debug/AndroidManifest.xml b/src/debug/AndroidManifest.xml
--- a/src/debug/AndroidManifest.xml
+++ b/src/debug/AndroidManifest.xml
@@ -11,7 +11,7 @@
         tools:replace="android:label"
         >
         <activity
-                android:name=".ActivityMain"
+                android:name=".ActivityPrincipal"
                 android:label="@string/app_name_debug"
                 tools:replace="android:label"
         />
diff --git a/src/it/reyboz/bustorino/ActivityMain.java b/src/it/reyboz/bustorino/ActivityMain.java
--- a/src/it/reyboz/bustorino/ActivityMain.java
+++ b/src/it/reyboz/bustorino/ActivityMain.java
@@ -34,6 +34,7 @@
 import androidx.appcompat.app.ActionBar;
 import androidx.appcompat.widget.Toolbar;
 import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
 import androidx.preference.PreferenceManager;
 import androidx.work.BackoffPolicy;
 import androidx.work.Constraints;
@@ -654,21 +655,19 @@
 
         @Override
         public void run() {
-            final boolean canRunPosition = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || getOption(LOCATION_PERMISSION_GIVEN, false);
-            final boolean noPermission = ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
-                    ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED;
+            //final boolean canRunPosition = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || getOption(LOCATION_PERMISSION_GIVEN, false);
+            final boolean noPermission = ContextCompat.checkSelfPermission(getApplicationContext(),
+                    Manifest.permission.ACCESS_FINE_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 (!canRunPosition) {
+
                     pendingNearbyStopsRequest = true;
                     Permissions.assertLocationPermissions(getApplicationContext(),runningAct);
                     Log.w(DEBUG_TAG, "Cannot get position: Asking permission, noPositionFromSys: " + noPermission);
                     return;
-                } else {
-                    Toast.makeText(getApplicationContext(), "Asked for permission position too many times", Toast.LENGTH_LONG).show();
-                }
+
             } else setOption(LOCATION_PERMISSION_GIVEN, true);
 
             LocationManager locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
diff --git a/src/it/reyboz/bustorino/ActivityPrincipal.java b/src/it/reyboz/bustorino/ActivityPrincipal.java
--- a/src/it/reyboz/bustorino/ActivityPrincipal.java
+++ b/src/it/reyboz/bustorino/ActivityPrincipal.java
@@ -1,13 +1,16 @@
 package it.reyboz.bustorino;
 
+import android.Manifest;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.View;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
@@ -30,6 +33,7 @@
 import com.google.android.material.navigation.NavigationView;
 import com.google.android.material.snackbar.Snackbar;
 
+import java.util.Arrays;
 import java.util.concurrent.TimeUnit;
 
 import it.reyboz.bustorino.backend.Stop;
@@ -82,11 +86,32 @@
         drawerToggle.syncState();
         mDrawer.addDrawerListener(drawerToggle);
 
+        mDrawer.addDrawerListener(new DrawerLayout.DrawerListener() {
+            @Override
+            public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
+
+            }
+
+            @Override
+            public void onDrawerOpened(@NonNull View drawerView) {
+                hideKeyboard();
+            }
+
+            @Override
+            public void onDrawerClosed(@NonNull View drawerView) {
+
+            }
+
+            @Override
+            public void onDrawerStateChanged(int newState) {
+            }
+        });
+
+
         mNavView = findViewById(R.id.nvView);
 
         setupDrawerContent(mNavView);
 
-
         /// LEGACY CODE
         //---------------------------- START INTENT CHECK QUEUE ------------------------------------
 
@@ -135,8 +160,6 @@
             requestArrivalsForStopID(busStopID);
         }
         //Try (hopefully) database update
-
-
         PeriodicWorkRequest wr = new PeriodicWorkRequest.Builder(DBUpdateWorker.class, 1, TimeUnit.DAYS)
                 .setBackoffCriteria(BackoffPolicy.LINEAR, 30, TimeUnit.MINUTES)
                 .setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED)
@@ -189,6 +212,11 @@
         return new ActionBarDrawerToggle(this, mDrawer, toolbar, R.string.drawer_open,  R.string.drawer_close);
 
     }
+
+    /**
+     * Setup drawer actions
+     * @param navigationView the navigation view on which to set the callbacks
+     */
     private void setupDrawerContent(NavigationView navigationView) {
         navigationView.setNavigationItemSelectedListener(
                 menuItem -> {
@@ -213,7 +241,21 @@
                         return true;
                     } else if(menuItem.getItemId() == R.id.nav_map_item){
                         closeDrawerIfOpen();
-                        createAndShowMapFragment(null);
+                        final String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+                        int result = askForPermissionIfNeeded(permission, STORAGE_PERMISSION_REQ);
+                        switch (result) {
+                            case PERMISSION_OK:
+                                createAndShowMapFragment(null);
+                                break;
+                            case PERMISSION_ASKING:
+                                permissionDoneRunnables.put(permission,
+                                        () -> createAndShowMapFragment(null));
+                                break;
+                            case PERMISSION_NEG_CANNOT_ASK:
+                                String storage_perm = getString(R.string.storage_permission);
+                                String text = getString(R.string.too_many_permission_asks,  storage_perm);
+                                Toast.makeText(getApplicationContext(),text, Toast.LENGTH_LONG).show();
+                        }
                         return true;
                     }
                     //selectDrawerItem(menuItem);
@@ -256,6 +298,27 @@
         return super.onCreateOptionsMenu(menu);
     }
 
+    @Override
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+        if (requestCode==STORAGE_PERMISSION_REQ){
+            final String storagePerm = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+                Log.d(DEBUG_TAG, "Permissions check: " + Arrays.toString(permissions));
+
+                if (permissionDoneRunnables.containsKey(storagePerm)) {
+                    Runnable toRun = permissionDoneRunnables.get(storagePerm);
+                    if (toRun != null)
+                        toRun.run();
+                    permissionDoneRunnables.remove(storagePerm);
+                }
+            } else {
+                //permission denied
+                showToastMessage(R.string.permission_storage_maps_msg, false);
+            }
+        }
+    }
+
     @Override
     public boolean onOptionsItemSelected(@NonNull MenuItem item) {
 
@@ -387,21 +450,35 @@
         if (probableFragment!=null){
             probableFragment.readyGUIfor(fragmentType);
         }
+        int titleResId;
         switch (fragmentType){
             case MAP:
                 mNavView.setCheckedItem(R.id.nav_map_item);
+                titleResId = R.string.map;
                 break;
             case FAVORITES:
                 mNavView.setCheckedItem(R.id.nav_favorites_item);
+                titleResId = R.string.nav_favorites_text;
                 break;
             case ARRIVALS:
-            case NEARBY_STOPS:
+                titleResId = R.string.nav_arrivals_text;
+                mNavView.setCheckedItem(R.id.nav_arrivals);
+                break;
             case STOPS:
+                titleResId = R.string.stop_search_view_title;
+                mNavView.setCheckedItem(R.id.nav_arrivals);
+                break;
             case MAIN_SCREEN_FRAGMENT:
+            case NEARBY_STOPS:
             case NEARBY_ARRIVALS:
+                titleResId=R.string.app_name_full;
                 mNavView.setCheckedItem(R.id.nav_arrivals);
                 break;
+            default:
+                titleResId = 0;
         }
+        if(getSupportActionBar()!=null && titleResId!=0)
+            getSupportActionBar().setTitle(titleResId);
     }
 
     @Override
diff --git a/src/it/reyboz/bustorino/BustoApp.java b/src/it/reyboz/bustorino/BustoApp.java
--- a/src/it/reyboz/bustorino/BustoApp.java
+++ b/src/it/reyboz/bustorino/BustoApp.java
@@ -5,16 +5,20 @@
 
 import org.acra.ACRA;
 import org.acra.BuildConfig;
-import org.acra.annotation.AcraCore;
-import org.acra.annotation.AcraDialog;
-import org.acra.annotation.AcraMailSender;
+import org.acra.ReportField;
 import org.acra.config.CoreConfigurationBuilder;
 import org.acra.config.DialogConfigurationBuilder;
 import org.acra.config.MailSenderConfigurationBuilder;
 import org.acra.data.StringFormat;
 
+import static org.acra.ReportField.*;
+
 
 public class BustoApp extends Application {
+    private static final ReportField[] REPORT_FIELDS = {REPORT_ID, APP_VERSION_CODE, APP_VERSION_NAME,
+            PACKAGE_NAME, PHONE_MODEL, BRAND, PRODUCT, ANDROID_VERSION, BUILD_CONFIG, CUSTOM_DATA,
+            IS_SILENT, STACK_TRACE, INITIAL_CONFIGURATION, CRASH_CONFIGURATION, DISPLAY, USER_COMMENT,
+            USER_APP_START_DATE, USER_CRASH_DATE, LOGCAT, SHARED_PREFERENCES};
 
     @Override
     protected void attachBaseContext(Context base) {
@@ -30,7 +34,9 @@
         builder.getPluginConfigurationBuilder(DialogConfigurationBuilder.class).setResText(R.string.message_crash)
                 .setResTheme(R.style.AppTheme)
                 .setEnabled(true);
+        builder.setReportContent(REPORT_FIELDS);
         if (!it.reyboz.bustorino.BuildConfig.DEBUG)
             ACRA.init(this, builder);
+
     }
 }
diff --git a/src/it/reyboz/bustorino/backend/utils.java b/src/it/reyboz/bustorino/backend/utils.java
--- a/src/it/reyboz/bustorino/backend/utils.java
+++ b/src/it/reyboz/bustorino/backend/utils.java
@@ -6,6 +6,7 @@
 import android.net.NetworkInfo;
 import android.net.Uri;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.View;
 
 public abstract class utils {
@@ -24,9 +25,15 @@
         return Math.abs(EarthRadius*c);
 
     }
+    /*
     public static int convertDipToPixels(Context con,float dips)
     {
         return (int) (dips * con.getResources().getDisplayMetrics().density + 0.5f);
+    }
+     */
+
+    public static float convertDipToPixels(Context con, float dp){
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,con.getResources().getDisplayMetrics());
     }
     public static int calculateNumColumnsFromSize(View containerView, int pixelsize){
         int width = containerView.getWidth();
diff --git a/src/it/reyboz/bustorino/fragments/ArrivalsFragment.java b/src/it/reyboz/bustorino/fragments/ArrivalsFragment.java
--- a/src/it/reyboz/bustorino/fragments/ArrivalsFragment.java
+++ b/src/it/reyboz/bustorino/fragments/ArrivalsFragment.java
@@ -185,6 +185,7 @@
             }
         });
         String displayName = getArguments().getString(STOP_TITLE);
+        if(displayName!=null)
         setTextViewMessage(String.format(
                 getString(R.string.passages), displayName));
 
diff --git a/src/it/reyboz/bustorino/fragments/CommonFragmentListener.java b/src/it/reyboz/bustorino/fragments/CommonFragmentListener.java
--- a/src/it/reyboz/bustorino/fragments/CommonFragmentListener.java
+++ b/src/it/reyboz/bustorino/fragments/CommonFragmentListener.java
@@ -1,5 +1,7 @@
 package it.reyboz.bustorino.fragments;
 
+import android.view.View;
+
 public interface CommonFragmentListener {
 
 
diff --git a/src/it/reyboz/bustorino/fragments/FavoritesFragment.java b/src/it/reyboz/bustorino/fragments/FavoritesFragment.java
--- a/src/it/reyboz/bustorino/fragments/FavoritesFragment.java
+++ b/src/it/reyboz/bustorino/fragments/FavoritesFragment.java
@@ -23,6 +23,7 @@
 import androidx.annotation.Nullable;
 import androidx.lifecycle.ViewModelProvider;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import it.reyboz.bustorino.ActivityFavorites;
@@ -93,6 +94,8 @@
 
         FavoritesViewModel model = new ViewModelProvider(this).get(FavoritesViewModel.class);
         model.getFavorites().observe(getViewLifecycleOwner(), this::showStops);
+
+        showStops(new ArrayList<>());
         return root;
     }
     @Override
diff --git a/src/it/reyboz/bustorino/fragments/MainScreenFragment.java b/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
--- a/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
+++ b/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
@@ -5,12 +5,12 @@
 import android.content.pm.PackageManager;
 import android.location.Criteria;
 import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
 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;
@@ -38,6 +38,8 @@
 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.ArrivalsFetcher;
 import it.reyboz.bustorino.backend.FiveTAPIFetcher;
@@ -45,11 +47,14 @@
 import it.reyboz.bustorino.backend.FiveTStopsFetcher;
 import it.reyboz.bustorino.backend.GTTJSONFetcher;
 import it.reyboz.bustorino.backend.GTTStopsFetcher;
+import it.reyboz.bustorino.backend.Palina;
 import it.reyboz.bustorino.backend.StopsFinderByName;
+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 android.content.Context.LOCATION_SERVICE;
+import static it.reyboz.bustorino.util.Permissions.LOCATION_PERMISSIONS;
 import static it.reyboz.bustorino.util.Permissions.LOCATION_PERMISSION_GIVEN;
 
 
@@ -112,14 +117,74 @@
         }
     };
 
+    /// 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) {
 
-    /// LOCATION STUFF ///
-    boolean pendingNearbyStopsRequest = false;
-    LocationManager locmgr;
+        }
+
+        @Override
+        public void onLocationStatusChanged(int status) {
+
+            if(status == AppLocationManager.LOCATION_GPS_AVAILABLE && !isNearbyFragmentShown()){
+                //request Stops
+                pendingNearbyStopsRequest = false;
+
+                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()){
+                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);
+                        }
+                    }
+                }
+            });
 
-    private final Criteria cr = new Criteria();
 
     //// ACTIVITY ATTACHED (LISTENER ///
     private CommonFragmentListener mListener;
@@ -208,7 +273,7 @@
         cr.setCostAllowed(true);
         cr.setPowerRequirement(Criteria.NO_REQUIREMENT);
 
-        locmgr = (LocationManager) getContext().getSystemService(LOCATION_SERVICE);
+       locationManager = AppLocationManager.getInstance(getContext());
 
         Log.d(DEBUG_TAG, "OnCreateView, savedInstanceState null: "+(savedInstanceState==null));
 
@@ -272,16 +337,15 @@
         if (setupOnAttached) {
             if (pendingStopID==null)
             //We want the nearby bus stops!
-            mainHandler.post(new NearbyStopsRequester(getContext(), cr, locListener));
+            mainHandler.post(new NearbyStopsRequester(context, cr));
             else{
                 ///TODO: if there is a stop displayed, we need to hold the update
             }
-            //If there are no providers available, then, wait for them
 
             setupOnAttached = false;
-        } else {
         }
 
+
     }
     @Override
     public void onDetach() {
@@ -295,8 +359,24 @@
     public void onResume() {
 
         final Context con = getContext();
-        if (con != null)
-            locmgr = (LocationManager) getContext().getSystemService(LOCATION_SERVICE);
+        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");
         }
@@ -324,7 +404,7 @@
     @Override
     public void onPause() {
         //mainHandler = null;
-        locmgr = null;
+        locationManager.removeLocationRequestFor(requester);
         super.onPause();
     }
 
@@ -384,10 +464,8 @@
     }
 
     ////////////////////////////////////// GUI HELPERS /////////////////////////////////////////////
-
     public void showKeyboard() {
-        if (getActivity() == null)
-            return;
+        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);
@@ -408,6 +486,10 @@
         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.
@@ -456,6 +538,17 @@
         //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) {
@@ -475,7 +568,7 @@
 
         //if we are getting results, already, stop waiting for nearbyStops
         if (pendingNearbyStopsRequest && (fragmentType == FragmentKind.ARRIVALS || fragmentType == FragmentKind.STOPS)) {
-            locmgr.removeUpdates(locListener);
+            locationManager.removeLocationRequestFor(requester);
             pendingNearbyStopsRequest = false;
         }
 
@@ -538,65 +631,48 @@
         }
     }
     /////////// LOCATION METHODS //////////
-    final LocationListener locListener = new LocationListener() {
-        @Override
-        public void onLocationChanged(Location location) {
-            Log.d(DEBUG_TAG, "Location changed");
-        }
-
-        @Override
-        public void onStatusChanged(String provider, int status, Bundle extras) {
-            Log.d(DEBUG_TAG, "Location provider status: " + status);
-            if (status == LocationProvider.AVAILABLE) {
-                resolveStopRequest(provider);
-            }
-        }
-
-        @Override
-        public void onProviderEnabled(String provider) {
-            resolveStopRequest(provider);
-        }
-
-        @Override
-        public void onProviderDisabled(String provider) {
 
-        }
-    };
-
-    private void resolveStopRequest(String provider) {
+    /*
+    private void startStopRequest(String provider) {
         Log.d(DEBUG_TAG, "Provider " + provider + " got enabled");
         if (locmgr != null && mainHandler != null && pendingNearbyStopsRequest && locmgr.getProvider(provider).meetsCriteria(cr)) {
-            pendingNearbyStopsRequest = false;
-            mainHandler.post(new NearbyStopsRequester(getContext(), cr, locListener));
+
         }
     }
 
+     */
+
     /**
      * Run location requests separately and asynchronously
      */
     class NearbyStopsRequester implements Runnable {
         Context appContext;
         Criteria cr;
-        LocationListener listener;
 
-        public NearbyStopsRequester(Context appContext, Criteria criteria, LocationListener listener) {
+        public NearbyStopsRequester(Context appContext, Criteria criteria) {
             this.appContext = appContext.getApplicationContext();
             this.cr = criteria;
-            this.listener = listener;
         }
 
         @Override
         public void run() {
-            final boolean canRunPosition = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || getOption(LOCATION_PERMISSION_GIVEN, false);
+            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 (!canRunPosition) {
+                if (!isOldVersion) {
                     pendingNearbyStopsRequest = true;
-                    Permissions.assertLocationPermissions(appContext,getActivity());
+                    //Permissions.assertLocationPermissions(appContext,getActivity());
+                    requestPermissionLauncher.launch(LOCATION_PERMISSIONS);
                     Log.w(DEBUG_TAG, "Cannot get position: Asking permission, noPositionFromSys: " + noPermission);
                     return;
                 } else {
@@ -604,35 +680,20 @@
                 }
             } else setOption(LOCATION_PERMISSION_GIVEN, true);
 
-            LocationManager locManager = (LocationManager) appContext.getSystemService(LOCATION_SERVICE);
-            if (locManager == null) {
-                Log.e(DEBUG_TAG, "location manager is nihil, cannot create NearbyStopsFragment");
-                return;
-            }
-            if (Permissions.anyLocationProviderMatchesCriteria(locManager, cr, 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");
-                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, "nearbyStop_correct");
-                ft.commit();
-                //fragMan.executePendingTransactions();
+                showNearbyStopsFragment();
                 pendingNearbyStopsRequest = false;
-            } else if (!Permissions.anyLocationProviderMatchesCriteria(locManager, cr, true)) {
-                //Wait for the providers
-                Log.d(DEBUG_TAG, "Queuing position request");
-                pendingNearbyStopsRequest = true;
-
-                locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10, 0.1f, listener);
+            } else if(!haveProviders){
+                Log.e(DEBUG_TAG, "NO PROVIDERS FOR POSITION");
             }
 
         }
     }
 
 }
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/fragments/MapFragment.java b/src/it/reyboz/bustorino/fragments/MapFragment.java
--- a/src/it/reyboz/bustorino/fragments/MapFragment.java
+++ b/src/it/reyboz/bustorino/fragments/MapFragment.java
@@ -1,9 +1,9 @@
 package it.reyboz.bustorino.fragments;
 
 import android.Manifest;
+import android.annotation.SuppressLint;
 import android.content.Context;
 
-import android.content.pm.PackageManager;
 import android.location.Location;
 import android.location.LocationManager;
 import android.os.AsyncTask;
@@ -13,10 +13,13 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageButton;
+import android.widget.Toast;
 
+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.core.app.ActivityCompat;
 import androidx.core.content.res.ResourcesCompat;
 import androidx.preference.PreferenceManager;
 
@@ -40,6 +43,7 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 
 import it.reyboz.bustorino.R;
 import it.reyboz.bustorino.backend.Stop;
@@ -47,8 +51,7 @@
 import it.reyboz.bustorino.map.CustomInfoWindow;
 import it.reyboz.bustorino.map.LocationOverlay;
 import it.reyboz.bustorino.middleware.GeneralActivity;
-
-import static it.reyboz.bustorino.util.Permissions.PERMISSION_REQUEST_POSITION;
+import it.reyboz.bustorino.util.Permissions;
 
 public class MapFragment extends BaseFragment {
 
@@ -108,6 +111,30 @@
         }
     };
 
+    private final ActivityResultLauncher<String[]> positionRequestLauncher =
+            registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
+                @Override
+                @SuppressLint("MissingPermission")
+                public void onActivityResult(Map<String, Boolean> result) {
+                    if(result.get(Manifest.permission.ACCESS_COARSE_LOCATION) && result.get(Manifest.permission.ACCESS_FINE_LOCATION)){
+
+                        map.getOverlays().remove(mLocationOverlay);
+                        startLocationOverlay(true);
+                        if(getContext()==null || getContext().getSystemService(Context.LOCATION_SERVICE)==null)
+                            return;
+                        LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
+                        Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+                        if (userLocation != null) {
+                            map.getController().setZoom(POSITION_FOUND_ZOOM);
+                            GeoPoint startPoint = new GeoPoint(userLocation);
+                            setLocationFollowing(true);
+                            map.getController().setCenter(startPoint);
+                        }
+                    }
+                    else Log.w(DEBUG_TAG,"No location permission");
+                }
+            });
+
     public MapFragment() {
     }
     public static MapFragment getInstance(){
@@ -181,13 +208,21 @@
 
         btCenterMap.setOnClickListener(v -> {
             //Log.i(TAG, "centerMap clicked ");
-            final GeoPoint myPosition = mLocationOverlay.getMyLocation();
-            map.getController().animateTo(myPosition);
+            if(Permissions.locationPermissionGranted(getContext())) {
+                final GeoPoint myPosition = mLocationOverlay.getMyLocation();
+                map.getController().animateTo(myPosition);
+            } else
+                Toast.makeText(getContext(), R.string.enable_position_message_map, Toast.LENGTH_SHORT)
+                        .show();
         });
 
         btFollowMe.setOnClickListener(v -> {
             //Log.i(TAG, "btFollowMe clicked ");
-            switchLocationFollowing(!followingLocation);
+            if(Permissions.locationPermissionGranted(getContext()))
+                setLocationFollowing(!followingLocation);
+            else
+                Toast.makeText(getContext(), R.string.enable_position_message_map, Toast.LENGTH_SHORT)
+                    .show();
         });
 
         return root;
@@ -261,8 +296,11 @@
      * Switch following the location on and off
      * @param value true if we want to follow location
      */
-    public void switchLocationFollowing(Boolean value){
+    public void setLocationFollowing(Boolean value){
         followingLocation = value;
+        if(mLocationOverlay==null || getContext() == null)
+            //nothing else to do
+            return;
         if (value){
             mLocationOverlay.enableFollowLocation();
         } else {
@@ -282,6 +320,26 @@
 
     }
 
+    /**
+     * Start the location overlay. Enable only when
+     * a) we know we have the permission
+     * b) the location map is set
+     */
+    private void startLocationOverlay(boolean enableLocation){
+        if(getActivity()== null) throw new IllegalStateException("Cannot enable LocationOverlay now");
+        // Location Overlay
+        // from OpenBikeSharing (THANK GOD)
+        Log.d(DEBUG_TAG, "Starting position overlay");
+        GpsMyLocationProvider imlp = new GpsMyLocationProvider(getActivity().getBaseContext());
+        imlp.setLocationUpdateMinDistance(5);
+        imlp.setLocationUpdateMinTime(2000);
+        this.mLocationOverlay = new LocationOverlay(imlp,map, locationCallbacks);
+        if (enableLocation) mLocationOverlay.enableMyLocation();
+        mLocationOverlay.setOptionsMenuEnabled(true);
+
+        map.getOverlays().add(this.mLocationOverlay);
+    }
+
     public void startMap(Bundle incoming, Bundle savedInstanceState) {
         //Check that we're attached
         GeneralActivity activity = getActivity() instanceof GeneralActivity ? (GeneralActivity) getActivity() : null;
@@ -312,52 +370,48 @@
         IMapController mapController = map.getController();
         GeoPoint startPoint = null;
 
-        boolean havePositionPermission = true;
-
-        if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
-            activity.askForPermissionIfNeeded(Manifest.permission.ACCESS_FINE_LOCATION, PERMISSION_REQUEST_POSITION);
-            havePositionPermission = false;
-        }
-        // Location Overlay
-        // from OpenBikeSharing (THANK GOD)
-        GpsMyLocationProvider imlp = new GpsMyLocationProvider(activity.getBaseContext());
-        imlp.setLocationUpdateMinDistance(5);
-        imlp.setLocationUpdateMinTime(2000);
-        this.mLocationOverlay = new LocationOverlay(imlp,map, locationCallbacks);
-        mLocationOverlay.enableMyLocation();
-        mLocationOverlay.setOptionsMenuEnabled(true);
-
+        // set the center point
         if (marker != null) {
             startPoint = marker;
             mapController.setZoom(POSITION_FOUND_ZOOM);
-            switchLocationFollowing(false);
+            setLocationFollowing(false);
         } else if (savedInstanceState != null) {
             mapController.setZoom(savedInstanceState.getDouble(MAP_CURRENT_ZOOM_KEY));
             mapController.setCenter(new GeoPoint(savedInstanceState.getDouble(MAP_CENTER_LAT_KEY),
                     savedInstanceState.getDouble(MAP_CENTER_LON_KEY)));
             Log.d(DEBUG_TAG, "Location following from savedInstanceState: "+savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY));
-            switchLocationFollowing(savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY));
+            setLocationFollowing(savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY));
         } else {
             Log.d(DEBUG_TAG, "No position found from intent or saved state");
             boolean found = false;
             LocationManager locationManager =
                     (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
-            if (locationManager != null) {
+            //check for permission
+            if (locationManager != null && Permissions.locationPermissionGranted(activity)) {
 
+                @SuppressLint("MissingPermission")
                 Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                 if (userLocation != null) {
                     mapController.setZoom(POSITION_FOUND_ZOOM);
                     startPoint = new GeoPoint(userLocation);
                     found = true;
-                    switchLocationFollowing(true);
+                    setLocationFollowing(true);
+                }
+            } else if(!Permissions.locationPermissionGranted(activity)){
+                if(shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)){
+                    //TODO: show dialog for permission rationale
+                    Toast.makeText(activity, R.string.enable_position_message_map, Toast.LENGTH_SHORT).show();
                 }
+                    positionRequestLauncher.launch(Permissions.LOCATION_PERMISSIONS);
+
             }
             if(!found){
                 startPoint = new GeoPoint(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON);
-                mapController.setZoom(16.0);
-                switchLocationFollowing(false);
+                mapController.setZoom(17.0);
+                setLocationFollowing(false);
             }
         }
+        startLocationOverlay(Permissions.locationPermissionGranted(activity));
 
         // set the minimum zoom level
         map.setMinZoomLevel(15.0);
@@ -366,10 +420,6 @@
             mapController.setCenter(startPoint);
         }
 
-
-
-        map.getOverlays().add(this.mLocationOverlay);
-
         //add stops overlay
         map.getOverlays().add(this.stopsFolderOverlay);
 
diff --git a/src/it/reyboz/bustorino/fragments/NearbyStopsFragment.java b/src/it/reyboz/bustorino/fragments/NearbyStopsFragment.java
--- a/src/it/reyboz/bustorino/fragments/NearbyStopsFragment.java
+++ b/src/it/reyboz/bustorino/fragments/NearbyStopsFragment.java
@@ -68,6 +68,8 @@
     public final static int TYPE_STOPS = 19, TYPE_ARRIVALS = 20;
     private int fragment_type;
 
+    public final static String FRAGMENT_TAG="NearbyStopsFrag";
+
     //data Bundle
     private final String BUNDLE_LOCATION =  "location";
     private final int LOADER_ID = 0;
@@ -135,12 +137,13 @@
     }
 
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
         // Inflate the layout for this fragment
+        if (getContext() == null) throw new RuntimeException();
         View root = inflater.inflate(R.layout.fragment_nearby_stops, container, false);
         gridRecyclerView = root.findViewById(R.id.stopGridRecyclerView);
-        gridLayoutManager = new AutoFitGridLayoutManager(getContext().getApplicationContext(), utils.convertDipToPixels(getContext(),COLUMN_WIDTH_DP));
+        gridLayoutManager = new AutoFitGridLayoutManager(getContext().getApplicationContext(), Float.valueOf(utils.convertDipToPixels(getContext(),COLUMN_WIDTH_DP)).intValue());
         gridRecyclerView.setLayoutManager(gridLayoutManager);
         gridRecyclerView.setHasFixedSize(false);
         circlingProgressBar = root.findViewById(R.id.loadingBar);
@@ -226,7 +229,6 @@
                     + " must implement OnFragmentInteractionListener");
         }
         Log.d(DEBUG_TAG, "OnAttach called");
-
     }
 
     @Override
@@ -408,6 +410,8 @@
             gridRecyclerView.setVisibility(View.VISIBLE);
         }
         messageTextView.setVisibility(View.GONE);
+
+        if(mListener!=null) mListener.readyGUIfor(FragmentKind.NEARBY_STOPS);
     }
 
     private void showArrivalsInRecycler(List<Palina> palinas){
@@ -434,6 +438,8 @@
         //arrivalsStopAdapter.notifyDataSetChanged();
 
         showRecyclerHidingLoadMessage();
+        if(mListener!=null) mListener.readyGUIfor(FragmentKind.NEARBY_ARRIVALS);
+
     }
 
     private void setNoStopsLayout(){
@@ -601,7 +607,7 @@
         @Override
         public LocationCriteria getLocationCriteria() {
 
-            return new LocationCriteria(60,TIME_INTERVAL_REQUESTS);
+            return new LocationCriteria(120,TIME_INTERVAL_REQUESTS);
         }
 
         @Override
@@ -611,6 +617,16 @@
         void resetUpdateTime(){
             lastUpdateTime = -1;
         }
+
+        @Override
+        public void onLocationProviderAvailable() {
+
+        }
+
+        @Override
+        public void onLocationDisabled() {
+
+        }
     }
 
     /**
diff --git a/src/it/reyboz/bustorino/map/LocationOverlay.java b/src/it/reyboz/bustorino/map/LocationOverlay.java
--- a/src/it/reyboz/bustorino/map/LocationOverlay.java
+++ b/src/it/reyboz/bustorino/map/LocationOverlay.java
@@ -44,6 +44,7 @@
 
     @Override
     public void disableFollowLocation() {
+
         super.disableFollowLocation();
         callbacks.onDisableFollowMyLocation();
     }
diff --git a/src/it/reyboz/bustorino/middleware/AppLocationManager.java b/src/it/reyboz/bustorino/middleware/AppLocationManager.java
--- a/src/it/reyboz/bustorino/middleware/AppLocationManager.java
+++ b/src/it/reyboz/bustorino/middleware/AppLocationManager.java
@@ -17,7 +17,10 @@
  */
 package it.reyboz.bustorino.middleware;
 
+import android.Manifest;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.location.Criteria;
 import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
@@ -25,7 +28,11 @@
 import android.os.Bundle;
 import android.util.Log;
 import android.widget.Toast;
+
+import androidx.core.content.ContextCompat;
+
 import it.reyboz.bustorino.util.LocationCriteria;
+import it.reyboz.bustorino.util.Permissions;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -39,37 +46,42 @@
     public static final int LOCATION_GPS_AVAILABLE = 22;
     public static final int LOCATION_UNAVAILABLE = -22;
 
-    private Context con;
-    private LocationManager locMan;
+    private final Context appContext;
+    private final LocationManager locMan;
     public static final String DEBUG_TAG = "BUSTO LocAdapter";
     private final String BUNDLE_LOCATION =  "location";
     private static AppLocationManager instance;
     private int oldGPSLocStatus = LOCATION_UNAVAILABLE;
     private int minimum_time_milli = -1;
 
-    private ArrayList<WeakReference<LocationRequester>> requestersRef = new ArrayList<>();
+    private boolean isLocationPermissionGiven = false;
+
+    private final ArrayList<WeakReference<LocationRequester>> requestersRef = new ArrayList<>();
 
 
-    private AppLocationManager(Context con) {
-        this.con = con.getApplicationContext();
-        locMan  = (LocationManager) con.getSystemService(Context.LOCATION_SERVICE);
+    private AppLocationManager(Context context) {
+        this.appContext = context.getApplicationContext();
+        locMan  = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+        isLocationPermissionGiven = checkLocationPermission(context);
     }
 
     public static AppLocationManager getInstance(Context con) {
-        if(instance==null) instance = new AppLocationManager(con.getApplicationContext());
+        if(instance==null) instance = new AppLocationManager(con);
         return instance;
     }
+
+    public static boolean checkLocationPermission(Context context){
+        return ContextCompat.checkSelfPermission(context,
+                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED;
+    }
     
 
-    private void requestGPSPositionUpdates(){
+    private void requestGPSPositionUpdates() throws SecurityException{
         final int timeinterval = (minimum_time_milli>0 && minimum_time_milli<Integer.MAX_VALUE)? minimum_time_milli : 2000;
-        try {
-            locMan.removeUpdates(this);
-            locMan.requestLocationUpdates(LocationManager.GPS_PROVIDER, timeinterval, 5, this);
-        } catch (SecurityException exc){
-            exc.printStackTrace();
-            Toast.makeText(con,"Cannot access GPS location",Toast.LENGTH_SHORT).show();
-        }
+
+        locMan.removeUpdates(this);
+        locMan.requestLocationUpdates(LocationManager.GPS_PROVIDER, timeinterval, 5, this);
+
     }
     private void cleanAndUpdateRequesters(){
         minimum_time_milli = Integer.MAX_VALUE;
@@ -88,15 +100,19 @@
     public void addLocationRequestFor(LocationRequester req){
         boolean present = false;
         minimum_time_milli = Integer.MAX_VALUE;
+        int countNull = 0;
         ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator();
         while(iter.hasNext()){
             final LocationRequester cReq = iter.next().get();
-            if(cReq==null) iter.remove();
-            else if(cReq.equals(req)){
+            if(cReq==null) {
+                countNull++;
+                iter.remove();
+            } else if(cReq.equals(req)){
                 present = true;
                 minimum_time_milli = Math.min(cReq.getLocationCriteria().getTimeInterval(),minimum_time_milli);
             }
         }
+        Log.d(DEBUG_TAG, countNull+" listeners have been removed because null");
         if(!present) {
             WeakReference<LocationRequester> newref = new WeakReference<>(req);
             requestersRef.add(newref);
@@ -104,7 +120,7 @@
             Log.d(DEBUG_TAG,"Added new stop requester, instance of "+req.getClass().getSimpleName());
         }
         if(requestersRef.size()>0){
-            Log.d(DEBUG_TAG,"Requesting position updates");
+            Log.d(DEBUG_TAG,"Requesting location updates");
             requestGPSPositionUpdates();
 
         }
@@ -134,6 +150,12 @@
             else cReq.onLocationStatusChanged(status);
         }
     }
+    public boolean isRequesterRegistered(LocationRequester requester){
+        for(WeakReference<LocationRequester> regRef: requestersRef){
+            if(regRef.get()!=null && regRef.get() ==requester) return true;
+        }
+        return false;
+    }
 
     @Override
     public void onLocationChanged(Location location) {
@@ -176,21 +198,35 @@
             }
                 oldGPSLocStatus = status;
             }
-        Log.d(DEBUG_TAG, "Provider: "+provider+" status: "+status);
+        Log.d(DEBUG_TAG, "Provider status changed: "+provider+" status: "+status);
     }
 
     @Override
     public void onProviderEnabled(String provider) {
+        cleanAndUpdateRequesters();
         requestGPSPositionUpdates();
         Log.d(DEBUG_TAG, "Provider: "+provider+" enabled");
+        for(WeakReference<LocationRequester> req: requestersRef){
+            if(req.get()==null) continue;
+            req.get().onLocationProviderAvailable();
+        }
+
     }
 
     @Override
     public void onProviderDisabled(String provider) {
-        locMan.removeUpdates(this);
+        cleanAndUpdateRequesters();
+        for(WeakReference<LocationRequester> req: requestersRef){
+            if(req.get()==null) continue;
+            req.get().onLocationDisabled();
+        }
+        //locMan.removeUpdates(this);
         Log.d(DEBUG_TAG, "Provider: "+provider+" disabled");
     }
 
+    public boolean anyLocationProviderMatchesCriteria(Criteria cr) {
+        return Permissions.anyLocationProviderMatchesCriteria(locMan, cr, true);
+    }
     /**
      * Interface to be implemented to get the location request
      */
@@ -207,6 +243,16 @@
          */
         void onLocationStatusChanged(int status);
 
+        /**
+         * We have a location provider available
+         */
+        void onLocationProviderAvailable();
+        /**
+         * Called when location is disabled
+         */
+        void onLocationDisabled();
+
+
         /**
          * Give the last time of update the requester has
          * Set it to -1 in order to receive each new location
diff --git a/src/it/reyboz/bustorino/middleware/GeneralActivity.java b/src/it/reyboz/bustorino/middleware/GeneralActivity.java
--- a/src/it/reyboz/bustorino/middleware/GeneralActivity.java
+++ b/src/it/reyboz/bustorino/middleware/GeneralActivity.java
@@ -2,12 +2,16 @@
 
 import android.Manifest;
 import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import com.google.android.material.snackbar.Snackbar;
+
+import androidx.annotation.Nullable;
 import androidx.core.app.ActivityCompat;
 import androidx.core.content.ContextCompat;
 import androidx.appcompat.app.AppCompatActivity;
@@ -20,6 +24,7 @@
 import java.util.HashMap;
 
 import it.reyboz.bustorino.R;
+import it.reyboz.bustorino.backend.utils;
 
 /**
  * Activity class that contains all the generally useful methods
@@ -81,7 +86,7 @@
         synchronized (this){
             if (permissionAsked.containsKey(permission)){
                 num_trials = permissionAsked.get(permission);
-                if (num_trials != null && num_trials > 3)
+                if (num_trials != null && num_trials > 4)
                     alreadyAsked = true;
 
             }
@@ -121,4 +126,29 @@
         ActivityCompat.requestPermissions(this,permissionstoRequest.toArray(new String[permissionstoRequest]));
     }
     */
+
+    //KEYBOARD STUFF
+    protected  View getRootView() {
+        return findViewById(android.R.id.content);
+    }
+
+    /**
+     * This method doesn't work, DO NOT USE
+     * @return if the keyboard is open
+     * TODO: fix this if you want
+     */
+    @Deprecated
+    public Boolean isKeyboardOpen(){
+        Rect visibleBounds = new Rect();
+        this.getRootView().getWindowVisibleDisplayFrame(visibleBounds);
+
+        double heightDiff = getRootView().getHeight() - visibleBounds.height();
+        final double marginOfError = Math.round(utils.convertDipToPixels(this,50f));
+        return heightDiff > marginOfError;
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+    }
 }
diff --git a/src/it/reyboz/bustorino/util/LocationCriteria.java b/src/it/reyboz/bustorino/util/LocationCriteria.java
--- a/src/it/reyboz/bustorino/util/LocationCriteria.java
+++ b/src/it/reyboz/bustorino/util/LocationCriteria.java
@@ -17,13 +17,21 @@
  */
 package it.reyboz.bustorino.util;
 
+import android.location.Criteria;
+
 /**
  * Own Location Criteria, because it's fun
+ *
  */
-public class LocationCriteria {
+public class LocationCriteria extends Criteria {
     private final float minAccuracy;
     private final int timeInterval;
 
+    /**
+     * Constructor
+     * @param minAccuracy in meters
+     * @param timeInterval in milliseconds
+     */
     public LocationCriteria(float minAccuracy,int timeInterval){
         this.minAccuracy = minAccuracy;
         this.timeInterval = timeInterval;
diff --git a/src/it/reyboz/bustorino/util/Permissions.java b/src/it/reyboz/bustorino/util/Permissions.java
--- a/src/it/reyboz/bustorino/util/Permissions.java
+++ b/src/it/reyboz/bustorino/util/Permissions.java
@@ -8,8 +8,11 @@
 import android.location.LocationManager;
 import android.util.Log;
 
+import androidx.activity.result.ActivityResultCaller;
+import androidx.activity.result.ActivityResultLauncher;
 import androidx.core.app.ActivityCompat;
 import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
 
 import java.util.List;
 
@@ -24,6 +27,9 @@
     final static public int PERMISSION_ASKING = 11;
     final static public int PERMISSION_NEG_CANNOT_ASK = -3;
 
+    final static public String[] LOCATION_PERMISSIONS={Manifest.permission.ACCESS_COARSE_LOCATION,
+            Manifest.permission.ACCESS_FINE_LOCATION};
+
     public static boolean anyLocationProviderMatchesCriteria(LocationManager mng, Criteria cr, boolean enabled) {
         List<String> providers = mng.getProviders(cr, enabled);
         Log.d(DEBUG_TAG, "Getting enabled location providers: ");
@@ -32,9 +38,18 @@
         }
         return providers.size() > 0;
     }
+    public static boolean isPermissionGranted(Context con,String permission){
+        return ContextCompat.checkSelfPermission(con, permission) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    public static boolean locationPermissionGranted(Context con){
+        return isPermissionGranted(con, Manifest.permission.ACCESS_FINE_LOCATION) &&
+                isPermissionGranted(con, Manifest.permission.ACCESS_COARSE_LOCATION);
+    }
 
     public static void assertLocationPermissions(Context con, Activity activity) {
-        if(ContextCompat.checkSelfPermission(con, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED){
+        if(!isPermissionGranted(con, Manifest.permission.ACCESS_FINE_LOCATION) ||
+                !isPermissionGranted(con,Manifest.permission.ACCESS_COARSE_LOCATION)){
             ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_POSITION);
         }
     }