Add lost mode platform changes
Changes:
* Add SEND_LOST_MODE_LOCATION_UPDATES permission.
* Add DPM.sendLostModeLocationUpdate API.
* Add intent action and extras to send lost mode
location updates to the DPC.
* Add DPM attribution tag
Manual testing:
* Add lost mode receiver to TestDPC
* Call new API in GmsCore using reflection
* Verify API call is successful and the
lost mode receiver receives the location update
Bug: 206945072
Test: atest com.android.server.devicepolicy.DevicePolicyManagerTest
manual testing
Change-Id: I9374a53c1146143c8f5bff3ac38cfe18d3f0bf2f
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 80f7a70..801500e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -287,6 +287,7 @@
field public static final String SECURE_ELEMENT_PRIVILEGED_OPERATION = "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
field public static final String SEND_CATEGORY_CAR_NOTIFICATIONS = "android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS";
field public static final String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY";
+ field public static final String SEND_LOST_MODE_LOCATION_UPDATES = "android.permission.SEND_LOST_MODE_LOCATION_UPDATES";
field public static final String SEND_SAFETY_CENTER_UPDATE = "android.permission.SEND_SAFETY_CENTER_UPDATE";
field public static final String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
field public static final String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
@@ -1069,6 +1070,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull int[]);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetStrings(@NonNull String[]);
+ method @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
@@ -1080,6 +1082,7 @@
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE = "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
field @RequiresPermission(android.Manifest.permission.DISPATCH_PROVISIONING_MESSAGE) public static final String ACTION_ESTABLISH_NETWORK_CONNECTION = "android.app.action.ESTABLISH_NETWORK_CONNECTION";
+ field public static final String ACTION_LOST_MODE_LOCATION_UPDATE = "android.app.action.LOST_MODE_LOCATION_UPDATE";
field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
field public static final String ACTION_PROVISION_FINANCED_DEVICE = "android.app.action.PROVISION_FINANCED_DEVICE";
field public static final String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
@@ -1106,6 +1109,7 @@
field public static final int CODE_USER_NOT_RUNNING = 3; // 0x3
field public static final int CODE_USER_SETUP_COMPLETED = 4; // 0x4
field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
+ field public static final String EXTRA_LOST_MODE_LOCATION = "android.app.extra.LOST_MODE_LOCATION";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 96d037c..986e152 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -62,6 +62,7 @@
import android.net.ProxyInfo;
import android.net.Uri;
import android.nfc.NfcAdapter;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -99,6 +100,7 @@
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.net.NetworkUtilsInternal;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.Preconditions;
@@ -133,6 +135,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
// TODO(b/172376923) - add CarDevicePolicyManager examples below (or remove reference to it).
/**
@@ -1795,6 +1798,28 @@
"android.app.action.RESET_PROTECTION_POLICY_CHANGED";
/**
+ * Broadcast action: sent when there is a location update on a device in lost mode. This
+ * broadcast is explicitly sent to the device policy controller app only.
+ *
+ * @see DevicePolicyManager#sendLostModeLocationUpdate
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_LOST_MODE_LOCATION_UPDATE =
+ "android.app.action.LOST_MODE_LOCATION_UPDATE";
+
+ /**
+ * Extra used with {@link #ACTION_LOST_MODE_LOCATION_UPDATE} to send the location of a device
+ * in lost mode. Value is {@code Location}.
+ *
+ * @see DevicePolicyManager#sendLostModeLocationUpdate
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_LOST_MODE_LOCATION =
+ "android.app.extra.LOST_MODE_LOCATION";
+
+ /**
* The ComponentName of the administrator component.
*
* @see #ACTION_ADD_DEVICE_ADMIN
@@ -5824,6 +5849,56 @@
}
/**
+ * Send a lost mode location update to the admin. This API is limited to organization-owned
+ * devices, which includes devices with a device owner or devices with a profile owner on an
+ * organization-owned managed profile.
+ *
+ * <p>The caller must hold the
+ * {@link android.Manifest.permission#SEND_LOST_MODE_LOCATION_UPDATES} permission.
+ *
+ * <p> Not for use by third-party applications.
+ *
+ * @param executor The executor through which the callback should be invoked.
+ * @param callback A callback object that will inform the caller whether a lost mode location
+ * update was successfully sent
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES)
+ public void sendLostModeLocationUpdate(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<Boolean> callback) {
+ throwIfParentInstance("sendLostModeLocationUpdate");
+ if (mService == null) {
+ executeCallback(AndroidFuture.completedFuture(false), executor, callback);
+ return;
+ }
+ try {
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
+ mService.sendLostModeLocationUpdate(future);
+ executeCallback(future, executor, callback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private void executeCallback(AndroidFuture<Boolean> future,
+ @CallbackExecutor @NonNull Executor executor,
+ Consumer<Boolean> callback) {
+ future.whenComplete((result, error) -> executor.execute(() -> {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (error != null) {
+ callback.accept(false);
+ } else {
+ callback.accept(result);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }));
+ }
+
+ /**
* Called by an application that is administering the device to set the
* global proxy and exclusion list.
* <p>
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index f663c17..8fe6b51 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -47,6 +47,7 @@
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keystore.ParcelableKeyGenParameterSpec;
import android.telephony.data.ApnSetting;
+import com.android.internal.infra.AndroidFuture;
import java.util.List;
@@ -119,6 +120,8 @@
FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(in ComponentName who);
boolean isFactoryResetProtectionPolicySupported();
+ void sendLostModeLocationUpdate(in AndroidFuture<boolean> future);
+
ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
ComponentName getGlobalProxyAdmin(int userHandle);
void setRecommendedGlobalProxy(in ComponentName admin, in ProxyInfo proxyInfo);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e84db41..e240504 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2318,6 +2318,14 @@
<permission android:name="android.permission.TRIGGER_LOST_MODE"
android:protectionLevel="signature|role"/>
+ <!-- @SystemApi Allows an application to instruct the framework to send location to the device
+ admin when an organization-owned device is in lost mode.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.SEND_LOST_MODE_LOCATION_UPDATES"
+ android:protectionLevel="signature|privileged"/>
+
<!-- ================================== -->
<!-- Permissions for accessing hardware -->
<!-- ================================== -->
@@ -6212,6 +6220,9 @@
<p>Not for use by third-party applications.</p> -->
<attribution android:tag="MusicRecognitionManagerService"
android:label="@string/music_recognition_manager_service"/>
+ <!-- Attribution for Device Policy Manager service. -->
+ <attribution android:tag="DevicePolicyManagerService"
+ android:label="@string/device_policy_manager_service"/>
<application android:process="system"
android:persistent="true"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1a5d8b7..eecebb6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -521,6 +521,8 @@
<string name="twilight_service">Twilight Service</string>
<!-- Attribution for Gnss Time Update service. [CHAR LIMIT=NONE]-->
<string name="gnss_time_update_service">GNSS Time Update Service</string>
+ <!-- Attribution for Device Policy Manager service. [CHAR LIMIT=NONE]-->
+ <string name="device_policy_manager_service">Device Policy Manager Service</string>
<!-- Attribution for MusicRecognitionManagerService. [CHAR LIMIT=NONE]-->
<string name="music_recognition_manager_service">Music Recognition Manager Service</string>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index de086df..0e06fac 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -528,6 +528,7 @@
<!-- Permissions required for CTS test - CtsSafetyCenterTestCases -->
<permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
+ <permission name="android.permission.SEND_LOST_MODE_LOCATION_UPDATES" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 46e24fa..c6fbfd8 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -110,6 +110,7 @@
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.READ_INSTALL_SESSIONS" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
+ <uses-permission android:name="android.permission.SEND_LOST_MODE_LOCATION_UPDATES" />
<!-- ACCESS_BACKGROUND_LOCATION is needed for testing purposes only. -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- ACCESS_MTP is needed for testing purposes only. -->
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 40196db..1d6684d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -245,6 +245,7 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.hardware.usb.UsbManager;
+import android.location.Location;
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.IAudioService;
@@ -260,6 +261,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -325,6 +327,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.LocalePicker;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.NetworkUtilsInternal;
@@ -404,6 +407,8 @@
protected static final String LOG_TAG = "DevicePolicyManager";
+ private static final String ATTRIBUTION_TAG = "DevicePolicyManagerService";
+
static final boolean VERBOSE_LOG = false; // DO NOT SUBMIT WITH TRUE
static final String DEVICE_POLICIES_XML = "device_policies.xml";
@@ -1772,7 +1777,7 @@
* Instantiates the service.
*/
public DevicePolicyManagerService(Context context) {
- this(new Injector(context));
+ this(new Injector(context.createAttributionContext(ATTRIBUTION_TAG)));
}
@VisibleForTesting
@@ -7209,6 +7214,64 @@
return getFrpManagementAgentUid() != -1;
}
+ @Override
+ public void sendLostModeLocationUpdate(AndroidFuture<Boolean> future) {
+ if (!mHasFeature) {
+ future.complete(false);
+ return;
+ }
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.SEND_LOST_MODE_LOCATION_UPDATES));
+
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
+ UserHandle.USER_SYSTEM);
+ Preconditions.checkState(admin != null,
+ "Lost mode location updates can only be sent on an organization-owned device.");
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ final List<String> providers =
+ mInjector.getLocationManager().getAllProviders().stream()
+ .filter(mInjector.getLocationManager()::isProviderEnabled)
+ .collect(Collectors.toList());
+ if (providers.isEmpty()) {
+ future.complete(false);
+ return;
+ }
+
+ final CancellationSignal cancellationSignal = new CancellationSignal();
+ List<String> providersWithNullLocation = new ArrayList<String>();
+ for (String provider : providers) {
+ mInjector.getLocationManager().getCurrentLocation(provider, cancellationSignal,
+ mContext.getMainExecutor(), location -> {
+ if (cancellationSignal.isCanceled()) {
+ return;
+ } else if (location != null) {
+ sendLostModeLocationUpdate(admin, location);
+ cancellationSignal.cancel();
+ future.complete(true);
+ } else {
+ // location == null, provider wasn't able to get location, see
+ // if there are more providers
+ providersWithNullLocation.add(provider);
+ if (providers.size() == providersWithNullLocation.size()) {
+ future.complete(false);
+ }
+ }
+ }
+ );
+ }
+ });
+ }
+ }
+
+ private void sendLostModeLocationUpdate(ActiveAdmin admin, Location location) {
+ final Intent intent = new Intent(
+ DevicePolicyManager.ACTION_LOST_MODE_LOCATION_UPDATE);
+ intent.putExtra(DevicePolicyManager.EXTRA_LOST_MODE_LOCATION, location);
+ intent.setPackage(admin.info.getPackageName());
+ mContext.sendBroadcastAsUser(intent, admin.getUserHandle());
+ }
+
/**
* Called by a privileged caller holding {@code BIND_DEVICE_ADMIN} permission to retrieve
* the remove warning for the given device admin.
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 842a438..63dfc85 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -7962,6 +7962,51 @@
() -> WifiSsidPolicy.createDenylistPolicy(ssids));
}
+ @Test
+ public void testSendLostModeLocationUpdate_noPermission() {
+ assertThrows(SecurityException.class, () -> dpm.sendLostModeLocationUpdate(
+ getServices().executor, /* empty callback */ result -> {}));
+ }
+
+ @Test
+ public void testSendLostModeLocationUpdate_notOrganizationOwnedDevice() {
+ mContext.callerPermissions.add(permission.SEND_LOST_MODE_LOCATION_UPDATES);
+ assertThrows(IllegalStateException.class, () -> dpm.sendLostModeLocationUpdate(
+ getServices().executor, /* empty callback */ result -> {}));
+ }
+
+ @Test
+ public void testSendLostModeLocationUpdate_asDeviceOwner() throws Exception {
+ final String TEST_PROVIDER = "network";
+ mContext.callerPermissions.add(permission.SEND_LOST_MODE_LOCATION_UPDATES);
+ setDeviceOwner();
+ when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER));
+ when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true);
+
+ dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {});
+
+ verify(getServices().locationManager, times(1)).getCurrentLocation(
+ eq(TEST_PROVIDER), any(), eq(getServices().executor), any());
+ }
+
+ @Test
+ public void testSendLostModeLocationUpdate_asProfileOwnerOfOrgOwnedDevice() throws Exception {
+ final String TEST_PROVIDER = "network";
+ final int MANAGED_PROFILE_ADMIN_UID =
+ UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
+ mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+ mContext.callerPermissions.add(permission.SEND_LOST_MODE_LOCATION_UPDATES);
+ addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
+ when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER));
+ when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true);
+
+ dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {});
+
+ verify(getServices().locationManager, times(1)).getCurrentLocation(
+ eq(TEST_PROVIDER), any(), eq(getServices().executor), any());
+ }
+
private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) {
final AppOpsManager.PackageOps vpnOp = new AppOpsManager.PackageOps(userVpnPackage,
userVpnUid, List.of(new AppOpsManager.OpEntry(
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 6eb2085..2cf67f8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -47,6 +47,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executor;
/**
* Context used throughout DPMS tests.
@@ -234,6 +235,8 @@
return mMockSystemServices.vpnManager;
case Context.DEVICE_POLICY_SERVICE:
return mMockSystemServices.devicePolicyManager;
+ case Context.LOCATION_SERVICE:
+ return mMockSystemServices.locationManager;
}
throw new UnsupportedOperationException();
}
@@ -493,6 +496,11 @@
}
@Override
+ public Executor getMainExecutor() {
+ return mMockSystemServices.executor;
+ }
+
+ @Override
public int checkCallingPermission(String permission) {
return checkPermission(permission);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 597a165..21fb2da 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -47,6 +47,7 @@
import android.content.pm.UserInfo;
import android.database.Cursor;
import android.hardware.usb.UsbManager;
+import android.location.LocationManager;
import android.media.IAudioService;
import android.net.ConnectivityManager;
import android.net.IIpConnectivityMetrics;
@@ -81,6 +82,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -90,6 +92,7 @@
public final File systemUserDataDir;
public final EnvironmentForMock environment;
public final SystemPropertiesForMock systemProperties;
+ public final Executor executor;
public final UserManager userManager;
public final UserManagerInternal userManagerInternal;
public final UsageStatsManagerInternal usageStatsManagerInternal;
@@ -127,6 +130,7 @@
public final UsbManager usbManager;
public final VpnManager vpnManager;
public final DevicePolicyManager devicePolicyManager;
+ public final LocationManager locationManager;
/** Note this is a partial mock, not a real mock. */
public final PackageManager packageManager;
public final BuildMock buildMock = new BuildMock();
@@ -138,6 +142,7 @@
environment = mock(EnvironmentForMock.class);
systemProperties = mock(SystemPropertiesForMock.class);
+ executor = mock(Executor.class);
userManager = mock(UserManager.class);
userManagerInternal = mock(UserManagerInternal.class);
usageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
@@ -175,6 +180,7 @@
usbManager = mock(UsbManager.class);
vpnManager = mock(VpnManager.class);
devicePolicyManager = mock(DevicePolicyManager.class);
+ locationManager = mock(LocationManager.class);
// Package manager is huge, so we use a partial mock instead.
packageManager = spy(realContext.getPackageManager());