Add is/setAppFunctionEnabled to sidecar

Flag: android.app.appfunctions.flags.enable_app_function_manager
Test: atest CtsAppFunctionTestCases -c
BUG: 357551503
Change-Id: I4b9fd044da76f1ced1c7be0c6d894fc4e70d2a90
diff --git a/libs/appfunctions/api/current.txt b/libs/appfunctions/api/current.txt
index 3ed33db..bb0fc41 100644
--- a/libs/appfunctions/api/current.txt
+++ b/libs/appfunctions/api/current.txt
@@ -5,6 +5,11 @@
     ctor public AppFunctionManager(android.content.Context);
     method public void executeAppFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
     method @Deprecated public void executeAppFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
+    method public void isAppFunctionEnabled(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
+    method public void setAppFunctionEnabled(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,java.lang.Exception>);
+    field public static final int APP_FUNCTION_STATE_DEFAULT = 0; // 0x0
+    field public static final int APP_FUNCTION_STATE_DISABLED = 2; // 0x2
+    field public static final int APP_FUNCTION_STATE_ENABLED = 1; // 0x1
   }
 
   public abstract class AppFunctionService extends android.app.Service {
@@ -41,6 +46,7 @@
     field public static final String PROPERTY_RETURN_VALUE = "returnValue";
     field public static final int RESULT_APP_UNKNOWN_ERROR = 2; // 0x2
     field public static final int RESULT_DENIED = 1; // 0x1
+    field public static final int RESULT_DISABLED = 6; // 0x6
     field public static final int RESULT_INTERNAL_ERROR = 3; // 0x3
     field public static final int RESULT_INVALID_ARGUMENT = 4; // 0x4
     field public static final int RESULT_OK = 0; // 0x0
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java
index 815fe05..d660926 100644
--- a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java
@@ -16,11 +16,18 @@
 
 package com.google.android.appfunctions.sidecar;
 
+import android.Manifest;
 import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.UserHandleAware;
 import android.content.Context;
 import android.os.CancellationSignal;
+import android.os.OutcomeReceiver;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -37,6 +44,39 @@
 // TODO(b/357551503): Implement get and set enabled app function APIs.
 // TODO(b/367329899): Add sidecar library to Android B builds.
 public final class AppFunctionManager {
+    /**
+     * The default state of the app function. Call {@link #setAppFunctionEnabled} with this to reset
+     * enabled state to the default value.
+     */
+    public static final int APP_FUNCTION_STATE_DEFAULT = 0;
+
+    /**
+     * The app function is enabled. To enable an app function, call {@link #setAppFunctionEnabled}
+     * with this value.
+     */
+    public static final int APP_FUNCTION_STATE_ENABLED = 1;
+
+    /**
+     * The app function is disabled. To disable an app function, call {@link #setAppFunctionEnabled}
+     * with this value.
+     */
+    public static final int APP_FUNCTION_STATE_DISABLED = 2;
+
+    /**
+     * The enabled state of the app function.
+     *
+     * @hide
+     */
+    @IntDef(
+            prefix = {"APP_FUNCTION_STATE_"},
+            value = {
+                    APP_FUNCTION_STATE_DEFAULT,
+                    APP_FUNCTION_STATE_ENABLED,
+                    APP_FUNCTION_STATE_DISABLED
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EnabledState {}
+
     private final android.app.appfunctions.AppFunctionManager mManager;
     private final Context mContext;
 
@@ -111,4 +151,64 @@
                 new CancellationSignal(),
                 callback);
     }
+
+    /**
+     * Returns a boolean through a callback, indicating whether the app function is enabled.
+     *
+     * <p>* This method can only check app functions owned by the caller, or those where the caller
+     * has visibility to the owner package and holds either the {@link
+     * Manifest.permission#EXECUTE_APP_FUNCTIONS} or {@link
+     * Manifest.permission#EXECUTE_APP_FUNCTIONS_TRUSTED} permission.
+     *
+     * <p>If operation fails, the callback's {@link OutcomeReceiver#onError} is called with errors:
+     *
+     * <ul>
+     *   <li>{@link IllegalArgumentException}, if the function is not found or the caller does not
+     *       have access to it.
+     * </ul>
+     *
+     * @param functionIdentifier the identifier of the app function to check (unique within the
+     *     target package) and in most cases, these are automatically generated by the AppFunctions
+     *     SDK
+     * @param targetPackage the package name of the app function's owner
+     * @param executor the executor to run the request
+     * @param callback the callback to receive the function enabled check result
+     */
+    public void isAppFunctionEnabled(
+            @NonNull String functionIdentifier,
+            @NonNull String targetPackage,
+            @NonNull Executor executor,
+            @NonNull OutcomeReceiver<Boolean, Exception> callback) {
+        mManager.isAppFunctionEnabled(functionIdentifier, targetPackage, executor, callback);
+    }
+
+    /**
+     * Sets the enabled state of the app function owned by the calling package.
+     *
+     * <p>If operation fails, the callback's {@link OutcomeReceiver#onError} is called with errors:
+     *
+     * <ul>
+     *   <li>{@link IllegalArgumentException}, if the function is not found or the caller does not
+     *       have access to it.
+     * </ul>
+     *
+     * @param functionIdentifier the identifier of the app function to enable (unique within the
+     *     calling package). In most cases, identifiers are automatically generated by the
+     *     AppFunctions SDK
+     * @param newEnabledState the new state of the app function
+     * @param executor the executor to run the callback
+     * @param callback the callback to receive the result of the function enablement. The call was
+     *     successful if no exception was thrown.
+     */
+    // Constants in @EnabledState should always mirror those in
+    // android.app.appfunctions.AppFunctionManager.
+    @SuppressLint("WrongConstant")
+    @UserHandleAware
+    public void setAppFunctionEnabled(
+            @NonNull String functionIdentifier,
+            @EnabledState int newEnabledState,
+            @NonNull Executor executor,
+            @NonNull OutcomeReceiver<Void, Exception> callback) {
+        mManager.setAppFunctionEnabled(functionIdentifier, newEnabledState, executor, callback);
+    }
 }
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
index 60c25fa..c7ce95b 100644
--- a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
@@ -76,6 +76,9 @@
     /** The operation was timed out. */
     public static final int RESULT_TIMED_OUT = 5;
 
+    /** The caller tried to execute a disabled app function. */
+    public static final int RESULT_DISABLED = 6;
+
     /** The result code of the app function execution. */
     @ResultCode private final int mResultCode;
 
@@ -234,6 +237,7 @@
                     RESULT_INTERNAL_ERROR,
                     RESULT_INVALID_ARGUMENT,
                     RESULT_TIMED_OUT,
+                    RESULT_DISABLED
             })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ResultCode {}