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

Commit 4698bcf0 authored by Evan Chen's avatar Evan Chen
Browse files

Companion App Manages Connectivity State Interfaces

Created two new APIs in CompanionDeviceManager:
notifyDeviceAppeared and notifyDeviceDisappeared for
companion apps report connectivity.

Create a new callback method for user to override when
device is connected and disconnected

Bug: 199435613
Test: atest CtsCompanionDevicesTestCases

Change-Id: I6884d085cf810fdd42466d620e888b07367c9b94
parent 5bb7a510
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -10127,8 +10127,10 @@ package android.companion {
    ctor public CompanionDeviceService();
    method @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES) public final void dispatchMessage(int, int, @NonNull byte[]);
    method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
    method @MainThread public abstract void onDeviceAppeared(@NonNull String);
    method @MainThread public abstract void onDeviceDisappeared(@NonNull String);
    method @Deprecated @MainThread public void onDeviceAppeared(@NonNull String);
    method @MainThread public void onDeviceAppeared(@NonNull android.companion.AssociationInfo);
    method @Deprecated @MainThread public void onDeviceDisappeared(@NonNull String);
    method @MainThread public void onDeviceDisappeared(@NonNull android.companion.AssociationInfo);
    method @MainThread public void onDispatchMessage(int, int, @NonNull byte[]);
    field public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
  }
+2 −0
Original line number Diff line number Diff line
@@ -2427,6 +2427,8 @@ package android.companion {
    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.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public void notifyDeviceAppeared(int);
    method @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public void notifyDeviceDisappeared(int);
    method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public void removeOnAssociationsChangedListener(@NonNull android.companion.CompanionDeviceManager.OnAssociationsChangedListener);
  }
+45 −0
Original line number Diff line number Diff line
@@ -776,6 +776,51 @@ public final class CompanionDeviceManager {
        }
    }

    /**
     * Notify the system that the given self-managed association has just 'appeared'.
     * This causes the system to bind to the companion app to keep it running until the association
     * is reported as 'disappeared'
     *
     * <p>This API is only available for the companion apps that manage the connectivity by
     * themselves.</p>
     *
     * @param associationId the unique {@link AssociationInfo#getId ID} assigned to the Association
     * recorded by CompanionDeviceManager
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED)
    public void notifyDeviceAppeared(int associationId) {
        try {
            mService.notifyDeviceAppeared(associationId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Notify the system that the given self-managed association has just 'disappeared'.
     * This causes the system to unbind to the companion app.
     *
     * <p>This API is only available for the companion apps that manage the connectivity by
     * themselves.</p>
     *
     * @param associationId the unique {@link AssociationInfo#getId ID} assigned to the Association
     * recorded by CompanionDeviceManager

     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED)
    public void notifyDeviceDisappeared(int associationId) {
        try {
            mService.notifyDeviceDisappeared(associationId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    private boolean checkFeaturePresent() {
        boolean featurePresent = mService != null;
        if (!featurePresent && DEBUG) {
+60 −16
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.util.Log;


import com.android.internal.util.function.pooled.PooledLambda;

import java.util.Objects;
@@ -34,8 +35,9 @@ import java.util.Objects;
/**
 * Service to be implemented by apps that manage a companion device.
 *
 * System will keep this service bound whenever an associated device is nearby,
 * ensuring app stays alive.
 * System will keep this service bound whenever an associated device is nearby for Bluetooth
 * devices or companion app manages the connectivity and reports disappeared, ensuring app stays
 * alive
 *
 * An app must be {@link CompanionDeviceManager#associate associated} with at leas one device,
 * before it can take advantage of this service.
@@ -43,6 +45,17 @@ import java.util.Objects;
 * You must declare this service in your manifest with an
 * intent-filter action of {@link #SERVICE_INTERFACE} and
 * permission of {@link android.Manifest.permission#BIND_COMPANION_DEVICE_SERVICE}
 *
 * <p>If you want to declare more than one of these services, you must declare the meta-data in the
 * service of your manifest with the corresponding name and value to true to indicate the
 * primary service.
 * Only the primary one will get the callback from
 * {@link #onDeviceAppeared(AssociationInfo associationInfo)}.</p>
 *
 * Example:
 * <meta-data
 *   android:name="primary"
 *   android:value="true" />
 */
public abstract class CompanionDeviceService extends Service {

@@ -52,13 +65,14 @@ public abstract class CompanionDeviceService extends Service {
     * An intent action for a service to be bound whenever this app's companion device(s)
     * are nearby.
     *
     * <p>The app will be kept alive for as long as the device is nearby.
     * <p>The app will be kept alive for as long as the device is nearby or companion app reports
     * appeared.
     * If the app is not running at the time device gets connected, the app will be woken up.</p>
     *
     * <p>Shortly after the device goes out of range, the service will be unbound, and the
     * app will be eligible for cleanup, unless any other user-visible components are running.</p>
     * <p>Shortly after the device goes out of range or the companion app reports disappeared,
     * the service will be unbound, and the app will be eligible for cleanup, unless any other
     * user-visible components are running.</p>
     *
     * <p>An app shouldn't declare more than one of these services.
     * If running in background is not essential for the devices that this app can manage,
     * app should avoid declaring this service.</p>
     *
@@ -73,9 +87,13 @@ public abstract class CompanionDeviceService extends Service {
     * Called by system whenever a device associated with this app is available.
     *
     * @param address the MAC address of the device
     * @deprecated please override {@link #onDeviceAppeared(AssociationInfo)} instead.
     */
    @Deprecated
    @MainThread
    public abstract void onDeviceAppeared(@NonNull String address);
    public void onDeviceAppeared(@NonNull String address) {
        // Do nothing. Companion apps can override this function.
    }

    /**
     * Called by system whenever a device associated with this app stops being available.
@@ -83,9 +101,13 @@ public abstract class CompanionDeviceService extends Service {
     * Usually this means the device goes out of range or is turned off.
     *
     * @param address the MAC address of the device
     * @deprecated please override {@link #onDeviceDisappeared(AssociationInfo)} instead.
     */
    @Deprecated
    @MainThread
    public abstract void onDeviceDisappeared(@NonNull String address);
    public void onDeviceDisappeared(@NonNull String address) {
        // Do nothing. Companion apps can override this function.
    }

    /**
     * Called by system whenever the system dispatches a message to the app to send it to
@@ -118,6 +140,30 @@ public abstract class CompanionDeviceService extends Service {
        companionDeviceManager.dispatchMessage(messageId, associationId, message);
    }

    /**
     * Called by system whenever a device associated with this app is connected.
     *
     * @param associationInfo A record for the companion device.
     */
    @MainThread
    public void onDeviceAppeared(@NonNull AssociationInfo associationInfo) {
        if (!associationInfo.isSelfManaged()) {
            onDeviceAppeared(associationInfo.getDeviceMacAddressAsString());
        }
    }

    /**
     * Called by system whenever a device associated with this app is disconnected.
     *
     * @param associationInfo A record for the companion device.
     */
    @MainThread
    public void onDeviceDisappeared(@NonNull AssociationInfo associationInfo) {
        if (!associationInfo.isSelfManaged()) {
            onDeviceDisappeared(associationInfo.getDeviceMacAddressAsString());
        }
    }

    @Nullable
    @Override
    public final IBinder onBind(@NonNull Intent intent) {
@@ -132,17 +178,15 @@ public abstract class CompanionDeviceService extends Service {
    class Stub extends ICompanionDeviceService.Stub {

        @Override
        public void onDeviceAppeared(String address) {
            Handler.getMain().sendMessage(PooledLambda.obtainMessage(
                    CompanionDeviceService::onDeviceAppeared,
                    CompanionDeviceService.this, address));
        public void onDeviceAppeared(AssociationInfo associationInfo) {
            Handler.getMain().post(
                    () -> CompanionDeviceService.this.onDeviceAppeared(associationInfo));
        }

        @Override
        public void onDeviceDisappeared(String address) {
            Handler.getMain().sendMessage(PooledLambda.obtainMessage(
                    CompanionDeviceService::onDeviceDisappeared,
                    CompanionDeviceService.this, address));
        public void onDeviceDisappeared(AssociationInfo associationInfo) {
            Handler.getMain().post(
                    () -> CompanionDeviceService.this.onDeviceDisappeared(associationInfo));
        }

        public void onDispatchMessage(int messageId, int associationId, @NonNull byte[] message) {
+5 −0
Original line number Diff line number Diff line
@@ -65,5 +65,10 @@ interface ICompanionDeviceManager {
    void dispatchMessage(in int messageId, in int associationId, in byte[] message);

    void addOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId);

    void removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId);

    void notifyDeviceAppeared(int associationId);

    void notifyDeviceDisappeared(int associationId);
}
Loading