Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93f34aa1 authored by Eva Chen's avatar Eva Chen
Browse files

Add test provider commands to location shell commands.

Test: Presubmits and manual testing
Bug: 176256956
Change-Id: I0fc90fd4b17291d55d4ee8115abe7dae2d676250
parent 8337a179
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1179,7 +1179,7 @@ public class LocationManagerService extends ILocationManager.Stub {
    @Override
    public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out,
            ParcelFileDescriptor err, String[] args) {
        return new LocationShellCommand(this).exec(
        return new LocationShellCommand(mContext, this).exec(
                this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(),
                args);
    }
+186 −9
Original line number Diff line number Diff line
@@ -16,21 +16,29 @@

package com.android.server.location;

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.provider.ProviderProperties;
import android.os.UserHandle;

import com.android.modules.utils.BasicShellCommandHandler;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Objects;

/**
 * Interprets and executes 'adb shell cmd location [args]'.
 */
class LocationShellCommand extends BasicShellCommandHandler {
    private static final float DEFAULT_TEST_LOCATION_ACCURACY = 100.0f;

    private final Context mContext;
    private final LocationManagerService mService;

    LocationShellCommand(LocationManagerService service) {
    LocationShellCommand(Context context, LocationManagerService service) {
        mContext = context;
        mService = Objects.requireNonNull(service);
    }

@@ -47,6 +55,44 @@ class LocationShellCommand extends BasicShellCommandHandler {
                mService.setLocationEnabledForUser(enabled, userId);
                return 0;
            }
            case "providers": {
                String command = getNextArgRequired();
                return parseProvidersCommand(command);
            }
            default:
                return handleDefaultCommands(cmd);
        }
    }

    private int parseProvidersCommand(String cmd) {
        switch (cmd) {
            case "add-test-provider": {
                String provider = getNextArgRequired();
                ProviderProperties properties = parseTestProviderProviderProperties();
                mService.addTestProvider(provider, properties, mContext.getOpPackageName(),
                        mContext.getFeatureId());
                return 0;
            }
            case "remove-test-provider": {
                String provider = getNextArgRequired();
                mService.removeTestProvider(provider, mContext.getOpPackageName(),
                        mContext.getFeatureId());
                return 0;
            }
            case "set-test-provider-enabled": {
                String provider = getNextArgRequired();
                boolean enabled = Boolean.parseBoolean(getNextArgRequired());
                mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName(),
                        mContext.getFeatureId());
                return 0;
            }
            case "set-test-provider-location": {
                String provider = getNextArgRequired();
                Location location = parseTestProviderLocation(provider);
                mService.setTestProviderLocation(provider, location, mContext.getOpPackageName(),
                        mContext.getFeatureId());
                return 0;
            }
            case "send-extra-command": {
                String provider = getNextArgRequired();
                String command = getNextArgRequired();
@@ -72,6 +118,120 @@ class LocationShellCommand extends BasicShellCommandHandler {
        return UserHandle.USER_CURRENT_OR_SELF;
    }

    private ProviderProperties parseTestProviderProviderProperties() {
        boolean requiresNetwork = false;
        boolean requiresSatellite = false;
        boolean requiresCell = false;
        boolean hasMonetaryCost = false;
        boolean supportsAltitude = false;
        boolean supportsSpeed = false;
        boolean supportsBearing = false;
        int powerRequirement = Criteria.POWER_LOW;
        int accuracy = Criteria.ACCURACY_FINE;

        String option = getNextOption();
        while (option != null) {
            switch (option) {
                case "--requiresNetwork": {
                    requiresNetwork = true;
                    break;
                }
                case "--requiresSatellite": {
                    requiresSatellite = true;
                    break;
                }
                case "--requiresCell": {
                    requiresCell = true;
                    break;
                }
                case "--hasMonetaryCost": {
                    hasMonetaryCost = true;
                    break;
                }
                case "--supportsAltitude": {
                    supportsAltitude = true;
                    break;
                }
                case "--supportsSpeed": {
                    supportsSpeed = true;
                    break;
                }
                case "--supportsBearing": {
                    supportsBearing = true;
                    break;
                }
                case "--powerRequirement": {
                    powerRequirement = Integer.parseInt(getNextArgRequired());
                    break;
                }
                case "--accuracy": {
                    accuracy = Integer.parseInt(getNextArgRequired());
                    break;
                }
                default:
                    throw new IllegalArgumentException(
                            "Received unexpected option: " + option);
            }
            option = getNextOption();
        }

        ProviderProperties properties = new ProviderProperties.Builder()
                .setHasNetworkRequirement(requiresNetwork)
                .setHasSatelliteRequirement(requiresSatellite)
                .setHasCellRequirement(requiresCell)
                .setHasMonetaryCost(hasMonetaryCost)
                .setHasAltitudeSupport(supportsAltitude)
                .setHasSpeedSupport(supportsSpeed)
                .setHasBearingSupport(supportsBearing)
                .setPowerUsage(powerRequirement)
                .setAccuracy(accuracy)
                .build();

        return properties;
    }

    private Location parseTestProviderLocation(String provider) {
        boolean hasLatitude = false;
        boolean hasLongitude = false;

        Location location = new Location(provider);
        location.setAccuracy(DEFAULT_TEST_LOCATION_ACCURACY);
        location.setTime(System.currentTimeMillis());

        String option = getNextOption();
        while (option != null) {
            switch (option) {
                case "--location": {
                    String[] locationInput = getNextArgRequired().split(",");
                    if (locationInput.length != 2) {
                        throw new IllegalArgumentException(
                                "Unexpected location format: " + Arrays.toString(locationInput));
                    }

                    location.setLatitude(Double.parseDouble(locationInput[0]));
                    location.setLongitude(Double.parseDouble(locationInput[1]));
                    break;
                }
                case "--accuracy": {
                    location.setAccuracy(Float.parseFloat(getNextArgRequired()));
                    break;
                }
                case "--time": {
                    location.setTime(Long.parseLong(getNextArgRequired()));
                    break;
                }
                default:
                    throw new IllegalArgumentException(
                            "Received unexpected option: " + option);
            }
            option = getNextOption();
        }

        location.setElapsedRealtimeNanos(System.nanoTime());

        return location;
    }

    @Override
    public void onHelp() {
        PrintWriter pw = getOutPrintWriter();
@@ -80,6 +240,23 @@ class LocationShellCommand extends BasicShellCommandHandler {
        pw.println("    Print this help text.");
        pw.println("  set-location-enabled [--user <USER_ID>] true|false");
        pw.println("    Sets the master location switch enabled state.");
        pw.println("  providers");
        pw.println("    add-test-provider <PROVIDER> [--requiresNetwork] [--requiresSatellite]");
        pw.println("      [--requiresCell] [--hasMonetaryCost] [--supportsAltitude]");
        pw.println("      [--supportsSpeed] [--supportsBearing]");
        pw.println("      [--powerRequirement <POWER_REQUIREMENT>]");
        pw.println("      Add the given test provider. Requires MOCK_LOCATION permissions which");
        pw.println("      can be enabled by running \"adb shell appops set <uid>");
        pw.println("      android:mock_location allow\". There are optional flags that can be");
        pw.println("      used to configure the provider properties. If no flags are included,");
        pw.println("      then default values will be used.");
        pw.println("    remove-test-provider <PROVIDER>");
        pw.println("      Remove the given test provider.");
        pw.println("    set-test-provider-enabled <PROVIDER> true|false");
        pw.println("      Sets the given test provider enabled state.");
        pw.println("    set-test-provider-location <PROVIDER> [--location <LATITUDE>,<LONGITUDE>]");
        pw.println("      [--accuracy <ACCURACY>] [--time <TIME>]");
        pw.println("      Set location for given test provider. Accuracy and time are optional.");
        pw.println("    send-extra-command <PROVIDER> <COMMAND>");
        pw.println("      Sends the given extra command to the given provider.");
        pw.println();