summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt1
-rw-r--r--core/java/android/app/appfunctions/AppFunctionManager.java76
-rw-r--r--core/java/android/app/appfunctions/AppFunctionService.java8
-rw-r--r--core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java12
4 files changed, 89 insertions, 8 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index c06b81498bc9..f96e4fdbeeb9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -8722,6 +8722,7 @@ package android.app.admin {
package android.app.appfunctions {
@FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public final class AppFunctionManager {
+ method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", "android.permission.EXECUTE_APP_FUNCTIONS"}, conditional=true) public void executeAppFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>);
}
@FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public abstract class AppFunctionService extends android.app.Service {
diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java
index 7801201e8bcb..4b6f406ded9d 100644
--- a/core/java/android/app/appfunctions/AppFunctionManager.java
+++ b/core/java/android/app/appfunctions/AppFunctionManager.java
@@ -16,11 +16,22 @@
package android.app.appfunctions;
+import static android.app.appfunctions.ExecuteAppFunctionResponse.getResultCode;
import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
+import android.Manifest;
+import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
import android.content.Context;
+import android.os.RemoteException;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Provides app functions related functionalities.
@@ -28,6 +39,7 @@ import android.content.Context;
* <p>App function is a specific piece of functionality that an app offers to the system. These
* functionalities can be integrated into various system features.
*/
+// TODO(b/357551503): Implement get and set enabled app function APIs.
@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
@SystemService(Context.APP_FUNCTION_SERVICE)
public final class AppFunctionManager {
@@ -35,7 +47,10 @@ public final class AppFunctionManager {
private final Context mContext;
/**
- * TODO(b/357551503): add comments when implement this class
+ * Creates an instance.
+ *
+ * @param mService An interface to the backing service.
+ * @param context A {@link Context}.
*
* @hide
*/
@@ -43,4 +58,63 @@ public final class AppFunctionManager {
this.mService = mService;
this.mContext = context;
}
+
+ /**
+ * Executes the app function.
+ * <p>
+ * Note: Applications can execute functions they define. To execute functions defined in
+ * another component, apps would need to have
+ * {@code android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or
+ * {@code android.permission.EXECUTE_APP_FUNCTIONS}.
+ *
+ * @param request the request to execute the app function
+ * @param executor the executor to run the callback
+ * @param callback the callback to receive the function execution result. if the calling app
+ * does not own the app function or does not have {@code
+ * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@code
+ * android.permission.EXECUTE_APP_FUNCTIONS}, the execution result will contain
+ * {@code ExecuteAppFunctionResponse.RESULT_DENIED}.
+ */
+ // TODO(b/360864791): Document that apps can opt-out from being executed by callers with
+ // EXECUTE_APP_FUNCTIONS and how a caller knows whether a function is opted out.
+ // TODO(b/357551503): Update documentation when get / set APIs are implemented that this will
+ // also return RESULT_DENIED if the app function is disabled.
+ @RequiresPermission(
+ anyOf = {Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
+ Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional = true)
+ @UserHandleAware
+ public void executeAppFunction(
+ @NonNull ExecuteAppFunctionRequest request,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<ExecuteAppFunctionResponse> callback
+ ) {
+ Objects.requireNonNull(request);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ ExecuteAppFunctionAidlRequest aidlRequest =
+ new ExecuteAppFunctionAidlRequest(
+ request,
+ mContext.getUser(),
+ mContext.getPackageName());
+ try {
+ mService.executeAppFunction(
+ aidlRequest,
+ new IExecuteAppFunctionCallback.Stub() {
+ @Override
+ public void onResult(ExecuteAppFunctionResponse result) {
+ try {
+ executor.execute(() -> callback.accept(result));
+ } catch (RuntimeException e) {
+ // Ideally shouldn't happen since errors are wrapped into the
+ // response, but we catch it here for additional safety.
+ callback.accept(new ExecuteAppFunctionResponse.Builder(
+ getResultCode(e), e.getMessage()).build());
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/appfunctions/AppFunctionService.java b/core/java/android/app/appfunctions/AppFunctionService.java
index fca465f5e8a9..d117227f242c 100644
--- a/core/java/android/app/appfunctions/AppFunctionService.java
+++ b/core/java/android/app/appfunctions/AppFunctionService.java
@@ -16,6 +16,7 @@
package android.app.appfunctions;
+import static android.app.appfunctions.ExecuteAppFunctionResponse.getResultCode;
import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.Manifest.permission.BIND_APP_FUNCTION_SERVICE;
@@ -86,13 +87,6 @@ public abstract class AppFunctionService extends Service {
}
};
- private static int getResultCode(@NonNull Throwable t) {
- if (t instanceof IllegalArgumentException) {
- return ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT;
- }
- return ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR;
- }
-
@NonNull
@Override
public final IBinder onBind(@Nullable Intent intent) {
diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
index 72205d9cf6c6..872327ddd461 100644
--- a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
+++ b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
@@ -236,6 +236,18 @@ public final class ExecuteAppFunctionResponse implements Parcelable {
}
/**
+ * Returns result codes from throwable.
+ *
+ * @hide
+ */
+ static @ResultCode int getResultCode(@NonNull Throwable t) {
+ if (t instanceof IllegalArgumentException) {
+ return ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT;
+ }
+ return ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR;
+ }
+
+ /**
* The builder for creating {@link ExecuteAppFunctionResponse} instances.
*/
@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)