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

Commit 82ed3afe authored by Arthur Ishiguro's avatar Arthur Ishiguro
Browse files

Implements updated PendingIntent APIs

Bug: 117612105
Test: Compile and run, verify API works as intended
Change-Id: I5789305a50739494f0c069faa8236b49bccae7b5
parent b549286a
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -834,7 +834,21 @@ public final class ContextHubManager {
    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
    @NonNull public ContextHubClient createClient(
            @NonNull ContextHubInfo hubInfo, @NonNull PendingIntent pendingIntent, long nanoAppId) {
        throw new UnsupportedOperationException("Not implemented yet");
        Preconditions.checkNotNull(pendingIntent);
        Preconditions.checkNotNull(hubInfo);

        ContextHubClient client = new ContextHubClient(hubInfo);

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

        client.setClientProxy(clientProxy);
        return client;
    }

    /**
+4 −0
Original line number Diff line number Diff line
@@ -61,6 +61,10 @@ interface IContextHubService {
    // Creates a client to send and receive messages
    IContextHubClient createClient(in IContextHubClientCallback client, int contextHubId);

    // Creates a PendingIntent-based client to send and receive messages
    IContextHubClient createPendingIntentClient(
            int contextHubId, in PendingIntent pendingIntent, long nanoAppId);

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

+43 −17
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ import java.util.function.Supplier;
 * notification callbacks. This class implements the IContextHubClient object, and the implemented
 * APIs must be thread-safe.
 *
 * TODO: Consider refactoring this class via inheritance
 *
 * @hide
 */
public class ContextHubClientBroker extends IContextHubClient.Stub
@@ -92,7 +94,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
    /*
     * The PendingIntent registered with this client.
     */
    private final PendingIntentRequest mPendingIntentRequest = new PendingIntentRequest();
    private final PendingIntentRequest mPendingIntentRequest;

    /*
     * Helper class to manage registered PendingIntent requests from the client.
@@ -142,6 +144,19 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
        mAttachedContextHubInfo = contextHubInfo;
        mHostEndPointId = hostEndPointId;
        mCallbackInterface = callback;
        mPendingIntentRequest = new PendingIntentRequest();
    }

    /* package */ ContextHubClientBroker(
            Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
            ContextHubInfo contextHubInfo, short hostEndPointId, PendingIntent pendingIntent,
            long nanoAppId) {
        mContext = context;
        mContextHubProxy = contextHubProxy;
        mClientManager = clientManager;
        mAttachedContextHubInfo = contextHubInfo;
        mHostEndPointId = hostEndPointId;
        mPendingIntentRequest = new PendingIntentRequest(pendingIntent, nanoAppId);
    }

    /**
@@ -178,19 +193,15 @@ public class ContextHubClientBroker extends IContextHubClient.Stub

    /**
     * Closes the connection for this client with the service.
     *
     * If the client has a PendingIntent registered, this method also unregisters it.
     */
    @Override
    public void close() {
        synchronized (this) {
            if (mCallbackInterface != null) {
                mCallbackInterface.asBinder().unlinkToDeath(this, 0 /* flags */);
                mCallbackInterface = null;
            }
            if (!mPendingIntentRequest.hasPendingIntent() && mRegistered) {
                mClientManager.unregisterClient(mHostEndPointId);
                mRegistered = false;
            }
            mPendingIntentRequest.clear();
        }
        onClientExit();
    }

    /**
@@ -198,7 +209,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
     */
    @Override
    public void binderDied() {
        close();
        onClientExit();
    }

    /**
@@ -274,14 +285,18 @@ public class ContextHubClientBroker extends IContextHubClient.Stub

    /**
     * @param intent    the PendingIntent to compare to
     * @param nanoAppId the ID of the nanoapp of the PendingIntent to compare to
     * @return true if the given PendingIntent is currently registered, false otherwise
     */
    /* package */ boolean hasPendingIntent(PendingIntent intent) {
    /* package */ boolean hasPendingIntent(PendingIntent intent, long nanoAppId) {
        PendingIntent pendingIntent = null;
        long intentNanoAppId;
        synchronized (this) {
            pendingIntent = mPendingIntentRequest.getPendingIntent();
            intentNanoAppId = mPendingIntentRequest.getNanoAppId();
        }
        return (pendingIntent != null) && pendingIntent.equals(intent);
        return (pendingIntent != null) && pendingIntent.equals(intent)
                && intentNanoAppId == nanoAppId;
    }

    /**
@@ -355,13 +370,10 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
                // The PendingIntent is no longer valid
                Log.w(TAG, "PendingIntent has been canceled, unregistering from client"
                        + " (host endpoint ID " + mHostEndPointId + ")");
                mPendingIntentRequest.clear();
                if (mCallbackInterface == null) {
                close();
            }
        }
    }
    }

    /**
     * @return true if the client is still registered with the service, false otherwise
@@ -369,4 +381,18 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
    private synchronized boolean isRegistered() {
        return mRegistered;
    }

    /**
     * Invoked when a client exits either explicitly or by binder death.
     */
    private synchronized void onClientExit() {
        if (mCallbackInterface != null) {
            mCallbackInterface.asBinder().unlinkToDeath(this, 0 /* flags */);
            mCallbackInterface = null;
        }
        if (!mPendingIntentRequest.hasPendingIntent() && mRegistered) {
            mClientManager.unregisterClient(mHostEndPointId);
            mRegistered = false;
        }
    }
}
+37 −16
Original line number Diff line number Diff line
@@ -111,6 +111,40 @@ import java.util.function.Consumer;
        return IContextHubClient.Stub.asInterface(broker);
    }

    /**
     * Registers a new client with the service.
     *
     * @param pendingIntent  the callback interface of the client to register
     * @param contextHubInfo the object describing the hub this client is attached to
     * @param nanoAppId      the ID of the nanoapp to receive Intent events for
     *
     * @return the client interface
     *
     * @throws IllegalArgumentException the PendingIntent was already registered for a different
     *                                  ContextHubClient
     * @throws IllegalStateException    if there were too many registered clients at the service
     */
    /* package */ IContextHubClient registerClient(
            ContextHubInfo contextHubInfo, PendingIntent pendingIntent, long nanoAppId) {
        ContextHubClientBroker broker;
        String registerString = "Regenerated";
        synchronized (this) {
            broker = getClientBroker(contextHubInfo.getId(), pendingIntent, nanoAppId);

            if (broker == null) {
                short hostEndPointId = getHostEndPointId();
                broker = new ContextHubClientBroker(
                        mContext, mContextHubProxy, this /* clientManager */, contextHubInfo,
                        hostEndPointId, pendingIntent, nanoAppId);
                mHostEndPointIdToClientMap.put(hostEndPointId, broker);
                registerString = "Registered";
            }
        }

        Log.d(TAG, registerString + " client with host endpoint ID " + broker.getHostEndPointId());
        return IContextHubClient.Stub.asInterface(broker);
    }

    /**
     * Handles a message sent from a nanoapp.
     *
@@ -186,20 +220,6 @@ import java.util.function.Consumer;
        forEachClientOfHub(contextHubId, client -> client.onNanoAppAborted(nanoAppId, abortCode));
    }

    /**
     * @param pendingIntent the PendingIntent to check
     * @return true if the given PendingIntent is registered by a client, false otherwise
     */
    /* package */ boolean isPendingIntentRegistered(PendingIntent pendingIntent) {
        for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
            if (broker.hasPendingIntent(pendingIntent)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns an available host endpoint ID.
     *
@@ -256,9 +276,10 @@ import java.util.function.Consumer;
     * @param contextHubId  the ID of the Context Hub the client is attached to
     * @return the matching ContextHubClientBroker, null if not found
     */
    private ContextHubClientBroker getClientBroker(PendingIntent pendingIntent, int contextHubId) {
    private ContextHubClientBroker getClientBroker(
            int contextHubId, PendingIntent pendingIntent, long nanoAppId) {
        for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
            if (broker.hasPendingIntent(pendingIntent)
            if (broker.hasPendingIntent(pendingIntent, nanoAppId)
                    && broker.getAttachedContextHubId() == contextHubId) {
                return broker;
            }
+24 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.location;

import android.app.PendingIntent;
import android.content.Context;
import android.hardware.contexthub.V1_0.AsyncEventType;
import android.hardware.contexthub.V1_0.ContextHub;
@@ -630,6 +631,29 @@ public class ContextHubService extends IContextHubService.Stub {
        return mClientManager.registerClient(clientCallback, contextHubInfo);
    }

    /**
     * Creates and registers a PendingIntent client at the service for the specified Context Hub.
     *
     * @param contextHubId  the ID of the hub this client is attached to
     * @param pendingIntent the PendingIntent associated with this client
     * @param nanoAppId     the ID of the nanoapp PendingIntent events will be sent for
     * @return the generated client interface
     *
     * @throws IllegalArgumentException if hubInfo does not represent a valid hub
     * @throws IllegalStateException    if there were too many registered clients at the service
     */
    @Override
    public IContextHubClient createPendingIntentClient(
            int contextHubId, PendingIntent pendingIntent, long nanoAppId) throws RemoteException {
        checkPermissions();
        if (!isValidContextHubId(contextHubId)) {
            throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
        }

        ContextHubInfo contextHubInfo = mContextHubIdToInfoMap.get(contextHubId);
        return mClientManager.registerClient(contextHubInfo, pendingIntent, nanoAppId);
    }

    /**
     * Loads a nanoapp binary at the specified Context hub.
     *