diff --git a/extern/MicroGUiTools b/extern/MicroGUiTools
index f34d87b..f0e7d6b 160000
--- a/extern/MicroGUiTools
+++ b/extern/MicroGUiTools
@@ -1 +1 @@
-Subproject commit f34d87bcc2bb44de1a8efd29b40c311dbea67049
+Subproject commit f0e7d6b1c806effee3f5040e5e8595e128c575e4
diff --git a/extern/UnifiedNlpApi b/extern/UnifiedNlpApi
index f7fcb8e..25d8b47 160000
--- a/extern/UnifiedNlpApi
+++ b/extern/UnifiedNlpApi
@@ -1 +1 @@
-Subproject commit f7fcb8e7cf966f58d784f450e061b88f96f73ecf
+Subproject commit 25d8b478eb2497803ffb8c5c45d186adb6b64850
diff --git a/unifiednlp-base/src/main/java/org/microg/nlp/AbstractProviderService.java b/unifiednlp-base/src/main/java/org/microg/nlp/AbstractProviderService.java
index 663bd14..a89441a 100644
--- a/unifiednlp-base/src/main/java/org/microg/nlp/AbstractProviderService.java
+++ b/unifiednlp-base/src/main/java/org/microg/nlp/AbstractProviderService.java
@@ -21,6 +21,8 @@
 import android.os.IBinder;
 
 public abstract class AbstractProviderService<T extends Provider> extends IntentService {
+    protected String TAG;
+
     /**
      * Creates an ProviderService.  Invoked by your subclass's constructor.
      *
@@ -28,6 +30,7 @@ public abstract class AbstractProviderService<T extends Provider> extends Intent
      */
     public AbstractProviderService(String tag) {
         super(tag);
+        this.TAG = tag;
     }
 
     @Override
diff --git a/unifiednlp-base/src/main/java/org/microg/nlp/location/AbstractLocationService.java b/unifiednlp-base/src/main/java/org/microg/nlp/location/AbstractLocationService.java
index 639f2bc..7309638 100644
--- a/unifiednlp-base/src/main/java/org/microg/nlp/location/AbstractLocationService.java
+++ b/unifiednlp-base/src/main/java/org/microg/nlp/location/AbstractLocationService.java
@@ -16,34 +16,49 @@
 
 package org.microg.nlp.location;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.location.Location;
-import android.os.Build;
 import android.os.IBinder;
+import android.util.Log;
 
 import org.microg.nlp.AbstractProviderService;
-import org.microg.nlp.ui.SettingInjectorService;
 
 import java.lang.reflect.Method;
 
+import static android.os.Build.VERSION.SDK_INT;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
 import static org.microg.nlp.api.Constants.ACTION_FORCE_LOCATION;
 import static org.microg.nlp.api.Constants.ACTION_RELOAD_SETTINGS;
 import static org.microg.nlp.api.Constants.INTENT_EXTRA_LOCATION;
 import static org.microg.nlp.api.Constants.PERMISSION_FORCE_LOCATION;
 
 public abstract class AbstractLocationService extends AbstractProviderService<LocationProvider> {
-    public static void reloadLocationService(Context context) {
+    public static ComponentName reloadLocationService(Context context) {
         Intent intent = new Intent(ACTION_RELOAD_SETTINGS);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+        setIntentTarget(context, intent);
+        return context.startService(intent);
+    }
+
+    public static ComponentName forceLocation(Context context, Location location) {
+        Intent intent = new Intent(ACTION_FORCE_LOCATION);
+        setIntentTarget(context, intent);
+        intent.putExtra(INTENT_EXTRA_LOCATION, location);
+        return context.startService(intent);
+    }
+
+    private static void setIntentTarget(Context context, Intent intent) {
+        if (SDK_INT >= JELLY_BEAN_MR1) {
             intent.setClass(context, LocationServiceV2.class);
         } else {
             intent.setClass(context, LocationServiceV1.class);
         }
-        context.startService(intent);
     }
 
+    public static boolean WAS_BOUND = false;
+
     /**
      * Creates an LocationService.  Invoked by your subclass's constructor.
      *
@@ -55,6 +70,7 @@ public AbstractLocationService(String tag) {
 
     @Override
     public IBinder onBind(Intent intent) {
+        WAS_BOUND = true;
         updateLauncherIcon();
         return super.onBind(intent);
     }
@@ -69,6 +85,8 @@ protected void onHandleIntent(Intent intent) {
                 if (provider != null && intent.hasExtra(INTENT_EXTRA_LOCATION)) {
                     provider.forceLocation(
                             (Location) intent.getParcelableExtra(INTENT_EXTRA_LOCATION));
+                } else {
+                    Log.d(TAG, "Cannot force location, provider not ready");
                 }
             }
         }
@@ -76,6 +94,8 @@ protected void onHandleIntent(Intent intent) {
         if (ACTION_RELOAD_SETTINGS.equals(intent.getAction())) {
             if (provider != null) {
                 provider.reload();
+            } else {
+                Log.d(TAG, "Cannot reload settings, provider not ready");
             }
         }
 
diff --git a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProvider.java b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProvider.java
index 3e6f929..b457e77 100644
--- a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProvider.java
+++ b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProvider.java
@@ -21,6 +21,8 @@
 import org.microg.nlp.Provider;
 
 interface LocationProvider extends Provider {
+    int FASTEST_REFRESH_INTERVAL = 2500; // in milliseconds
+
     void onEnable();
 
     void onDisable();
diff --git a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProviderV1.java b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProviderV1.java
index 0b5138e..1eb41a7 100644
--- a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProviderV1.java
+++ b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProviderV1.java
@@ -137,7 +137,7 @@ public void onEnableLocationTracking(boolean enable) {
     @Override
     public void onSetMinTime(long minTime, WorkSource ws) {
         Log.v(TAG, "onSetMinTime: " + minTime + " by " + ws);
-        autoTime = minTime;
+        autoTime = Math.max(minTime, FASTEST_REFRESH_INTERVAL);
         helper.setTime(autoTime);
         if (autoUpdate) helper.enable();
     }
diff --git a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProviderV2.java b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProviderV2.java
index 465b68a..f310520 100644
--- a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProviderV2.java
+++ b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationProviderV2.java
@@ -88,13 +88,9 @@ public long onGetStatusUpdateTime() {
     public void onSetRequest(ProviderRequestUnbundled requests, WorkSource source) {
         Log.v(TAG, "onSetRequest: " + requests + " by " + source);
 
-        long autoTime = requests.getInterval();
+        long autoTime = Math.max(requests.getInterval(), FASTEST_REFRESH_INTERVAL);
         boolean autoUpdate = requests.getReportLocation();
 
-        if (autoTime < 1500) {
-            // Limit to 1.5s
-            autoTime = 1500;
-        }
         Log.v(TAG, "using autoUpdate=" + autoUpdate + " autoTime=" + autoTime);
 
         if (autoUpdate) {
diff --git a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationServiceV1.java b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationServiceV1.java
index 430b966..e515705 100644
--- a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationServiceV1.java
+++ b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationServiceV1.java
@@ -17,11 +17,10 @@
 package org.microg.nlp.location;
 
 public class LocationServiceV1 extends AbstractLocationService {
-    private static final String TAG = "NlpLocationService";
     private static LocationProviderV1 THE_ONE;
 
     public LocationServiceV1() {
-        super(TAG);
+        super("NlpLocationServiceV1");
     }
 
     @Override
diff --git a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationServiceV2.java b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationServiceV2.java
index 54aa1c1..af5e25b 100644
--- a/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationServiceV2.java
+++ b/unifiednlp-base/src/main/java/org/microg/nlp/location/LocationServiceV2.java
@@ -17,11 +17,10 @@
 package org.microg.nlp.location;
 
 public class LocationServiceV2 extends AbstractLocationService {
-    private static final String TAG = "NlpLocationService";
     private static LocationProviderV2 THE_ONE;
 
     public LocationServiceV2() {
-        super(TAG);
+        super("NlpLocationServiceV2");
     }
 
     @Override
diff --git a/unifiednlp-base/src/main/java/org/microg/tools/selfcheck/NlpOsCompatChecks.java b/unifiednlp-base/src/main/java/org/microg/tools/selfcheck/NlpOsCompatChecks.java
new file mode 100644
index 0000000..b57d7bb
--- /dev/null
+++ b/unifiednlp-base/src/main/java/org/microg/tools/selfcheck/NlpOsCompatChecks.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2013-2016 microG Project Team
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.microg.tools.selfcheck;
+
+import android.content.Context;
+
+import java.util.Arrays;
+
+import static android.os.Build.VERSION.SDK_INT;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+import static android.os.Build.VERSION_CODES.KITKAT;
+import static android.os.Build.VERSION_CODES.M;
+
+public class NlpOsCompatChecks implements SelfCheckGroup {
+
+    @Override
+    public String getGroupName(Context context) {
+        return "Network location provider support";
+    }
+
+    @Override
+    public void doChecks(Context context, ResultCollector collector) {
+        checkSystemIsSupported(context, collector);
+        checkSystemIsConfigured(context, collector);
+    }
+
+    private boolean checkSystemIsSupported(Context context, ResultCollector collector) {
+        boolean isSupported = (SDK_INT >= KITKAT && SDK_INT <= M);
+        collector.addResult("Android version supported:", isSupported ? Result.Positive : Result.Unknown, "Your Android version is not officially supported. This does not necessarily mean anything.");
+        return isSupported;
+    }
+
+    private boolean checkSystemIsConfigured(Context context, ResultCollector collector) {
+        // 2.3+ com.android.internal.R.string.config_networkLocationProvider
+        // 4.1+ com.android.internal.R.string.config_networkLocationProviderPackageName
+        // 4.2+ com.android.internal.R.array.config_locationProviderPackageNames
+        // 4.3+ com.android.internal.R.array.config_locationProviderPackageNames /
+        //      com.android.internal.R.string.config_networkLocationProviderPackageName /
+        //      com.android.internal.R.bool.config_enableNetworkLocationOverlay
+        boolean systemMatchesPackage = false;
+        if (SDK_INT < JELLY_BEAN) {
+            systemMatchesPackage |= context.getPackageName().equals(getResourceString(context, "config_networkLocationProvider"));
+        } else {
+            boolean overlay = getResourceBool(context, "config_enableNetworkLocationOverlay");
+            if (SDK_INT < JELLY_BEAN_MR1 || (SDK_INT > JELLY_BEAN_MR1 && !overlay)) {
+                systemMatchesPackage |= context.getPackageName().equals(getResourceString(context, "config_networkLocationProviderPackageName"));
+            }
+            if (SDK_INT == JELLY_BEAN_MR1 || (SDK_INT > JELLY_BEAN_MR1 && overlay)) {
+                systemMatchesPackage |= Arrays.asList(getResourceArray(context, "config_locationProviderPackageNames")).contains(context.getPackageName());
+            }
+        }
+        collector.addResult("System supports location provider:", systemMatchesPackage ? Result.Positive : Result.Negative, "Your system does not support this UnifiedNlp package. Either install a matching package or a compatibility Xposed module.");
+        return systemMatchesPackage;
+    }
+
+    private String[] getResourceArray(Context context, String identifier) {
+        try {
+            int resId = context.getResources().getIdentifier(identifier, "array", "android");
+            if (resId == 0)
+                resId = context.getResources().getIdentifier(identifier, "array", "com.android.internal");
+            return context.getResources().getStringArray(resId);
+        } catch (Exception e) {
+            return new String[0];
+        }
+    }
+
+    private boolean getResourceBool(Context context, String identifier) {
+        try {
+            int resId = context.getResources().getIdentifier(identifier, "bool", "android");
+            if (resId == 0)
+                resId = context.getResources().getIdentifier(identifier, "bool", "com.android.internal");
+            return context.getResources().getBoolean(resId);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    private String getResourceString(Context context, String identifier) {
+        try {
+            int resId = context.getResources().getIdentifier(identifier, "string", "android");
+            if (resId == 0)
+                resId = context.getResources().getIdentifier(identifier, "string", "com.android.internal");
+            return context.getString(resId);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+}
diff --git a/unifiednlp-base/src/main/java/org/microg/tools/selfcheck/NlpStatusChecks.java b/unifiednlp-base/src/main/java/org/microg/tools/selfcheck/NlpStatusChecks.java
new file mode 100644
index 0000000..4f25efb
--- /dev/null
+++ b/unifiednlp-base/src/main/java/org/microg/tools/selfcheck/NlpStatusChecks.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2013-2016 microG Project Team
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.microg.tools.selfcheck;
+
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import org.microg.nlp.Preferences;
+import org.microg.nlp.location.AbstractLocationService;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static android.location.LocationManager.NETWORK_PROVIDER;
+import static org.microg.nlp.api.Constants.LOCATION_EXTRA_BACKEND_PROVIDER;
+import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;
+import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;
+import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Unknown;
+
+public class NlpStatusChecks implements SelfCheckGroup {
+    @Override
+    public String getGroupName(Context context) {
+        return "UnifiedNlp status";
+    }
+
+    @Override
+    public void doChecks(Context context, ResultCollector collector) {
+        providerWasBound(context, collector);
+        isLocationProviderSetUp(context, collector);
+        isProvidingLastLocation(context, collector);
+        isProvidingLocation(context, collector);
+    }
+
+    private boolean providerWasBound(Context context, ResultCollector collector) {
+        collector.addResult("UnifiedNlp is registered in system:", AbstractLocationService.WAS_BOUND ? Positive : Negative, "The system did not bind the UnifiedNlp service. If you just installed UnifiedNlp you should try to reboot this device.");
+        return AbstractLocationService.WAS_BOUND;
+    }
+
+    private boolean isLocationProviderSetUp(Context context, ResultCollector collector) {
+        boolean setupLocationProvider = !TextUtils.isEmpty(new Preferences(context).getLocationBackends());
+        collector.addResult("Location backend(s) set up:", setupLocationProvider ? Positive : Negative, "Install and configure a UnifiedNlp location backend to use network-based geolocation,");
+        return setupLocationProvider;
+    }
+
+    private boolean isProvidingLastLocation(Context context, ResultCollector collector) {
+        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+        Location location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+        boolean hasKnown = location != null && location.getExtras().containsKey(LOCATION_EXTRA_BACKEND_PROVIDER);
+        collector.addResult("UnifiedNlp has known location:", hasKnown ? Positive : Unknown, "UnifiedNlp has no last known location. This will cause some apps to fail.");
+        return hasKnown;
+    }
+
+    private void isProvidingLocation(Context context, final ResultCollector collector) {
+        final AtomicBoolean result = new AtomicBoolean(false);
+        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (result) {
+                    try {
+                        result.wait(10000);
+                    } catch (InterruptedException e) {
+                    }
+                    collector.addResult("UnifiedNlp provides location updates:", result.get() ? Positive : Unknown, "No UnifiedNlp location was provided by the system within 10 seconds.");
+                }
+            }
+        }).start();
+        locationManager.requestSingleUpdate(NETWORK_PROVIDER, new LocationListener() {
+            @Override
+            public void onLocationChanged(Location location) {
+                synchronized (result) {
+                    result.set(location.getExtras().containsKey(LOCATION_EXTRA_BACKEND_PROVIDER));
+                    result.notifyAll();
+                }
+            }
+
+            @Override
+            public void onStatusChanged(String provider, int status, Bundle extras) {
+            }
+
+            @Override
+            public void onProviderEnabled(String provider) {
+            }
+
+            @Override
+            public void onProviderDisabled(String provider) {
+            }
+        }, null);
+    }
+}