Loading core/api/current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -8773,13 +8773,15 @@ 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>); method @Deprecated @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>); 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 android.os.CancellationSignal, @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 { ctor public AppFunctionService(); method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent); method @MainThread public abstract void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>); method @Deprecated @MainThread public abstract void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>); method @MainThread public void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>); field @NonNull public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService"; } core/java/android/app/appfunctions/AppFunctionManager.java +63 −18 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.annotation.UserHandleAware; import android.content.Context; import android.os.CancellationSignal; import android.os.ICancellationSignal; import android.os.RemoteException; import java.util.Objects; Loading Loading @@ -73,7 +75,43 @@ public final class AppFunctionManager { * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@code * android.permission.EXECUTE_APP_FUNCTIONS}, the execution result will contain {@code * ExecuteAppFunctionResponse.RESULT_DENIED}. * @deprecated Use {@link #executeAppFunction(ExecuteAppFunctionRequest, Executor, * CancellationSignal, Consumer)} instead. This method will be removed once usage references * are updated. */ @RequiresPermission( anyOf = { Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED, Manifest.permission.EXECUTE_APP_FUNCTIONS }, conditional = true) @UserHandleAware @Deprecated public void executeAppFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<ExecuteAppFunctionResponse> callback) { executeAppFunction(request, executor, new CancellationSignal(), callback); } /** * 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 cancellationSignal the cancellation signal to cancel the execution. * @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/357551503): Document the behavior when the cancellation signal is issued. // 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 Loading @@ -88,6 +126,7 @@ public final class AppFunctionManager { public void executeAppFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull CancellationSignal cancellationSignal, @NonNull Consumer<ExecuteAppFunctionResponse> callback) { Objects.requireNonNull(request); Objects.requireNonNull(executor); Loading @@ -96,7 +135,9 @@ public final class AppFunctionManager { ExecuteAppFunctionAidlRequest aidlRequest = new ExecuteAppFunctionAidlRequest( request, mContext.getUser(), mContext.getPackageName()); try { ICancellationSignal cancellationTransport = mService.executeAppFunction( aidlRequest, new IExecuteAppFunctionCallback.Stub() { Loading @@ -105,7 +146,8 @@ public final class AppFunctionManager { try { executor.execute(() -> callback.accept(result)); } catch (RuntimeException e) { // Ideally shouldn't happen since errors are wrapped into the // Ideally shouldn't happen since errors are wrapped into // the // response, but we catch it here for additional safety. callback.accept( ExecuteAppFunctionResponse.newFailure( Loading @@ -115,6 +157,9 @@ public final class AppFunctionManager { } } }); if (cancellationTransport != null) { cancellationSignal.setRemote(cancellationTransport); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading core/java/android/app/appfunctions/AppFunctionService.java +63 −1 Original line number Diff line number Diff line Loading @@ -29,7 +29,12 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.CancellationSignal; import android.os.RemoteCallback; import android.os.RemoteException; import java.util.function.Consumer; Loading Loading @@ -74,6 +79,7 @@ public abstract class AppFunctionService extends Service { */ void perform( @NonNull ExecuteAppFunctionRequest request, @NonNull CancellationSignal cancellationSignal, @NonNull Consumer<ExecuteAppFunctionResponse> callback); } Loading @@ -85,6 +91,7 @@ public abstract class AppFunctionService extends Service { @Override public void executeAppFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull ICancellationCallback cancellationCallback, @NonNull IExecuteAppFunctionCallback callback) { if (context.checkCallingPermission(BIND_APP_FUNCTION_SERVICE) == PERMISSION_DENIED) { Loading @@ -93,7 +100,10 @@ public abstract class AppFunctionService extends Service { SafeOneTimeExecuteAppFunctionCallback safeCallback = new SafeOneTimeExecuteAppFunctionCallback(callback); try { onExecuteFunction.perform(request, safeCallback::onResult); onExecuteFunction.perform( request, buildCancellationSignal(cancellationCallback), safeCallback::onResult); } catch (Exception ex) { // Apps should handle exceptions. But if they don't, report the error on // behalf of them. Loading @@ -105,6 +115,21 @@ public abstract class AppFunctionService extends Service { }; } private static CancellationSignal buildCancellationSignal( @NonNull ICancellationCallback cancellationCallback) { final ICancellationSignal cancellationSignalTransport = CancellationSignal.createTransport(); CancellationSignal cancellationSignal = CancellationSignal.fromTransport(cancellationSignalTransport); try { cancellationCallback.sendCancellationTransport(cancellationSignalTransport); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return cancellationSignal ; } private final Binder mBinder = createBinder( AppFunctionService.this, AppFunctionService.this::onExecuteFunction); Loading @@ -115,6 +140,7 @@ public abstract class AppFunctionService extends Service { return mBinder; } /** * Called by the system to execute a specific app function. * Loading @@ -134,9 +160,45 @@ public abstract class AppFunctionService extends Service { * * @param request The function execution request. * @param callback A callback to report back the result. * * @deprecated Use {@link #onExecuteFunction(ExecuteAppFunctionRequest, CancellationSignal, * Consumer)} instead. This method will be removed once usage references are updated. */ @MainThread @Deprecated public abstract void onExecuteFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull Consumer<ExecuteAppFunctionResponse> callback); /** * Called by the system to execute a specific app function. * * <p>This method is triggered when the system requests your AppFunctionService to handle a * particular function you have registered and made available. * * <p>To ensure proper routing of function requests, assign a unique identifier to each * function. This identifier doesn't need to be globally unique, but it must be unique within * your app. For example, a function to order food could be identified as "orderFood". In most * cases this identifier should come from the ID automatically generated by the AppFunctions * SDK. You can determine the specific function to invoke by calling {@link * ExecuteAppFunctionRequest#getFunctionIdentifier()}. * * <p>This method is always triggered in the main thread. You should run heavy tasks on a worker * thread and dispatch the result with the given callback. You should always report back the * result using the callback, no matter if the execution was successful or not. * * <p>This method also accepts a {@link CancellationSignal} that the app should listen to cancel * the execution of function if requested by the system. * * @param request The function execution request. * @param cancellationSignal A signal to cancel the execution. * @param callback A callback to report back the result. */ @MainThread public void onExecuteFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull CancellationSignal cancellationSignal, @NonNull Consumer<ExecuteAppFunctionResponse> callback) { onExecuteFunction(request, callback); } } core/java/android/app/appfunctions/IAppFunctionManager.aidl +3 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.app.appfunctions; import android.app.appfunctions.ExecuteAppFunctionAidlRequest; import android.app.appfunctions.IExecuteAppFunctionCallback; import android.os.ICancellationSignal; /** * Defines the interface for apps to interact with the app function execution service Loading @@ -32,7 +33,7 @@ interface IAppFunctionManager { * @param callback the callback to report the result. */ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,android.Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional = true)") void executeAppFunction( ICancellationSignal executeAppFunction( in ExecuteAppFunctionAidlRequest request, in IExecuteAppFunctionCallback callback ); Loading core/java/android/app/appfunctions/IAppFunctionService.aidl +3 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ package android.app.appfunctions; import android.os.Bundle; import android.app.appfunctions.ICancellationCallback; import android.app.appfunctions.IExecuteAppFunctionCallback; import android.app.appfunctions.ExecuteAppFunctionRequest; Loading @@ -34,10 +34,12 @@ oneway interface IAppFunctionService { * Called by the system to execute a specific app function. * * @param request the function execution request. * @param cancellationCallback a callback to send back the cancellation transport. * @param callback a callback to report back the result. */ void executeAppFunction( in ExecuteAppFunctionRequest request, in ICancellationCallback cancellationCallback, in IExecuteAppFunctionCallback callback ); } Loading
core/api/current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -8773,13 +8773,15 @@ 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>); method @Deprecated @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>); 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 android.os.CancellationSignal, @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 { ctor public AppFunctionService(); method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent); method @MainThread public abstract void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>); method @Deprecated @MainThread public abstract void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>); method @MainThread public void onExecuteFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>); field @NonNull public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService"; }
core/java/android/app/appfunctions/AppFunctionManager.java +63 −18 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.annotation.UserHandleAware; import android.content.Context; import android.os.CancellationSignal; import android.os.ICancellationSignal; import android.os.RemoteException; import java.util.Objects; Loading Loading @@ -73,7 +75,43 @@ public final class AppFunctionManager { * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@code * android.permission.EXECUTE_APP_FUNCTIONS}, the execution result will contain {@code * ExecuteAppFunctionResponse.RESULT_DENIED}. * @deprecated Use {@link #executeAppFunction(ExecuteAppFunctionRequest, Executor, * CancellationSignal, Consumer)} instead. This method will be removed once usage references * are updated. */ @RequiresPermission( anyOf = { Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED, Manifest.permission.EXECUTE_APP_FUNCTIONS }, conditional = true) @UserHandleAware @Deprecated public void executeAppFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<ExecuteAppFunctionResponse> callback) { executeAppFunction(request, executor, new CancellationSignal(), callback); } /** * 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 cancellationSignal the cancellation signal to cancel the execution. * @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/357551503): Document the behavior when the cancellation signal is issued. // 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 Loading @@ -88,6 +126,7 @@ public final class AppFunctionManager { public void executeAppFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull CancellationSignal cancellationSignal, @NonNull Consumer<ExecuteAppFunctionResponse> callback) { Objects.requireNonNull(request); Objects.requireNonNull(executor); Loading @@ -96,7 +135,9 @@ public final class AppFunctionManager { ExecuteAppFunctionAidlRequest aidlRequest = new ExecuteAppFunctionAidlRequest( request, mContext.getUser(), mContext.getPackageName()); try { ICancellationSignal cancellationTransport = mService.executeAppFunction( aidlRequest, new IExecuteAppFunctionCallback.Stub() { Loading @@ -105,7 +146,8 @@ public final class AppFunctionManager { try { executor.execute(() -> callback.accept(result)); } catch (RuntimeException e) { // Ideally shouldn't happen since errors are wrapped into the // Ideally shouldn't happen since errors are wrapped into // the // response, but we catch it here for additional safety. callback.accept( ExecuteAppFunctionResponse.newFailure( Loading @@ -115,6 +157,9 @@ public final class AppFunctionManager { } } }); if (cancellationTransport != null) { cancellationSignal.setRemote(cancellationTransport); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading
core/java/android/app/appfunctions/AppFunctionService.java +63 −1 Original line number Diff line number Diff line Loading @@ -29,7 +29,12 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.CancellationSignal; import android.os.RemoteCallback; import android.os.RemoteException; import java.util.function.Consumer; Loading Loading @@ -74,6 +79,7 @@ public abstract class AppFunctionService extends Service { */ void perform( @NonNull ExecuteAppFunctionRequest request, @NonNull CancellationSignal cancellationSignal, @NonNull Consumer<ExecuteAppFunctionResponse> callback); } Loading @@ -85,6 +91,7 @@ public abstract class AppFunctionService extends Service { @Override public void executeAppFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull ICancellationCallback cancellationCallback, @NonNull IExecuteAppFunctionCallback callback) { if (context.checkCallingPermission(BIND_APP_FUNCTION_SERVICE) == PERMISSION_DENIED) { Loading @@ -93,7 +100,10 @@ public abstract class AppFunctionService extends Service { SafeOneTimeExecuteAppFunctionCallback safeCallback = new SafeOneTimeExecuteAppFunctionCallback(callback); try { onExecuteFunction.perform(request, safeCallback::onResult); onExecuteFunction.perform( request, buildCancellationSignal(cancellationCallback), safeCallback::onResult); } catch (Exception ex) { // Apps should handle exceptions. But if they don't, report the error on // behalf of them. Loading @@ -105,6 +115,21 @@ public abstract class AppFunctionService extends Service { }; } private static CancellationSignal buildCancellationSignal( @NonNull ICancellationCallback cancellationCallback) { final ICancellationSignal cancellationSignalTransport = CancellationSignal.createTransport(); CancellationSignal cancellationSignal = CancellationSignal.fromTransport(cancellationSignalTransport); try { cancellationCallback.sendCancellationTransport(cancellationSignalTransport); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return cancellationSignal ; } private final Binder mBinder = createBinder( AppFunctionService.this, AppFunctionService.this::onExecuteFunction); Loading @@ -115,6 +140,7 @@ public abstract class AppFunctionService extends Service { return mBinder; } /** * Called by the system to execute a specific app function. * Loading @@ -134,9 +160,45 @@ public abstract class AppFunctionService extends Service { * * @param request The function execution request. * @param callback A callback to report back the result. * * @deprecated Use {@link #onExecuteFunction(ExecuteAppFunctionRequest, CancellationSignal, * Consumer)} instead. This method will be removed once usage references are updated. */ @MainThread @Deprecated public abstract void onExecuteFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull Consumer<ExecuteAppFunctionResponse> callback); /** * Called by the system to execute a specific app function. * * <p>This method is triggered when the system requests your AppFunctionService to handle a * particular function you have registered and made available. * * <p>To ensure proper routing of function requests, assign a unique identifier to each * function. This identifier doesn't need to be globally unique, but it must be unique within * your app. For example, a function to order food could be identified as "orderFood". In most * cases this identifier should come from the ID automatically generated by the AppFunctions * SDK. You can determine the specific function to invoke by calling {@link * ExecuteAppFunctionRequest#getFunctionIdentifier()}. * * <p>This method is always triggered in the main thread. You should run heavy tasks on a worker * thread and dispatch the result with the given callback. You should always report back the * result using the callback, no matter if the execution was successful or not. * * <p>This method also accepts a {@link CancellationSignal} that the app should listen to cancel * the execution of function if requested by the system. * * @param request The function execution request. * @param cancellationSignal A signal to cancel the execution. * @param callback A callback to report back the result. */ @MainThread public void onExecuteFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull CancellationSignal cancellationSignal, @NonNull Consumer<ExecuteAppFunctionResponse> callback) { onExecuteFunction(request, callback); } }
core/java/android/app/appfunctions/IAppFunctionManager.aidl +3 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.app.appfunctions; import android.app.appfunctions.ExecuteAppFunctionAidlRequest; import android.app.appfunctions.IExecuteAppFunctionCallback; import android.os.ICancellationSignal; /** * Defines the interface for apps to interact with the app function execution service Loading @@ -32,7 +33,7 @@ interface IAppFunctionManager { * @param callback the callback to report the result. */ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,android.Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional = true)") void executeAppFunction( ICancellationSignal executeAppFunction( in ExecuteAppFunctionAidlRequest request, in IExecuteAppFunctionCallback callback ); Loading
core/java/android/app/appfunctions/IAppFunctionService.aidl +3 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ package android.app.appfunctions; import android.os.Bundle; import android.app.appfunctions.ICancellationCallback; import android.app.appfunctions.IExecuteAppFunctionCallback; import android.app.appfunctions.ExecuteAppFunctionRequest; Loading @@ -34,10 +34,12 @@ oneway interface IAppFunctionService { * Called by the system to execute a specific app function. * * @param request the function execution request. * @param cancellationCallback a callback to send back the cancellation transport. * @param callback a callback to report back the result. */ void executeAppFunction( in ExecuteAppFunctionRequest request, in ICancellationCallback cancellationCallback, in IExecuteAppFunctionCallback callback ); }