Add permission gated provider to access the hardware GPS directly.
-Only applicable when an app level GPS provider override is present which may mask the hardware provider. Bug: 260010264 Test: atest LocationManagerServiceTest, atest LocationProviderManagerTest Change-Id: I085152f9074863dcf8d8ee96981846b847966018
This commit is contained in:
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 (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);
|
||||
}
|
||||
if (criteria != null && !LocationProvider.propertiesMeetCriteria(name,
|
||||
manager.getProperties(), criteria)) {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user