Implements the new loadNanoApp/unloadNanoApp APIs

Bug: 67734082
Test: Run a test app that uses the new API to load/unload a nanoapp,
verify that the nanoapp loads/unloads successfully
Change-Id: I8cbd46515ad33f7d9a1805dadcf8a99428686aef
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index b31c7bc..7b9f8f0 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -342,7 +342,17 @@
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public ContextHubTransaction<Void> loadNanoApp(
             ContextHubInfo hubInfo, NanoAppBinary appBinary) {
-        throw new UnsupportedOperationException("TODO: Implement this");
+        ContextHubTransaction<Void> transaction =
+                new ContextHubTransaction<>(ContextHubTransaction.TYPE_LOAD_NANOAPP);
+        IContextHubTransactionCallback callback = createTransactionCallback(transaction);
+
+        try {
+            mService.loadNanoAppOnHub(hubInfo.getId(), callback, appBinary);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        return transaction;
     }
 
     /**
@@ -357,7 +367,17 @@
      */
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public ContextHubTransaction<Void> unloadNanoApp(ContextHubInfo hubInfo, long nanoAppId) {
-        throw new UnsupportedOperationException("TODO: Implement this");
+        ContextHubTransaction<Void> transaction =
+                new ContextHubTransaction<>(ContextHubTransaction.TYPE_UNLOAD_NANOAPP);
+        IContextHubTransactionCallback callback = createTransactionCallback(transaction);
+
+        try {
+            mService.unloadNanoAppFromHub(hubInfo.getId(), callback, nanoAppId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        return transaction;
     }
 
     /**
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index a8569ef..d35aa3cc 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -72,7 +72,8 @@
             TRANSACTION_FAILED_PENDING,
             TRANSACTION_FAILED_AT_HUB,
             TRANSACTION_FAILED_TIMEOUT,
-            TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE})
+            TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE,
+            TRANSACTION_FAILED_HAL_UNAVAILABLE})
     public @interface Result {}
     public static final int TRANSACTION_SUCCESS = 0;
     /**
@@ -103,6 +104,10 @@
      * Failure mode when the transaction has failed internally at the service.
      */
     public static final int TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE = 7;
+    /**
+     * Failure mode when the Context Hub HAL was not available.
+     */
+    public static final int TRANSACTION_FAILED_HAL_UNAVAILABLE = 8;
 
     /**
      * A class describing the response for a ContextHubTransaction.
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index 1bb7c8f..3b39c8d1 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -20,41 +20,53 @@
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.ContextHubMessage;
 import android.hardware.location.NanoApp;
+import android.hardware.location.NanoAppBinary;
 import android.hardware.location.NanoAppFilter;
 import android.hardware.location.NanoAppInstanceInfo;
 import android.hardware.location.IContextHubCallback;
 import android.hardware.location.IContextHubClient;
 import android.hardware.location.IContextHubClientCallback;
+import android.hardware.location.IContextHubTransactionCallback;
 
 /**
  * @hide
  */
 interface IContextHubService {
 
-    // register a callback to receive messages
+    // Registers a callback to receive messages
     int registerCallback(in IContextHubCallback callback);
 
     // Gets a list of available context hub handles
     int[] getContextHubHandles();
 
-    // Get the properties of a hub
+    // Gets the properties of a hub
     ContextHubInfo getContextHubInfo(int contextHubHandle);
 
-    // Load a nanoapp on a specified context hub
+    // Loads a nanoapp at the specified hub (old API)
     int loadNanoApp(int hubHandle, in NanoApp app);
 
-    // Unload a nanoapp instance
+    // Unloads a nanoapp given its instance ID (old API)
     int unloadNanoApp(int nanoAppInstanceHandle);
 
-    // get information about a nanoAppInstance
+    // Gets the NanoAppInstanceInfo of a nanoapp give its instance ID
     NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle);
 
-    // find all nanoApp instances matching some filter
+    // Finds all nanoApp instances matching some filter
     int[] findNanoAppOnHub(int hubHandle, in NanoAppFilter filter);
 
-    // send a message to a nanoApp
+    // Sends a message to a nanoApp
     int sendMessage(int hubHandle, int nanoAppHandle, in ContextHubMessage msg);
 
     // Creates a client to send and receive messages
     IContextHubClient createClient(in IContextHubClientCallback client, int contextHubId);
+
+    // Loads a nanoapp at the specified hub (new API)
+    void loadNanoAppOnHub(
+            int contextHubId, in IContextHubTransactionCallback transactionCallback,
+            in NanoAppBinary nanoAppBinary);
+
+    // Unloads a nanoapp on a specified context hub (new API)
+    void unloadNanoAppFromHub(
+            int contextHubId, in IContextHubTransactionCallback transactionCallback,
+            long nanoAppId);
 }
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java
index e08c659..fcf1f14 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/ContextHubService.java
@@ -738,6 +738,76 @@
         return mClientManager.registerClient(clientCallback, contextHubId);
     }
 
+    /**
+     * Loads a nanoapp binary at the specified Context hub.
+     *
+     * @param contextHubId the ID of the hub to load the binary
+     * @param transactionCallback the client-facing transaction callback interface
+     * @param nanoAppBinary the binary to load
+     *
+     * @throws RemoteException
+     */
+    @Override
+    public void loadNanoAppOnHub(
+            int contextHubId, IContextHubTransactionCallback transactionCallback,
+            NanoAppBinary nanoAppBinary) throws RemoteException {
+        checkPermissions();
+        if (mContextHubProxy == null) {
+            transactionCallback.onTransactionComplete(
+                    ContextHubTransaction.TRANSACTION_FAILED_HAL_UNAVAILABLE);
+            return;
+        }
+        if (!isValidContextHubId(contextHubId)) {
+            Log.e(TAG, "Cannot load nanoapp for invalid hub ID " + contextHubId);
+            transactionCallback.onTransactionComplete(
+                    ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
+            return;
+        }
+        if (nanoAppBinary == null) {
+            Log.e(TAG, "NanoAppBinary cannot be null in loadNanoAppOnHub");
+            transactionCallback.onTransactionComplete(
+                    ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
+            return;
+        }
+
+        ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
+                contextHubId, nanoAppBinary, transactionCallback);
+
+        addTransaction(transaction);
+    }
+
+    /**
+     * Unloads a nanoapp from the specified Context Hub.
+     *
+     * @param contextHubId the ID of the hub to unload the nanoapp
+     * @param transactionCallback the client-facing transaction callback interface
+     * @param nanoAppId the ID of the nanoapp to unload
+     *
+     * @throws RemoteException
+     */
+    @Override
+    public void unloadNanoAppFromHub(
+            int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId)
+            throws RemoteException {
+        checkPermissions();
+        if (mContextHubProxy == null) {
+            transactionCallback.onTransactionComplete(
+                    ContextHubTransaction.TRANSACTION_FAILED_HAL_UNAVAILABLE);
+            return;
+        }
+        if (!isValidContextHubId(contextHubId)) {
+            Log.e(TAG, "Cannot unload nanoapp for invalid hub ID " + contextHubId);
+            transactionCallback.onTransactionComplete(
+                    ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
+            return;
+        }
+
+        ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
+                contextHubId, nanoAppId, transactionCallback);
+
+        addTransaction(transaction);
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;