diff options
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) |