Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f4f38ce authored by Tony Mak's avatar Tony Mak Committed by Android (Google) Code Review
Browse files

Merge changes from topic "cancellation-signal" into main

* changes:
  Update Sidecar Library with CancellationSignal.
  Add CancellationSignal to AppFunctionManager API.
parents fb097f1f 193643cb
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -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";
  }
+63 −18
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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);
@@ -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() {
@@ -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(
@@ -115,6 +157,9 @@ public final class AppFunctionManager {
                                    }
                                }
                            });
            if (cancellationTransport != null) {
                cancellationSignal.setRemote(cancellationTransport);
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+63 −1
Original line number Diff line number Diff line
@@ -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;

@@ -74,6 +79,7 @@ public abstract class AppFunctionService extends Service {
         */
        void perform(
                @NonNull ExecuteAppFunctionRequest request,
                @NonNull CancellationSignal cancellationSignal,
                @NonNull Consumer<ExecuteAppFunctionResponse> callback);
    }

@@ -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) {
@@ -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.
@@ -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);
@@ -115,6 +140,7 @@ public abstract class AppFunctionService extends Service {
        return mBinder;
    }


    /**
     * Called by the system to execute a specific app function.
     *
@@ -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);
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -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
@@ -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
    );
+3 −1
Original line number Diff line number Diff line
@@ -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;

@@ -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