Merge "[Perm Sync] Add an API for the companion app to get the perm sync consent" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 5b339fa..e11f8ce 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9676,6 +9676,7 @@
method @Deprecated @NonNull public java.util.List<java.lang.String> getAssociations();
method @NonNull public java.util.List<android.companion.AssociationInfo> getMyAssociations();
method @Deprecated public boolean hasNotificationAccess(android.content.ComponentName);
+ method @FlaggedApi("android.companion.perm_sync_user_consent") public boolean isPermissionTransferUserConsented(int);
method public void requestNotificationAccess(android.content.ComponentName);
method @FlaggedApi("android.companion.association_tag") public void setAssociationTag(int, @NonNull String);
method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index e0ce917..e4a03c5 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -1358,6 +1358,36 @@
}
/**
+ * Return the current state of consent for permission transfer for the association.
+ * True if the user has allowed permission transfer for the association, false otherwise.
+ *
+ * <p>
+ * Note: The initial user consent is collected via
+ * {@link #buildPermissionTransferUserConsentIntent(int) a permission transfer user consent dialog}.
+ * After the user has made their initial selection, they can toggle the permission transfer
+ * feature in the settings.
+ * This method always returns the state of the toggle setting.
+ * </p>
+ *
+ * @param associationId The unique {@link AssociationInfo#getId ID} assigned to the association
+ * of the companion device recorded by CompanionDeviceManager
+ * @return True if the user has consented to the permission transfer, or false otherwise.
+ * @throws DeviceNotAssociatedException Exception if the companion device is not associated with
+ * the user or the calling app.
+ */
+ @UserHandleAware
+ @FlaggedApi(Flags.FLAG_PERM_SYNC_USER_CONSENT)
+ public boolean isPermissionTransferUserConsented(int associationId) {
+ try {
+ return mService.isPermissionTransferUserConsented(mContext.getOpPackageName(),
+ mContext.getUserId(), associationId);
+ } catch (RemoteException e) {
+ ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Start system data transfer which has been previously approved by the user.
*
* <p>Before calling this method, the app needs to make sure there's a communication channel
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index c5a1988..22689f3 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -97,6 +97,8 @@
PendingIntent buildPermissionTransferUserConsentIntent(String callingPackage, int userId,
int associationId);
+ boolean isPermissionTransferUserConsented(String callingPackage, int userId, int associationId);
+
void startSystemDataTransfer(String packageName, int userId, int associationId,
in ISystemDataTransferCallback callback);
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
index 6e33dff..9e410b8 100644
--- a/core/java/android/companion/flags.aconfig
+++ b/core/java/android/companion/flags.aconfig
@@ -27,3 +27,10 @@
description: "Enable device presence APIs"
bug: "283000075"
}
+
+flag {
+ name: "perm_sync_user_consent"
+ namespace: "companion"
+ description: "Expose perm sync user consent API"
+ bug: "309528663"
+}
\ No newline at end of file
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 71a1f01..cce596b 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -833,6 +833,13 @@
}
@Override
+ public boolean isPermissionTransferUserConsented(String packageName, int userId,
+ int associationId) {
+ return mSystemDataTransferProcessor.isPermissionTransferUserConsented(packageName,
+ userId, associationId);
+ }
+
+ @Override
public void startSystemDataTransfer(String packageName, int userId, int associationId,
ISystemDataTransferCallback callback) {
mSystemDataTransferProcessor.startSystemDataTransfer(packageName, userId,
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index e5c847a..bd646fa 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -120,7 +120,8 @@
* Resolve the requested association, throwing if the caller doesn't have
* adequate permissions.
*/
- private @NonNull AssociationInfo resolveAssociation(String packageName, int userId,
+ @NonNull
+ private AssociationInfo resolveAssociation(String packageName, int userId,
int associationId) {
AssociationInfo association = mAssociationStore.getAssociationById(associationId);
association = PermissionsUtils.sanitizeWithCallerChecks(mContext, association);
@@ -133,6 +134,20 @@
}
/**
+ * Return whether the user has consented to the permission transfer for the association.
+ */
+ public boolean isPermissionTransferUserConsented(String packageName, @UserIdInt int userId,
+ int associationId) {
+ resolveAssociation(packageName, userId, associationId);
+
+ PermissionSyncRequest request = getPermissionSyncRequest(associationId);
+ if (request == null) {
+ return false;
+ }
+ return request.isUserConsented();
+ }
+
+ /**
* Build a PendingIntent of permission sync user consent dialog
*/
public PendingIntent buildPermissionTransferUserConsentIntent(String packageName,