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

Commit ed988283 authored by Philip P. Moltmann's avatar Philip P. Moltmann
Browse files

Allow location provider to deep link into permissions UI

Test: Built
Bug: 118437704
Change-Id: I566acaf09bad27a47ec3822816c136c01b18bfc9
parent 330f4578
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1052,6 +1052,7 @@ package android.content {
    field public static final java.lang.String ACTION_INSTALL_INSTANT_APP_PACKAGE = "android.intent.action.INSTALL_INSTANT_APP_PACKAGE";
    field public static final java.lang.String ACTION_INSTANT_APP_RESOLVER_SETTINGS = "android.intent.action.INSTANT_APP_RESOLVER_SETTINGS";
    field public static final java.lang.String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
    field public static final java.lang.String ACTION_MANAGE_APP_PERMISSION = "android.intent.action.MANAGE_APP_PERMISSION";
    field public static final java.lang.String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
    field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
    field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
@@ -2719,6 +2720,7 @@ package android.location {
  public class LocationManager {
    method public deprecated boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
    method public deprecated boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
    method public android.app.PendingIntent createManageLocationPermissionIntent(java.lang.String, java.lang.String);
    method public void flushGnssBatch();
    method public int getGnssBatchSize();
    method public java.lang.String getNetworkProviderPackage();
@@ -3645,9 +3647,9 @@ package android.net.wifi {
    method public boolean isPortableHotspotSupported();
    method public boolean isWifiApEnabled();
    method public boolean isWifiScannerSupported();
    method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler);
    method public boolean isWpa3SaeSupported();
    method public boolean isWpa3SuiteBSupported();
    method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler);
    method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
    method public boolean startScan(android.os.WorkSource);
    method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
+26 −2
Original line number Diff line number Diff line
@@ -1752,6 +1752,30 @@ public class Intent implements Parcelable, Cloneable {
    public static final String ACTION_MANAGE_APP_PERMISSIONS =
            "android.intent.action.MANAGE_APP_PERMISSIONS";

    /**
     * Activity action: Launch UI to manage a specific permissions of an app.
     * <p>
     * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose permission
     * will be managed by the launched UI.
     * </p>
     * <p>
     * Input: {@link #EXTRA_PERMISSION_NAME} specifies the (individual) permission
     * that should be managed by the launched UI.
     * </p>
     * <p>
     * Output: Nothing.
     * </p>
     *
     * @see #EXTRA_PACKAGE_NAME
     * @see #EXTRA_PERMISSION_NAME
     *
     * @hide
     */
    @SystemApi
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_MANAGE_APP_PERMISSION =
            "android.intent.action.MANAGE_APP_PERMISSION";

    /**
     * Activity action: Launch UI to manage permissions.
     * <p>
@@ -1882,8 +1906,8 @@ public class Intent implements Parcelable, Cloneable {
    /**
     * Activity action: Launch UI to manage which apps have a given permission.
     * <p>
     * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission access
     * to which will be managed by the launched UI.
     * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission group
     * which will be managed by the launched UI.
     * </p>
     * <p>
     * Output: Nothing.
+14 −0
Original line number Diff line number Diff line
@@ -120,4 +120,18 @@ interface ILocationManager

    // used by gts tests to verify throttling whitelist
    String[] getBackgroundThrottlingWhitelist();

    /**
     * Allow the {@link android.location.LocationManager#getNetworkProviderPackage location
     * provider} to start the UI to modify the location permission for a package.
     *
     * <p>Can only be called by the location provider.
     *
     * @param packageName The package the permission belongs to
     * @param permission The (individual) permission to switch
     *
     * @return A pending intent that starts the permission management UI or {@code null} if the
     *         intent cannot be created
     */
    PendingIntent createManageLocationPermissionIntent(in String packageName, in String permission);
}
+28 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.Manifest.permission.LOCATION_HARDWARE;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
@@ -43,7 +44,9 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;

import com.android.internal.location.ProviderProperties;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -2393,4 +2396,29 @@ public class LocationManager {
            return null;
        }
    }

    /**
     * Allow the {@link android.location.LocationManager#getNetworkProviderPackage location
     * provider} to start the UI to modify the location permission for a package.
     *
     * <p>Can only be called by the location provider.
     *
     * @param packageName The package the permission belongs to
     * @param permission The (individual) location permission to switch
     *
     * @return A one-shot pending intent that starts the permission management UI or {@code null} if
     *         the intent cannot be created
     *
     * @hide
     */
    @SystemApi
    public @Nullable PendingIntent createManageLocationPermissionIntent(@NonNull String packageName,
            @NonNull String permission) {
        try {
            return mService.createManageLocationPermissionIntent(packageName, permission);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
            return null;
        }
    }
}
+45 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server;

import static android.content.pm.PackageManager.PERMISSION_GRANTED;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -83,6 +84,7 @@ import com.android.internal.location.ProviderRequest;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.location.ActivityRecognitionProxy;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
@@ -111,6 +113,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;

/**
@@ -3420,6 +3423,48 @@ public class LocationManagerService extends ILocationManager.Stub {
        }
    }

    @Override
    public PendingIntent createManageLocationPermissionIntent(String packageName,
            String permission) {
        Preconditions.checkNotNull(packageName);
        Preconditions.checkArgument(permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)
                || permission.equals(Manifest.permission.ACCESS_COARSE_LOCATION)
                || permission.equals(Manifest.permission.ACCESS_BACKGROUND_LOCATION));

        int callingUid = Binder.getCallingUid();
        long token = Binder.clearCallingIdentity();
        try {
            String locProvider = getNetworkProviderPackage();
            if (locProvider == null) {
                return null;
            }

            PackageInfo locProviderInfo;
            try {
                locProviderInfo = mContext.getPackageManager().getPackageInfo(
                        locProvider, PackageManager.MATCH_DIRECT_BOOT_AUTO);
            } catch (NameNotFoundException e) {
                Log.e(TAG, "Could not resolve " + locProvider, e);
                return null;
            }

            if (locProviderInfo.applicationInfo.uid != callingUid) {
                throw new SecurityException("Only " + locProvider + " can call this API");
            }

            Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION);
            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
            intent.putExtra(Intent.EXTRA_PERMISSION_NAME, permission);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            return PendingIntent.getActivity(mContext,
                    Objects.hash(packageName, permission), intent,
                    PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    private void log(String log) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Slog.d(TAG, log);