diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 561ec10e67098c024a094c3f00885682d025edec..d7567fc120a081bf89c593bb588f8f38c8b0ed75 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -6246,6 +6246,7 @@ package android.location {
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
     field public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED = "android.location.action.ADAS_GNSS_ENABLED_CHANGED";
     field public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
+    field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";
   }
 
   public final class LocationRequest implements android.os.Parcelable {
@@ -6385,6 +6386,7 @@ package android.location.provider {
     method public void setAllowed(boolean);
     method public void setProperties(@NonNull android.location.provider.ProviderProperties);
     field public static final String ACTION_FUSED_PROVIDER = "com.android.location.service.FusedLocationProvider";
+    field public static final String ACTION_GNSS_PROVIDER = "android.location.provider.action.GNSS_PROVIDER";
     field public static final String ACTION_NETWORK_PROVIDER = "com.android.location.service.v3.NetworkLocationProvider";
   }
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 9b81c09f5c5b17e50a7adc8df88b7cbf947cc483..3619d3ac5253e48785316070f2e2dc36ebb59339 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -194,6 +194,21 @@ public class LocationManager {
      */
     public static final String GPS_PROVIDER = "gps";
 
+    /**
+     * Standard name of the GNSS hardware location provider.
+     *
+     * <p>This provider is similar to {@link LocationManager#GPS_PROVIDER}, but it directly uses the
+     * HAL GNSS implementation and doesn't go through any provider overrides that may exist. This
+     * provider will only be available when the GPS_PROVIDER is overridden with a proxy using {@link
+     * android.location.provider.LocationProviderBase#ACTION_GNSS_PROVIDER}, and is intended only
+     * for use internally by the location provider system.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+    public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";
+
     /**
      * A special location provider for receiving locations without actively initiating a location
      * fix. This location provider is always present.
diff --git a/location/java/android/location/provider/LocationProviderBase.java b/location/java/android/location/provider/LocationProviderBase.java
index 5acec79a2d3b2d4ffae72d8879ba306762e1f61f..18672b7fe10d1ef6600c1308a33db23c34a1ced5 100644
--- a/location/java/android/location/provider/LocationProviderBase.java
+++ b/location/java/android/location/provider/LocationProviderBase.java
@@ -104,8 +104,6 @@ public abstract class LocationProviderBase {
     /**
      * The action the wrapping service should have in its intent filter to implement the
      * {@link android.location.LocationManager#GPS_PROVIDER}.
-     *
-     * @hide
      */
     public static final String ACTION_GNSS_PROVIDER =
             "android.location.provider.action.GNSS_PROVIDER";
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 3ce51c3d1412b2db958f33510955fa4193098817..b4c9596933117f654bbdb66a0394f95444b79b93 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -24,6 +24,7 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.location.LocationManager.BLOCK_PENDING_INTENT_SYSTEM_API_USAGE;
 import static android.location.LocationManager.FUSED_PROVIDER;
+import static android.location.LocationManager.GPS_HARDWARE_PROVIDER;
 import static android.location.LocationManager.GPS_PROVIDER;
 import static android.location.LocationManager.NETWORK_PROVIDER;
 import static android.location.LocationRequest.LOW_POWER_EXCEPTIONS;
@@ -95,6 +96,7 @@ import android.util.IndentingPrintWriter;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.FgThread;
@@ -319,6 +321,9 @@ public class LocationManagerService extends ILocationManager.Stub implements
 
         for (LocationProviderManager manager : mProviderManagers) {
             if (providerName.equals(manager.getName())) {
+                if (!manager.isVisibleToCaller()) {
+                    return null;
+                }
                 return manager;
             }
         }
@@ -341,8 +346,9 @@ public class LocationManagerService extends ILocationManager.Stub implements
         }
     }
 
-    private void addLocationProviderManager(LocationProviderManager manager,
-            @Nullable AbstractLocationProvider realProvider) {
+    @VisibleForTesting
+    void addLocationProviderManager(
+            LocationProviderManager manager, @Nullable AbstractLocationProvider realProvider) {
         synchronized (mProviderManagers) {
             Preconditions.checkState(getLocationProviderManager(manager.getName()) == null);
 
@@ -453,6 +459,20 @@ public class LocationManagerService extends ILocationManager.Stub implements
             }
             if (gnssProvider == null) {
                 gnssProvider = mGnssManagerService.getGnssLocationProvider();
+            } else {
+                // If we have a GNSS provider override, add the hardware provider as a standalone
+                // option for use by apps with the correct permission. Note the GNSS HAL can only
+                // support a single client, so mGnssManagerService.getGnssLocationProvider() can
+                // only be installed with a single provider.
+                LocationProviderManager gnssHardwareManager =
+                        new LocationProviderManager(
+                                mContext,
+                                mInjector,
+                                GPS_HARDWARE_PROVIDER,
+                                mPassiveManager,
+                                Collections.singletonList(Manifest.permission.LOCATION_HARDWARE));
+                addLocationProviderManager(
+                        gnssHardwareManager, mGnssManagerService.getGnssLocationProvider());
             }
 
             LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector,
@@ -629,7 +649,9 @@ public class LocationManagerService extends ILocationManager.Stub implements
     public List<String> getAllProviders() {
         ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
         for (LocationProviderManager manager : mProviderManagers) {
-            providers.add(manager.getName());
+            if (manager.isVisibleToCaller()) {
+                providers.add(manager.getName());
+            }
         }
         return providers;
     }
@@ -644,15 +666,18 @@ public class LocationManagerService extends ILocationManager.Stub implements
         synchronized (mLock) {
             ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
             for (LocationProviderManager manager : mProviderManagers) {
-                String name = manager.getName();
-                if (enabledOnly && !manager.isEnabled(UserHandle.getCallingUserId())) {
-                    continue;
-                }
-                if (criteria != null && !LocationProvider.propertiesMeetCriteria(name,
-                        manager.getProperties(), criteria)) {
-                    continue;
+                if (manager.isVisibleToCaller()) {
+                    String name = manager.getName();
+                    if (enabledOnly && !manager.isEnabled(UserHandle.getCallingUserId())) {
+                        continue;
+                    }
+                    if (criteria != null
+                            && !LocationProvider.propertiesMeetCriteria(
+                                    name, manager.getProperties(), criteria)) {
+                        continue;
+                    }
+                    providers.add(name);
                 }
-                providers.add(name);
             }
             return providers;
         }
@@ -1059,7 +1084,9 @@ public class LocationManagerService extends ILocationManager.Stub implements
     public void addProviderRequestListener(IProviderRequestListener listener) {
         mContext.enforceCallingOrSelfPermission(INTERACT_ACROSS_USERS, null);
         for (LocationProviderManager manager : mProviderManagers) {
-            manager.addProviderRequestListener(listener);
+            if (manager.isVisibleToCaller()) {
+                manager.addProviderRequestListener(listener);
+            }
         }
     }
 
@@ -1649,7 +1676,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
                 if (provider != null && !provider.equals(manager.getName())) {
                     continue;
                 }
-                if (identity.equals(manager.getProviderIdentity())) {
+                if (identity.equals(manager.getProviderIdentity()) && manager.isVisibleToCaller()) {
                     return true;
                 }
             }
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 7063cb80d514a6fab4fc3fe8dbd9b610292bcb1f..ffdb53142567d711e423367317b38b15e9f158e5 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -19,6 +19,7 @@ package com.android.server.location.provider;
 import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
 import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
 import static android.app.compat.CompatChanges.isChangeEnabled;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.location.LocationManager.DELIVER_HISTORICAL_LOCATIONS;
 import static android.location.LocationManager.GPS_PROVIDER;
 import static android.location.LocationManager.KEY_FLUSH_COMPLETE;
@@ -48,6 +49,7 @@ import static java.lang.Math.min;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.app.AlarmManager.OnAlarmListener;
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
@@ -124,6 +126,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -1362,6 +1365,10 @@ public class LocationProviderManager extends
     @GuardedBy("mMultiplexerLock")
     private final ArrayList<ProviderEnabledListener> mEnabledListeners;
 
+    // Extra permissions required to use this provider (on top of the usual location permissions).
+    // Not guarded because it's read only.
+    private final Collection<String> mRequiredPermissions;
+
     private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
 
     protected final LocationManagerInternal mLocationManagerInternal;
@@ -1435,12 +1442,34 @@ public class LocationProviderManager extends
 
     public LocationProviderManager(Context context, Injector injector,
             String name, @Nullable PassiveLocationProviderManager passiveManager) {
+        this(context, injector, name, passiveManager, Collections.emptyList());
+    }
+
+    /**
+     * Creates a manager for a location provider (the two have a 1:1 correspondence).
+     *
+     * @param context Context in which the manager is running.
+     * @param injector Injector to retrieve system components (useful to override in testing)
+     * @param name Name of this provider (used in LocationManager APIs by client apps).
+     * @param passiveManager The "passive" manager (special case provider that returns locations
+     *     from all other providers).
+     * @param requiredPermissions Required permissions for accessing this provider. All of the given
+     *     permissions are required to access the provider. If a caller doesn't hold the correct
+     *     permission, the provider will be invisible to it.
+     */
+    public LocationProviderManager(
+            Context context,
+            Injector injector,
+            String name,
+            @Nullable PassiveLocationProviderManager passiveManager,
+            Collection<String> requiredPermissions) {
         mContext = context;
         mName = Objects.requireNonNull(name);
         mPassiveManager = passiveManager;
         mState = STATE_STOPPED;
         mEnabled = new SparseBooleanArray(2);
         mLastLocations = new SparseArray<>(2);
+        mRequiredPermissions = requiredPermissions;
 
         mEnabledListeners = new ArrayList<>();
         mProviderRequestListeners = new CopyOnWriteArrayList<>();
@@ -1559,6 +1588,24 @@ public class LocationProviderManager extends
         }
     }
 
+    /**
+     * Returns true if this provider is visible to the current caller (whether called from a binder
+     * thread or not). If a provider isn't visible, then all APIs return the same data they would if
+     * the provider didn't exist (i.e. the caller can't see or use the provider).
+     *
+     * <p>This method doesn't require any permissions, but uses permissions to determine which
+     * subset of providers are visible.
+     */
+    @SuppressLint("AndroidFrameworkRequiresPermission")
+    public boolean isVisibleToCaller() {
+        for (String permission : mRequiredPermissions) {
+            if (mContext.checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public void addEnabledListener(ProviderEnabledListener listener) {
         synchronized (mMultiplexerLock) {
             Preconditions.checkState(mState != STATE_STOPPED);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d112965b93233d7301aa24d9c4776b69e8c667b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationManagerServiceTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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 com.android.server.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.location.ILocationListener;
+import android.location.LocationManagerInternal;
+import android.location.LocationRequest;
+import android.location.provider.ProviderRequest;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.LocalServices;
+import com.android.server.location.injector.FakeUserInfoHelper;
+import com.android.server.location.injector.TestInjector;
+import com.android.server.location.provider.AbstractLocationProvider;
+import com.android.server.location.provider.LocationProviderManager;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
+
+import com.google.common.util.concurrent.MoreExecutors;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import java.util.Collections;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocationManagerServiceTest {
+    private static final String PROVIDER_WITH_PERMISSION = "provider_with_permission";
+    private static final String PROVIDER_WITHOUT_PERMISSION = "provider_without_permission";
+    private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID;
+    private static final String CALLER_PACKAGE = "caller_package";
+    private static final String MISSING_PERMISSION = "missing_permission";
+
+    private TestInjector mInjector;
+    private LocationManagerService mLocationManagerService;
+
+    @Spy private FakeAbstractLocationProvider mProviderWithPermission;
+    @Spy private FakeAbstractLocationProvider mProviderWithoutPermission;
+    @Mock private ILocationListener mLocationListener;
+    @Mock private IBinder mBinder;
+    @Mock private Context mContext;
+    @Mock private Resources mResources;
+    @Mock private PackageManager mPackageManager;
+    @Mock private AppOpsManager mAppOpsManager;
+    @Mock private PowerManager mPowerManager;
+    @Mock private PowerManager.WakeLock mWakeLock;
+    @Mock private LegacyPermissionManagerInternal mPermissionManagerInternal;
+
+    @Before
+    public void setUp() {
+        initMocks(this);
+
+        doReturn(mContext).when(mContext).createAttributionContext(any());
+        doReturn("android").when(mContext).getPackageName();
+        doReturn(mResources).when(mContext).getResources();
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
+        doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
+        doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
+        String[] packages = {CALLER_PACKAGE};
+        doReturn(InstrumentationRegistry.getInstrumentation().getContext().getContentResolver())
+                .when(mContext)
+                .getContentResolver();
+        doReturn(packages).when(mPackageManager).getPackagesForUid(anyInt());
+        doReturn(mBinder).when(mLocationListener).asBinder();
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext)
+                .checkCallingOrSelfPermission(MISSING_PERMISSION);
+
+        mInjector = new TestInjector(mContext);
+        mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, true);
+
+        LocalServices.addService(LegacyPermissionManagerInternal.class, mPermissionManagerInternal);
+
+        mLocationManagerService = new LocationManagerService(mContext, mInjector);
+
+        LocationProviderManager managerWithPermission =
+                new LocationProviderManager(
+                        mContext, mInjector, PROVIDER_WITH_PERMISSION, /* passiveManager= */ null);
+        mLocationManagerService.addLocationProviderManager(
+                managerWithPermission, mProviderWithPermission);
+        LocationProviderManager managerWithoutPermission =
+                new LocationProviderManager(
+                        mContext,
+                        mInjector,
+                        PROVIDER_WITHOUT_PERMISSION,
+                        /* passiveManager= */ null,
+                        Collections.singletonList(MISSING_PERMISSION));
+        mLocationManagerService.addLocationProviderManager(
+                managerWithoutPermission, mProviderWithoutPermission);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        LocalServices.removeServiceForTest(LegacyPermissionManagerInternal.class);
+        LocalServices.removeServiceForTest(LocationManagerInternal.class);
+    }
+
+    @Test
+    public void testRequestLocationUpdates() {
+        LocationRequest request = new LocationRequest.Builder(0).build();
+        mLocationManagerService.registerLocationListener(
+                PROVIDER_WITH_PERMISSION,
+                request,
+                mLocationListener,
+                CALLER_PACKAGE,
+                /* attributionTag= */ null,
+                "any_listener_id");
+        verify(mProviderWithPermission).onSetRequestPublic(any());
+    }
+
+    @Test
+    public void testRequestLocationUpdates_noPermission() {
+        LocationRequest request = new LocationRequest.Builder(0).build();
+        assertThrows(
+                IllegalArgumentException.class,
+                () ->
+                        mLocationManagerService.registerLocationListener(
+                                PROVIDER_WITHOUT_PERMISSION,
+                                request,
+                                mLocationListener,
+                                CALLER_PACKAGE,
+                                /* attributionTag= */ null,
+                                "any_listener_id"));
+    }
+
+    @Test
+    public void testHasProvider() {
+        assertThat(mLocationManagerService.hasProvider(PROVIDER_WITH_PERMISSION)).isTrue();
+    }
+
+    @Test
+    public void testHasProvider_noPermission() {
+        assertThat(mLocationManagerService.hasProvider(PROVIDER_WITHOUT_PERMISSION)).isFalse();
+    }
+
+    @Test
+    public void testGetAllProviders() {
+        assertThat(mLocationManagerService.getAllProviders()).contains(PROVIDER_WITH_PERMISSION);
+        assertThat(mLocationManagerService.getAllProviders())
+                .doesNotContain(PROVIDER_WITHOUT_PERMISSION);
+    }
+
+    abstract static class FakeAbstractLocationProvider extends AbstractLocationProvider {
+        FakeAbstractLocationProvider() {
+            super(
+                    MoreExecutors.directExecutor(),
+                    /* identity= */ null,
+                    /* properties= */ null,
+                    /* extraAttributionTags= */ Collections.emptySet());
+            setAllowed(true);
+        }
+
+        @Override
+        protected void onSetRequest(ProviderRequest request) {
+            // Call a public version of this method so mockito can verify.
+            onSetRequestPublic(request);
+        }
+
+        public abstract void onSetRequestPublic(ProviderRequest request);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index aa28ad489027f90074647abec20aaa7e0ddfd64b..7dc1935f89ba1efa191681979104c7ebd40eaccc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -102,6 +102,7 @@ import org.mockito.Mock;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Random;
@@ -133,6 +134,7 @@ public class LocationProviderManagerTest {
     private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
             "mypackage", "attribution", "listener");
     private static final WorkSource WORK_SOURCE = new WorkSource(IDENTITY.getUid());
+    private static final String MISSING_PERMISSION = "missing_permission";
 
     private Random mRandom;
 
@@ -173,6 +175,9 @@ public class LocationProviderManagerTest {
         doReturn(mPackageManager).when(mContext).getPackageManager();
         doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
         doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext)
+                .checkCallingOrSelfPermission(MISSING_PERMISSION);
 
         mInjector = new TestInjector(mContext);
         mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, true);
@@ -187,12 +192,18 @@ public class LocationProviderManagerTest {
     }
 
     private void createManager(String name) {
+        createManager(name, Collections.emptyList());
+    }
+
+    private void createManager(String name, Collection<String> requiredPermissions) {
         mStateChangedListener = mock(LocationProviderManager.StateChangedListener.class);
 
         mProvider = new TestProvider(PROPERTIES, PROVIDER_IDENTITY);
         mProvider.setProviderAllowed(true);
 
-        mManager = new LocationProviderManager(mContext, mInjector, name, mPassive);
+        mManager =
+                new LocationProviderManager(
+                        mContext, mInjector, name, mPassive, requiredPermissions);
         mManager.startManager(mStateChangedListener);
         mManager.setRealProvider(mProvider);
     }
@@ -1317,6 +1328,17 @@ public class LocationProviderManagerTest {
         assertThat(mInjector.getPackageResetHelper().isResetableForPackage("mypackage")).isFalse();
     }
 
+    @Test
+    public void testIsVisibleToCaller() {
+        assertThat(mManager.isVisibleToCaller()).isTrue();
+    }
+
+    @Test
+    public void testIsVisibleToCaller_noPermissions() {
+        createManager("any_name", Collections.singletonList(MISSING_PERMISSION));
+        assertThat(mManager.isVisibleToCaller()).isFalse();
+    }
+
     private ILocationListener createMockLocationListener() {
         return spy(new ILocationListener.Stub() {
             @Override