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

Commit 818d2dac authored by Anthony Stange's avatar Anthony Stange
Browse files

Add new callback / intent type to ContextHub APIs

Updates the ContextHub APIs to support notifying clients (either through
traditional callbacks or via PendingIntent) that their ability to
communicate with nanoapps has changed.

Also, adds the ability for clients to discover the permissions required
to communicate with nanoapps so they know whether their initial or
subsequent nanoapp messages will successfully be delivered.

Bug: 166846988
Test: compile
Change-Id: I37e475a1457a031890693d2858b5d5f7de34de26
parent 3f08df9f
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -3168,6 +3168,7 @@ package android.hardware.location {
  public class ContextHubClientCallback {
    ctor public ContextHubClientCallback();
    method public void onClientAuthorizationChanged(@NonNull android.hardware.location.ContextHubClient, long, int);
    method public void onHubReset(android.hardware.location.ContextHubClient);
    method public void onMessageFromNanoApp(android.hardware.location.ContextHubClient, android.hardware.location.NanoAppMessage);
    method public void onNanoAppAborted(android.hardware.location.ContextHubClient, long, int);
@@ -3204,6 +3205,7 @@ package android.hardware.location {
  public class ContextHubIntentEvent {
    method @NonNull public static android.hardware.location.ContextHubIntentEvent fromIntent(@NonNull android.content.Intent);
    method public int getClientAuthorizationState();
    method @NonNull public android.hardware.location.ContextHubInfo getContextHubInfo();
    method public int getEventType();
    method public int getNanoAppAbortCode();
@@ -3231,6 +3233,10 @@ package android.hardware.location {
    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int unloadNanoApp(int);
    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
    method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
    field public static final int AUTHORIZATION_DENIED = 0; // 0x0
    field public static final int AUTHORIZATION_DENIED_GRACE_PERIOD = 1; // 0x1
    field public static final int AUTHORIZATION_GRANTED = 2; // 0x2
    field public static final int EVENT_CLIENT_AUTHORIZATION = 7; // 0x7
    field public static final int EVENT_HUB_RESET = 6; // 0x6
    field public static final int EVENT_NANOAPP_ABORTED = 4; // 0x4
    field public static final int EVENT_NANOAPP_DISABLED = 3; // 0x3
@@ -3238,6 +3244,7 @@ package android.hardware.location {
    field public static final int EVENT_NANOAPP_LOADED = 0; // 0x0
    field public static final int EVENT_NANOAPP_MESSAGE = 5; // 0x5
    field public static final int EVENT_NANOAPP_UNLOADED = 1; // 0x1
    field public static final String EXTRA_CLIENT_AUTHORIZATION_STATE = "android.hardware.location.extra.CLIENT_AUTHORIZATION_STATE";
    field public static final String EXTRA_CONTEXT_HUB_INFO = "android.hardware.location.extra.CONTEXT_HUB_INFO";
    field public static final String EXTRA_EVENT_TYPE = "android.hardware.location.extra.EVENT_TYPE";
    field public static final String EXTRA_MESSAGE = "android.hardware.location.extra.MESSAGE";
@@ -3476,8 +3483,10 @@ package android.hardware.location {
  public final class NanoAppState implements android.os.Parcelable {
    ctor public NanoAppState(long, int, boolean);
    ctor public NanoAppState(long, int, boolean, @NonNull java.util.List<java.lang.String>);
    method public int describeContents();
    method public long getNanoAppId();
    method @NonNull public java.util.List<java.lang.String> getNanoAppPermissions();
    method public long getNanoAppVersion();
    method public boolean isEnabled();
    method public void writeToParcel(android.os.Parcel, int);
+31 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package android.hardware.location;

import android.annotation.NonNull;
import android.annotation.SystemApi;

import java.util.concurrent.Executor;
@@ -101,4 +102,34 @@ public class ContextHubClientCallback {
     * @param nanoAppId the ID of the nanoapp that had been disabled
     */
    public void onNanoAppDisabled(ContextHubClient client, long nanoAppId) {}

    /**
     * Callback invoked when a {@link ContextHubClient}'s authorization to communicate with a
     * nanoapp changes. This typically happens as a result of the app that created the
     * {@link ContextHubClient} gaining or losing the permissions required to communicate with a
     * nanoapp.
     *
     * An example of the connection callbacks looks like:
     * 1) {@link ContextHubClient} sends message to nanoapp and holds required permissions
     * 2) {@link ContextHubClient} loses required permissions
     * 3) Callback invoked with the nanoapp ID and
     *    {@link ContextHubManager#AUTHORIZATION_DENIED_GRACE_PERIOD}
     * 4) {@link ContextHubClient} performs any cleanup required with the nanoapp
     * 5) Callback invoked with the nanoapp ID and {@link ContextHubManager#AUTHORIZATION_DENIED}.
     *    At this point, any further attempts of communication between the nanoapp and the
     *    {@link ContextHubClient} will be dropped by the contexthub along with
     *    {@link ContextHubManager#AUTHORIZATION_DENIED} being sent. The {@link ContextHubClient}
     *    should assume no communciation can happen again until
     *    {@link ContextHubManager#AUTHORIZATION_GRANTED} is received.
     *
     * @param client the client that is associated with this callback
     * @param nanoAppId the ID of the nanoapp associated with the new
     * authorization state
     * @param authorization the authorization state denoting the ability of the
     * client to communicate with the nanoapp
     */
    public void onClientAuthorizationChanged(
            @NonNull ContextHubClient client,
            long nanoAppId,
            @ContextHubManager.AuthorizationState int authorization) {}
}
+39 −6
Original line number Diff line number Diff line
@@ -43,39 +43,45 @@ public class ContextHubIntentEvent {

    private final int mNanoAppAbortCode;

    private final int mClientAuthorizationState;

    private ContextHubIntentEvent(
            @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType,
            long nanoAppId, NanoAppMessage nanoAppMessage, int nanoAppAbortCode) {
            long nanoAppId, NanoAppMessage nanoAppMessage, int nanoAppAbortCode,
            @ContextHubManager.AuthorizationState int clientAuthorizationState) {
        mContextHubInfo = contextHubInfo;
        mEventType = eventType;
        mNanoAppId = nanoAppId;
        mNanoAppMessage = nanoAppMessage;
        mNanoAppAbortCode = nanoAppAbortCode;
        mClientAuthorizationState = clientAuthorizationState;
    }

    private ContextHubIntentEvent(
            @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType) {
        this(contextHubInfo, eventType, -1 /* nanoAppId */, null /* nanoAppMessage */,
                -1 /* nanoAppAbortCode */);
                -1 /* nanoAppAbortCode */, 0 /* clientAuthorizationState */);
    }

    private ContextHubIntentEvent(
            @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType,
            long nanoAppId) {
        this(contextHubInfo, eventType, nanoAppId, null /* nanoAppMessage */,
                -1 /* nanoAppAbortCode */);
                -1 /* nanoAppAbortCode */, 0 /* clientAuthorizationState */);
    }

    private ContextHubIntentEvent(
            @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType,
            long nanoAppId, @NonNull NanoAppMessage nanoAppMessage) {
        this(contextHubInfo, eventType, nanoAppId, nanoAppMessage, -1 /* nanoAppAbortCode */);
        this(contextHubInfo, eventType, nanoAppId, nanoAppMessage, -1 /* nanoAppAbortCode */,
                0 /* clientAuthorizationState */);
    }

    private ContextHubIntentEvent(
            @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType,
            long nanoAppId, int nanoAppAbortCode) {
        this(contextHubInfo, eventType, nanoAppId, null /* nanoAppMessage */, nanoAppAbortCode);
        this(contextHubInfo, eventType, nanoAppId, null /* nanoAppMessage */, nanoAppAbortCode,
                0 /* clientAuthorizationState */);
    }

    /**
@@ -105,7 +111,8 @@ public class ContextHubIntentEvent {
            case ContextHubManager.EVENT_NANOAPP_ENABLED:
            case ContextHubManager.EVENT_NANOAPP_DISABLED:
            case ContextHubManager.EVENT_NANOAPP_ABORTED:
            case ContextHubManager.EVENT_NANOAPP_MESSAGE: // fall through
            case ContextHubManager.EVENT_NANOAPP_MESSAGE:
            case ContextHubManager.EVENT_CLIENT_AUTHORIZATION: // fall through
                long nanoAppId = getLongExtraOrThrow(intent, ContextHubManager.EXTRA_NANOAPP_ID);
                if (eventType == ContextHubManager.EVENT_NANOAPP_MESSAGE) {
                    hasExtraOrThrow(intent, ContextHubManager.EXTRA_MESSAGE);
@@ -120,6 +127,11 @@ public class ContextHubIntentEvent {
                    int nanoAppAbortCode = getIntExtraOrThrow(
                            intent, ContextHubManager.EXTRA_NANOAPP_ABORT_CODE);
                    event = new ContextHubIntentEvent(info, eventType, nanoAppId, nanoAppAbortCode);
                } else if (eventType == ContextHubManager.EVENT_CLIENT_AUTHORIZATION) {
                    int authState = getIntExtraOrThrow(
                            intent, ContextHubManager.EXTRA_CLIENT_AUTHORIZATION_STATE);
                    event = new ContextHubIntentEvent(info, eventType, nanoAppId,
                            null /* nanoAppMessage */, -1 /* nanoAppAbortCode */, authState);
                } else {
                    event = new ContextHubIntentEvent(info, eventType, nanoAppId);
                }
@@ -192,6 +204,21 @@ public class ContextHubIntentEvent {
        return mNanoAppMessage;
    }

    /**
     * @return the client authorization state
     *
     * @throws UnsupportedOperationException if this was not a client authorization state event
     */
    @ContextHubManager.AuthorizationState
    public int getClientAuthorizationState() {
        if (mEventType != ContextHubManager.EVENT_CLIENT_AUTHORIZATION) {
            throw new UnsupportedOperationException(
                    "Cannot invoke getClientAuthorizationState() on non-authorization event: "
                    + mEventType);
        }
        return mClientAuthorizationState;
    }

    @NonNull
    @Override
    public String toString() {
@@ -207,6 +234,9 @@ public class ContextHubIntentEvent {
        if (mEventType == ContextHubManager.EVENT_NANOAPP_MESSAGE) {
            out += ", nanoAppMessage = " + mNanoAppMessage;
        }
        if (mEventType == ContextHubManager.EVENT_CLIENT_AUTHORIZATION) {
            out += ", clientAuthState = " + mClientAuthorizationState;
        }

        return out + "]";
    }
@@ -233,6 +263,9 @@ public class ContextHubIntentEvent {
                    if (mEventType == ContextHubManager.EVENT_NANOAPP_MESSAGE) {
                        isEqual &= other.getNanoAppMessage().equals(mNanoAppMessage);
                    }
                    if (mEventType == ContextHubManager.EVENT_CLIENT_AUTHORIZATION) {
                        isEqual &= other.getClientAuthorizationState() == mClientAuthorizationState;
                    }
                } catch (UnsupportedOperationException e) {
                    isEqual = false;
                }
+59 −0
Original line number Diff line number Diff line
@@ -58,6 +58,12 @@ import java.util.concurrent.Executor;
public final class ContextHubManager {
    private static final String TAG = "ContextHubManager";

    /**
     * An extra of type int describing the client's authorization state.
     */
    public static final String EXTRA_CLIENT_AUTHORIZATION_STATE =
            "android.hardware.location.extra.CLIENT_AUTHORIZATION_STATE";

    /**
     * An extra of type {@link ContextHubInfo} describing the source of the event.
     */
@@ -85,6 +91,42 @@ public final class ContextHubManager {
     */
    public static final String EXTRA_MESSAGE = "android.hardware.location.extra.MESSAGE";

    /**
     * Constants describing if a {@link ContextHubClient} and a {@link NanoApp} are authorized to
     * communicate.
     *
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = { "AUTHORIZATION_" }, value = {
        AUTHORIZATION_DENIED,
        AUTHORIZATION_DENIED_GRACE_PERIOD,
        AUTHORIZATION_GRANTED,
    })
    public @interface AuthorizationState { }

    /**
     * Indicates that the {@link ContextHubClient} can no longer communicate with a nanoapp. If the
     * {@link ContextHubClient} attempts to send messages to the nanoapp, it will continue to
     * receive this authorization state if the connection is still closed.
     */
    public static final int AUTHORIZATION_DENIED = 0;

    /**
     * Indicates the {@link ContextHubClient} will soon lose its authorization to communicate with a
     * nanoapp. The {@link ContextHubClient} must perform any cleanup with the nanoapp as soon as
     * possible.
     *
     * Note that the time between this state event and {@link AUTHORIZATION_DENIED} must be enough
     * for the {@link ContextHubClient} to send at least one message to the nanoapp.
     */
    public static final int AUTHORIZATION_DENIED_GRACE_PERIOD = 1;

    /**
     * The {@link ContextHubClient} is authorized to communicate with the nanoapp.
     */
    public static final int AUTHORIZATION_GRANTED = 2;

    /**
     * Constants describing the type of events from a Context Hub.
     * {@hide}
@@ -98,6 +140,7 @@ public final class ContextHubManager {
        EVENT_NANOAPP_ABORTED,
        EVENT_NANOAPP_MESSAGE,
        EVENT_HUB_RESET,
        EVENT_CLIENT_AUTHORIZATION,
    })
    public @interface Event { }

@@ -138,6 +181,14 @@ public final class ContextHubManager {
     */
    public static final int EVENT_HUB_RESET = 6;

    /**
     * An event describing a client authorization state change. See
     * {@link ContextHubClientCallback#onClientAuthorizationChanged} for more details on when this
     * event will be sent. Contains the EXTRA_NANOAPP_ID and EXTRA_CLIENT_AUTHORIZATION_STATE
     * extras.
     */
    public static final int EVENT_CLIENT_AUTHORIZATION = 7;

    private final Looper mMainLooper;
    private final IContextHubService mService;
    private Callback mCallback;
@@ -747,6 +798,14 @@ public final class ContextHubManager {
            public void onNanoAppDisabled(long nanoAppId) {
                executor.execute(() -> callback.onNanoAppDisabled(client, nanoAppId));
            }

            @Override
            public void onClientAuthorizationChanged(
                    long nanoAppId, @ContextHubManager.AuthorizationState int authorization) {
                executor.execute(
                        () -> callback.onClientAuthorizationChanged(
                                client, nanoAppId, authorization));
            }
        };
    }

+3 −0
Original line number Diff line number Diff line
@@ -46,4 +46,7 @@ oneway interface IContextHubClientCallback {

    // Callback invoked when a nanoapp is disabled at the attached Context Hub.
    void onNanoAppDisabled(long nanoAppId);

    // Callback invoked when the authorization state of a client changes.
    void onClientAuthorizationChanged(long nanoAppId, int authorization);
}
Loading