1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.extensions.appfunctions; 18 19 import static com.android.extensions.appfunctions.SidecarConverter.getPlatformAppFunctionException; 20 import static com.android.extensions.appfunctions.SidecarConverter.getPlatformExecuteAppFunctionResponse; 21 22 import android.annotation.MainThread; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SdkConstant; 26 import android.app.Service; 27 import android.content.Intent; 28 import android.os.Binder; 29 import android.os.CancellationSignal; 30 import android.os.IBinder; 31 import android.os.OutcomeReceiver; 32 33 /** 34 * Abstract base class to provide app functions to the system. 35 * 36 * <p>Include the following in the manifest: 37 * 38 * <pre> 39 * {@literal 40 * <service android:name=".YourService" 41 * android:permission="android.permission.BIND_APP_FUNCTION_SERVICE"> 42 * <intent-filter> 43 * <action android:name="android.app.appfunctions.AppFunctionService" /> 44 * </intent-filter> 45 * </service> 46 * } 47 * </pre> 48 * 49 * <p>This class wraps {@link android.app.appfunctions.AppFunctionService} functionalities and 50 * exposes it here as a sidecar library (avoiding direct dependency on the platform API). 51 * 52 * @see AppFunctionManager 53 */ 54 public abstract class AppFunctionService extends Service { 55 /** 56 * The permission to only allow system access to the functions through {@link 57 * AppFunctionManagerService}. 58 */ 59 @NonNull 60 public static final String BIND_APP_FUNCTION_SERVICE = 61 "android.permission.BIND_APP_FUNCTION_SERVICE"; 62 63 /** 64 * The {@link Intent} that must be declared as handled by the service. To be supported, the 65 * service must also require the {@link BIND_APP_FUNCTION_SERVICE} permission so that other 66 * applications can not abuse it. 67 */ 68 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 69 @NonNull 70 public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService"; 71 72 private final Binder mBinder = 73 android.app.appfunctions.AppFunctionService.createBinder( 74 /* context= */ this, 75 /* onExecuteFunction= */ (platformRequest, 76 callingPackage, 77 callingPackageSigningInfo, 78 cancellationSignal, 79 callback) -> { 80 AppFunctionService.this.onExecuteFunction( 81 SidecarConverter.getSidecarExecuteAppFunctionRequest( 82 platformRequest), 83 callingPackage, 84 cancellationSignal, 85 new OutcomeReceiver<>() { 86 @Override 87 public void onResult(ExecuteAppFunctionResponse result) { 88 callback.onResult( 89 getPlatformExecuteAppFunctionResponse(result)); 90 } 91 92 @Override 93 public void onError(AppFunctionException exception) { 94 callback.onError( 95 getPlatformAppFunctionException(exception)); 96 } 97 }); 98 }); 99 100 @NonNull 101 @Override onBind(@ullable Intent intent)102 public final IBinder onBind(@Nullable Intent intent) { 103 return mBinder; 104 } 105 106 /** 107 * Called by the system to execute a specific app function. 108 * 109 * <p>This method is the entry point for handling all app function requests in an app. When the 110 * system needs your AppFunctionService to perform a function, it will invoke this method. 111 * 112 * <p>Each function you've registered is identified by a unique identifier. This identifier 113 * doesn't need to be globally unique, but it must be unique within your app. For example, a 114 * function to order food could be identified as "orderFood". In most cases, this identifier is 115 * automatically generated by the AppFunctions SDK. 116 * 117 * <p>You can determine which function to execute by calling {@link 118 * ExecuteAppFunctionRequest#getFunctionIdentifier()}. This allows your service to route the 119 * incoming request to the appropriate logic for handling the specific function. 120 * 121 * <p>This method is always triggered in the main thread. You should run heavy tasks on a worker 122 * thread and dispatch the result with the given callback. You should always report back the 123 * result using the callback, no matter if the execution was successful or not. 124 * 125 * <p>This method also accepts a {@link CancellationSignal} that the app should listen to cancel 126 * the execution of function if requested by the system. 127 * 128 * @param request The function execution request. 129 * @param callingPackage The package name of the app that is requesting the execution. 130 * @param cancellationSignal A signal to cancel the execution. 131 * @param callback A callback to report back the result or error. 132 */ 133 @MainThread onExecuteFunction( @onNull ExecuteAppFunctionRequest request, @NonNull String callingPackage, @NonNull CancellationSignal cancellationSignal, @NonNull OutcomeReceiver<ExecuteAppFunctionResponse, AppFunctionException> callback)134 public abstract void onExecuteFunction( 135 @NonNull ExecuteAppFunctionRequest request, 136 @NonNull String callingPackage, 137 @NonNull CancellationSignal cancellationSignal, 138 @NonNull OutcomeReceiver<ExecuteAppFunctionResponse, AppFunctionException> callback); 139 } 140