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

Commit 1bb34a86 authored by Arthur Ishiguro's avatar Arthur Ishiguro
Browse files

Updates PendingIntent-based service APIs

Modifies the APIs such that ContextHubClient can be generated by
either the ContextHubClientCallback or the PendingIntent (exclusive or),
for simplicity. ContextHubClients can be regenerated through the
createClient() API, while maintaining the original host endpoint ID.

Also removes the API implementation based on the original design.

Bug: 117612105
Test: Compile only
Change-Id: Ic62aa8695eee3d68722163934de76e77c1f0bc0c
parent 45ac8e40
Loading
Loading
Loading
Loading
+6 −68
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.RemoteException;

import com.android.internal.util.Preconditions;
@@ -88,7 +87,12 @@ public class ContextHubClient implements Closeable {
     * Closes the connection for this client and the Context Hub Service.
     *
     * When this function is invoked, the messaging associated with this client is invalidated.
     * All futures messages targeted for this client are dropped at the service.
     * All futures messages targeted for this client are dropped at the service, and the
     * ContextHubClient is unregistered from the service.
     *
     * If this object has a PendingIntent, i.e. the object was generated via
     * {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo, long)}, then the
     * Intent events corresponding to the PendingIntent will no longer be triggered.
     */
    public void close() {
        if (!mIsClosed.getAndSet(true)) {
@@ -101,72 +105,6 @@ public class ContextHubClient implements Closeable {
        }
    }

    /**
     * Registers to receive persistent intents for a given nanoapp.
     *
     * This method should be used if the caller wants to receive notifications even after the
     * process exits. The client must have an open connection with the Context Hub Service (i.e. it
     * cannot have been closed through the {@link #close()} method). Only one PendingIntent can be
     * registered at a time for a single ContextHubClient, and the PendingIntent cannot be
     * registered if already registered by a ContextHubClient. If registered successfully, intents
     * will be delivered regarding events for the specified nanoapp from the attached Context Hub.
     * Any unicast messages for this client will also be delivered. The intent will have an extra
     * {@link ContextHubManager.EXTRA_CONTEXT_HUB_INFO} of type {@link ContextHubInfo}, which
     * describes the Context Hub the intent event was for. The intent will also have an extra
     * {@link ContextHubManager.EXTRA_EVENT_TYPE} of type {@link ContextHubManager.Event}, which
     * will contain the type of the event. See {@link ContextHubManager.Event} for description of
     * each event type, along with event-specific extra fields. A client can use
     * {@link ContextHubIntentEvent.fromIntent(Intent)} to parse the Intent generated by the event.
     *
     * When the intent is received, this client can be recreated through
     * {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo,
     * ContextHubClientCallback, Exectutor)}. When recreated, the client can be treated as the
     * same endpoint entity from a nanoapp's perspective, and can be continued to be used to send
     * messages even if the original process has exited.
     *
     * Intents will be delivered until it is unregistered through
     * {@link #unregisterIntent(PendingIntent)}. Note that the registration of this client will
     * continued to be maintained at the Context Hub Service until
     * {@link #unregisterIntent(PendingIntent)} is called for registered intents.
     *
     * @param pendingIntent the PendingIntent to register for this client
     * @param nanoAppId     the unique ID of the nanoapp to receive events for
     * @return true on success, false otherwise
     *
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
    public boolean registerIntent(@NonNull PendingIntent pendingIntent, long nanoAppId) {
        Preconditions.checkNotNull(pendingIntent, "PendingIntent cannot be null");

        try {
            return mClientProxy.registerIntent(pendingIntent, nanoAppId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Unregisters an intent previously registered via {@link #registerIntent(PendingIntent, long)}.
     * If this intent has not been registered for this client, this method returns false.
     *
     * @param pendingIntent the PendingIntent to unregister
     *
     * @return true on success, false otherwise
     *
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
    public boolean unregisterIntent(@NonNull PendingIntent pendingIntent) {
        Preconditions.checkNotNull(pendingIntent, "PendingIntent cannot be null");

        try {
            return mClientProxy.unregisterIntent(pendingIntent);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Sends a message to a nanoapp through the Context Hub Service.
     *
+33 −58
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
@@ -793,73 +794,47 @@ public final class ContextHubManager {
    }

    /**
     * Creates a ContextHubClient based on an Intent received by the Context Hub Service.
     * Creates a ContextHubClient that will receive notifications based on Intent events.
     *
     * This method is intended to be used after receiving an Intent received as a result of
     * {@link ContextHubClient.registerIntent(PendingIntent, long)}, and must have been created
     * through {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)} or
     * equivalent at an earlier time.
     * This method should be used instead of {@link #createClient(ContextHubInfo,
     * ContextHubClientCallback)} and the equivalent API if the caller wants to preserve the
     * messaging endpoint of a ContextHubClient, even after a process exits. If the PendingIntent
     * with the provided nanoapp has already been registered at the service previously, then the
     * same ContextHubClient will be regenerated without creating a new client connection at the
     * service. Note that the PendingIntent, nanoapp, and Context Hub must all match in identifying
     * a previously registered ContextHubClient. If a client is regenerated, it can be treated as
     * the same endpoint entity from a nanoapp's perspective, and can be continued to be
     * used to send messages even if the original process has exited.
     *
     * @param pendingIntent the PendingIntent that has been registered with a client
     * @param hubInfo       the hub to attach this client to
     * @param callback      the notification callback to register
     * @param executor      the executor to invoke the callback
     * @return the registered client object
     * If registered successfully, intents will be delivered regarding events or messages from the
     * specified nanoapp from the attached Context Hub. The intent will have an extra
     * {@link ContextHubManager.EXTRA_CONTEXT_HUB_INFO} of type {@link ContextHubInfo}, which
     * describes the Context Hub the intent event was for. The intent will also have an extra
     * {@link ContextHubManager.EXTRA_EVENT_TYPE} of type {@link ContextHubManager.Event}, which
     * will contain the type of the event. See {@link ContextHubManager.Event} for description of
     * each event type, along with event-specific extra fields. The client can also use
     * {@link ContextHubIntentEvent.fromIntent(Intent)} to parse the Intent generated by the event.
     *
     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
     *                                  was not associated with a client
     * @throws IllegalStateException    if the client is already registered to a valid callback
     * @throws NullPointerException     if pendingIntent, hubInfo, callback, or executor is null
     *
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
    @NonNull public ContextHubClient createClient(
            @NonNull PendingIntent pendingIntent, @NonNull ContextHubInfo hubInfo,
            @NonNull ContextHubClientCallback callback,
            @NonNull @CallbackExecutor Executor executor) {
        Preconditions.checkNotNull(pendingIntent, "PendingIntent cannot be null");
        Preconditions.checkNotNull(callback, "Callback cannot be null");
        Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
        Preconditions.checkNotNull(executor, "Executor cannot be null");

        ContextHubClient client = new ContextHubClient(hubInfo);
        IContextHubClientCallback clientInterface = createClientCallback(
                client, callback, executor);

        IContextHubClient clientProxy;
        try {
            clientProxy = mService.bindClient(pendingIntent, clientInterface, hubInfo.getId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        client.setClientProxy(clientProxy);
        return client;
    }

    /**
     * Equivalent to {@link #createClient(PendingIntent, ContextHubInfo, ContextHubClientCallback,
     * Executor)} with the executor using the main thread's Looper.
     * Intent events will be delivered until it is unregistered through
     * {@link ContextHubClient.close()}. Note that the registration of this
     * ContextHubClient at the Context Hub Service will continued to be maintained until
     * {@link ContextHubClient.close()} is called.
     *
     * @param pendingIntent the PendingIntent that has been registered with a client
     * @param hubInfo       the hub to attach this client to
     * @param callback      the notification callback to register
     * @param pendingIntent the PendingIntent to register to the client
     * @param nanoAppId     the ID of the nanoapp that Intent events will be generated for
     * @return the registered client object
     *
     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
     *                                  was not associated with a client
     * @throws IllegalStateException    if the client is already registered to a valid callback
     * @throws NullPointerException     if pendingIntent, hubInfo, or callback is null
     * @throws IllegalArgumentException if hubInfo does not represent a valid hub
     * @throws IllegalStateException    if there were too many registered clients at the service
     * @throws NullPointerException     if pendingIntent or hubInfo is null
     *
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
    @NonNull public ContextHubClient createClient(
            @NonNull PendingIntent pendingIntent, @NonNull ContextHubInfo hubInfo,
            @NonNull ContextHubClientCallback callback) {
        return createClient(
                pendingIntent, hubInfo, callback, new HandlerExecutor(Handler.getMain()));
            @NonNull ContextHubInfo hubInfo, @NonNull PendingIntent pendingIntent, long nanoAppId) {
        throw new UnsupportedOperationException("Not implemented yet");
    }

    /**
+0 −6
Original line number Diff line number Diff line
@@ -29,10 +29,4 @@ interface IContextHubClient {

    // Closes the connection with the Context Hub
    void close();

    // Registers a PendingIntent with the client
    boolean registerIntent(in PendingIntent pendingIntent, long nanoAppId);

    // Unregisters a PendingIntent from the client
    boolean unregisterIntent(in PendingIntent pendingIntent);
}
+0 −5
Original line number Diff line number Diff line
@@ -61,11 +61,6 @@ interface IContextHubService {
    // Creates a client to send and receive messages
    IContextHubClient createClient(in IContextHubClientCallback client, int contextHubId);

    // Binds an existing client to a new callback interface, provided a previously registered
    // PendingIntent
    IContextHubClient bindClient(
            in PendingIntent pendingIntent, in IContextHubClientCallback client, int contextHubId);

    // Returns a list of ContextHub objects of available hubs
    List<ContextHubInfo> getContextHubs();

+0 −69
Original line number Diff line number Diff line
@@ -130,31 +130,6 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
        public void clear() {
            mPendingIntent = null;
        }

        public boolean register(PendingIntent pendingIntent, long nanoAppId) {
            boolean success = false;
            if (hasPendingIntent()) {
                Log.e(TAG, "Failed to register PendingIntent: registered PendingIntent exists");
            } else {
                mNanoAppId = nanoAppId;
                mPendingIntent = pendingIntent;
                success = true;
            }

            return success;
        }

        public boolean unregister(PendingIntent pendingIntent) {
            boolean success = false;
            if (!hasPendingIntent() || !mPendingIntent.equals(pendingIntent)) {
                Log.e(TAG, "Failed to unregister PendingIntent: PendingIntent is not registered");
            } else {
                mPendingIntent = null;
                success = true;
            }

            return success;
        }
    }

    /* package */ ContextHubClientBroker(
@@ -203,50 +178,6 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
        return ContextHubServiceUtil.toTransactionResult(result);
    }

    /**
     * @param pendingIntent the intent to register
     * @param nanoAppId     the ID of the nanoapp to send events for
     * @return true on success, false otherwise
     */
    @Override
    public boolean registerIntent(PendingIntent pendingIntent, long nanoAppId) {
        ContextHubServiceUtil.checkPermissions(mContext);
        if (mClientManager.isPendingIntentRegistered(pendingIntent)) {
            Log.e(TAG, "Failed to register PendingIntent: already registered");
            return false;
        }

        boolean success = false;
        synchronized (this) {
            if (mCallbackInterface == null) {
                Log.e(TAG, "Failed to register PendingIntent: client connection is closed");
            } else {
                success = mPendingIntentRequest.register(pendingIntent, nanoAppId);
            }
        }

        return success;
    }

    /**
     * @param pendingIntent the intent to unregister
     * @return true on success, false otherwise
     */
    @Override
    public boolean unregisterIntent(PendingIntent pendingIntent) {
        ContextHubServiceUtil.checkPermissions(mContext);

        boolean success = false;
        synchronized (this) {
            success = mPendingIntentRequest.unregister(pendingIntent);
            if (mCallbackInterface == null) {
                close();
            }
        }

        return success;
    }

    /**
     * Closes the connection for this client with the service.
     */
Loading