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

Commit 74a54c9f authored by Sergey Nikolaienkov's avatar Sergey Nikolaienkov
Browse files

Refresh CompanionDeviceManager's API surface

Make the AssociationInfo and DeviceId classes public.

Deprecate the existing public associate() method that take a callback
based on onDeviceFound(), and introduce a new one that takes an
AssociationRequestCallback.

Deprecate the existing public disassociate() method that takes a MAC
address, and introduce another one that takes an associationId.

Deprecate the existing public getAssociations() method that returns a
list of MAC addresses, and introduce a new public method
getMyAssociations() that retuns a list of AssociationInfo objects.

Introduce new system API to retrieve list of all associations for a
user: getAllAssociations().

Introduce new system APIs for monitoring changes to the existing
associations: OnAssociationsChangedListener interface, and
add(remove)OnAssociationsChangedListener() methods.

Bug: 194301022
Test: atest CompanionDeviceManagerTest
Test: atest BluetoothInstrumentationTests
Test: atest SettingsRoboTests:NotificationBackendTest
Change-Id: Ic0235db29b26ed1a427c71edb2eb0df76fa4dc4c
parent 3c8b0b82
Loading
Loading
Loading
Loading
+23 −6
Original line number Diff line number Diff line
@@ -9948,6 +9948,16 @@ package android.bluetooth.le {
package android.companion {
  public final class AssociationInfo implements android.os.Parcelable {
    method public int describeContents();
    method @Nullable public android.net.MacAddress getDeviceMacAddress();
    method @Nullable public String getDeviceProfile();
    method @Nullable public CharSequence getDisplayName();
    method public int getId();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.companion.AssociationInfo> CREATOR;
  }
  public final class AssociationRequest implements android.os.Parcelable {
    method public int describeContents();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -9960,6 +9970,7 @@ package android.companion {
    method @NonNull public android.companion.AssociationRequest.Builder addDeviceFilter(@Nullable android.companion.DeviceFilter<?>);
    method @NonNull public android.companion.AssociationRequest build();
    method @NonNull public android.companion.AssociationRequest.Builder setDeviceProfile(@NonNull String);
    method @NonNull public android.companion.AssociationRequest.Builder setDisplayName(@NonNull CharSequence);
    method @NonNull public android.companion.AssociationRequest.Builder setSingleDevice(boolean);
  }
@@ -9995,20 +10006,26 @@ package android.companion {
  }
  public final class CompanionDeviceManager {
    method @RequiresPermission(value=android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull android.companion.CompanionDeviceManager.Callback, @Nullable android.os.Handler);
    method public void disassociate(@NonNull String);
    method @NonNull public java.util.List<java.lang.String> getAssociations();
    method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, "android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING", "android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION"}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull android.companion.CompanionDeviceManager.Callback, @Nullable android.os.Handler);
    method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, "android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING", "android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION"}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.Callback);
    method @Deprecated public void disassociate(@NonNull String);
    method public void disassociate(int);
    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 public void requestNotificationAccess(android.content.ComponentName);
    method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
    method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
    field public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE";
    field public static final String EXTRA_ASSOCIATION = "android.companion.extra.ASSOCIATION";
    field @Deprecated public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE";
  }
  public abstract static class CompanionDeviceManager.Callback {
    ctor public CompanionDeviceManager.Callback();
    method public abstract void onDeviceFound(android.content.IntentSender);
    method public abstract void onFailure(CharSequence);
    method public void onAssociationCreated(@NonNull android.companion.AssociationInfo);
    method public void onAssociationPending(@NonNull android.content.IntentSender);
    method @Deprecated public void onDeviceFound(@NonNull android.content.IntentSender);
    method public abstract void onFailure(@Nullable CharSequence);
  }
  public abstract class CompanionDeviceService extends android.app.Service {
+20 −0
Original line number Diff line number Diff line
@@ -256,6 +256,7 @@ package android {
    field public static final String RENOUNCE_PERMISSIONS = "android.permission.RENOUNCE_PERMISSIONS";
    field public static final String REQUEST_COMPANION_PROFILE_APP_STREAMING = "android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING";
    field public static final String REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION = "android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION";
    field public static final String REQUEST_COMPANION_SELF_MANAGED = "android.permission.REQUEST_COMPANION_SELF_MANAGED";
    field public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
    field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
    field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
@@ -2343,15 +2344,34 @@ package android.bluetooth.le {
package android.companion {
  public final class AssociationInfo implements android.os.Parcelable {
    method @NonNull public String getPackageName();
    method public boolean isSelfManaged();
  }
  public final class AssociationRequest implements android.os.Parcelable {
    method @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public boolean isForceConfirmation();
    method @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public boolean isSelfManaged();
    field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING) public static final String DEVICE_PROFILE_APP_STREAMING = "android.app.role.COMPANION_DEVICE_APP_STREAMING";
    field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION) public static final String DEVICE_PROFILE_AUTOMOTIVE_PROJECTION = "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION";
  }
  public static final class AssociationRequest.Builder {
    method @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setForceConfirmation(boolean);
    method @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setSelfManaged(boolean);
  }
  public final class CompanionDeviceManager {
    method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public void addOnAssociationsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.OnAssociationsChangedListener);
    method @RequiresPermission(android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES) public void associate(@NonNull String, @NonNull android.net.MacAddress, @NonNull byte[]);
    method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean canPairWithoutPrompt(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
    method @NonNull @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public java.util.List<android.companion.AssociationInfo> getAllAssociations();
    method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociatedForWifiConnection(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
    method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public void removeOnAssociationsChangedListener(@NonNull android.companion.CompanionDeviceManager.OnAssociationsChangedListener);
  }
  public static interface CompanionDeviceManager.OnAssociationsChangedListener {
    method public void onAssociationsChanged(@NonNull java.util.List<android.companion.AssociationInfo>);
  }
}
+50 −12
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package android.companion;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
import android.net.MacAddress;
import android.os.Parcel;
@@ -26,11 +27,12 @@ import java.util.Date;
import java.util.Objects;

/**
 * A record indicating that a device with a given address was confirmed by the user to be
 * associated to a given companion app
 *
 * @hide
 * TODO(b/1979395): un-hide.
 * Details for a specific "association" that has been established between an app and companion
 * device.
 * <p>
 * An association gives an app the ability to interact with a companion device without needing to
 * acquire broader runtime permissions. An association only exists after the user has confirmed that
 * an app should have access to a companion device.
 */
public final class AssociationInfo implements Parcelable {
    /**
@@ -90,12 +92,19 @@ public final class AssociationInfo implements Parcelable {
        return mId;
    }

    /** @hide */
    public int getUserId() {
    /**
     * @return the ID of the user who "owns" this association.
     * @hide
     */
    public @UserIdInt int getUserId() {
        return mUserId;
    }

    /** @hide */
    /**
     * @return the package name of the app which this association refers to.
     * @hide
     */
    @SystemApi
    public @NonNull String getPackageName() {
        return mPackageName;
    }
@@ -113,17 +122,19 @@ public final class AssociationInfo implements Parcelable {
    }

    /**
     * @return the display name of the device (only "self-managed" association are expected to
     * specify a non-null display name of the device).
     * @return the display name of the companion device (optionally) provided by the companion
     * application.
     *
     * @see #isSelfManaged()
     * @see AssociationRequest.Builder#setDisplayName(CharSequence)
     */
    public @Nullable CharSequence getDisplayName() {
        return mDisplayName;
    }

    /**
     * @return the profile of the device.
     * @return the companion device profile used when establishing this
     *         association, or {@code null} if no specific profile was used.
     * @see AssociationRequest.Builder#setDeviceProfile(String)
     */
    public @Nullable String getDeviceProfile() {
        return mDeviceProfile;
@@ -131,8 +142,10 @@ public final class AssociationInfo implements Parcelable {

    /**
     * @return whether the association is managed by the companion application it belongs to.
     * @see AssociationRequest.Builder#setSelfManaged(boolean)
     * @hide
     */
    @SystemApi
    public boolean isSelfManaged() {
        return mSelfManaged;
    }
@@ -160,6 +173,30 @@ public final class AssociationInfo implements Parcelable {
        return mUserId == userId && Objects.equals(mPackageName, packageName);
    }

    /**
     * Utility method for checking if the association represents a device with the given MAC
     * address.
     *
     * @return {@code false} if the association is "self-managed".
     *         {@code false} if the {@code addr} is {@code null} or is not a valid MAC address.
     *         Otherwise - the result of {@link MacAddress#equals(Object)}
     *
     * @hide
     */
    public boolean isLinkedTo(@Nullable String addr) {
        if (mSelfManaged) return false;

        if (addr == null) return false;

        final MacAddress macAddress;
        try {
            macAddress = MacAddress.fromString(addr);
        } catch (IllegalArgumentException e) {
            return false;
        }
        return macAddress.equals(mDeviceMacAddress);
    }

    @Override
    public String toString() {
        return "Association{"
@@ -233,6 +270,7 @@ public final class AssociationInfo implements Parcelable {
        mTimeApprovedMs = in.readLong();
    }

    @NonNull
    public static final Parcelable.Creator<AssociationInfo> CREATOR =
            new Parcelable.Creator<AssociationInfo>() {
        @Override
+166 −24

File changed.

Preview size limit exceeded, changes collapsed.

+392 −131

File changed.

Preview size limit exceeded, changes collapsed.

Loading