Allow location provider to deep link into permissions UI
Test: Built
Bug: 118437704
Change-Id: I566acaf09bad27a47ec3822816c136c01b18bfc9
diff --git a/api/system-current.txt b/api/system-current.txt
index d8f7f4a..6bb6d50 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1052,6 +1052,7 @@
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 @@
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 @@
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);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6c0fa4c..aa34da8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1753,6 +1753,30 @@
"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>
* Input: Nothing.
@@ -1882,8 +1906,8 @@
/**
* 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.
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 1276881..b5d835a 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -120,4 +120,18 @@
// 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);
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index b1968ba..02680ab 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -22,6 +22,7 @@
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.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 @@
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;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 90ad09e..046442a 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -18,6 +18,7 @@
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.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.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
/**
@@ -3420,6 +3423,48 @@
}
}
+ @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);