diff --git a/api/system-current.txt b/api/system-current.txt index e6a3e9bf3e8e0..e525a71567c42 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1370,6 +1370,14 @@ package android.bluetooth.le { } +package android.companion { + + public final class CompanionDeviceManager { + method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociated(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle); + } + +} + package android.content { public class ContentProviderClient implements java.lang.AutoCloseable { diff --git a/api/test-current.txt b/api/test-current.txt index a060dfcb83112..5247bd1fa16a6 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -640,6 +640,14 @@ package android.bluetooth { } +package android.companion { + + public final class CompanionDeviceManager { + method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociated(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle); + } + +} + package android.content { public final class AutofillOptions implements android.os.Parcelable { diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index 9cb73f931773a..28cc1f8fc107f 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -21,7 +21,10 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.app.Activity; import android.app.Application; import android.app.PendingIntent; @@ -29,9 +32,11 @@ import android.content.ComponentName; import android.content.Context; import android.content.IntentSender; import android.content.pm.PackageManager; +import android.net.MacAddress; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; +import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.util.Log; @@ -252,6 +257,38 @@ public final class CompanionDeviceManager { } } + /** + * Check if a given package was {@link #associate associated} with a device with given + * mac address by given user. + * + * @param packageName the package to check for + * @param macAddress the mac address or BSSID of the device to check for + * @param user the user to check for + * @return whether a corresponding association record exists + * + * @hide + */ + @SystemApi + @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES) + public boolean isDeviceAssociated( + @NonNull String packageName, + @NonNull MacAddress macAddress, + @NonNull UserHandle user) { + if (!checkFeaturePresent()) { + return false; + } + checkNotNull(packageName, "package name cannot be null"); + checkNotNull(macAddress, "mac address cannot be null"); + checkNotNull(user, "user cannot be null"); + try { + return mService.isDeviceAssociated( + packageName, macAddress.toString(), user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private boolean checkFeaturePresent() { boolean featurePresent = mService != null; if (!featurePresent && DEBUG) { diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index 561342efb3ba2..2e1ff0be85773 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -39,4 +39,6 @@ interface ICompanionDeviceManager { boolean hasNotificationAccess(in ComponentName component); PendingIntent requestNotificationAccess(in ComponentName component); + + boolean isDeviceAssociated(in String packageName, in String macAddress, int userId); } diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java index f9cf23b29a696..4165f202998cb 100644 --- a/core/java/com/android/internal/util/CollectionUtils.java +++ b/core/java/com/android/internal/util/CollectionUtils.java @@ -230,6 +230,15 @@ public class CollectionUtils { return find(items, predicate) != null; } + /** + * Returns whether there exists at least one element in the set for which + * condition {@code predicate} is true + */ + public static boolean any(@Nullable Set items, + java.util.function.Predicate predicate) { + return find(items, predicate) != null; + } + /** * Returns the first element from the list for which * condition {@code predicate} is true, or null if there is no such element @@ -244,6 +253,37 @@ public class CollectionUtils { return null; } + /** + * Returns the first element from the set for which + * condition {@code predicate} is true, or null if there is no such element + */ + public static @Nullable T find(@Nullable Set cur, + java.util.function.Predicate predicate) { + if (cur == null || predicate == null) return null; + int size = cur.size(); + if (size == 0) return null; + try { + if (cur instanceof ArraySet) { + ArraySet arraySet = (ArraySet) cur; + for (int i = 0; i < size; i++) { + T item = arraySet.valueAt(i); + if (predicate.test(item)) { + return item; + } + } + } else { + for (T t : cur) { + if (predicate.test(t)) { + return t; + } + } + } + } catch (Exception e) { + throw ExceptionUtils.propagate(e); + } + return null; + } + /** * Similar to {@link List#add}, but with support for list values of {@code null} and * {@link Collections#emptyList} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 11a5062296543..8fa610240d5ac 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3547,7 +3547,7 @@ + android:protectionLevel="signature|wifi" />