137 lines
5.9 KiB
Java
137 lines
5.9 KiB
Java
/*
|
|
* Copyright (C) 2024 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.app.appsearch.functions;
|
|
|
|
import android.annotation.FlaggedApi;
|
|
import android.annotation.MainThread;
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.app.Service;
|
|
import android.app.appsearch.AppSearchResult;
|
|
import android.app.appsearch.aidl.AppSearchResultParcel;
|
|
import android.app.appsearch.aidl.IAppFunctionService;
|
|
import android.app.appsearch.aidl.IAppSearchResultCallback;
|
|
import android.app.appsearch.flags.Flags;
|
|
import android.content.Intent;
|
|
import android.os.Binder;
|
|
import android.os.IBinder;
|
|
import android.os.Process;
|
|
|
|
import java.util.function.Consumer;
|
|
|
|
/**
|
|
* Abstract base class to provide app functions to the system.
|
|
*
|
|
* <p>Include the following in the manifest:
|
|
*
|
|
* <pre>
|
|
* {@literal
|
|
* <service android:name=".YourService"
|
|
* android:permission="android.permission.BIND_APP_FUNCTION_SERVICE">
|
|
* <intent-filter>
|
|
* <action android:name="android.app.appsearch.functions.AppFunctionService" />
|
|
* </intent-filter>
|
|
* </service>
|
|
* }
|
|
* </pre>
|
|
*
|
|
* @see AppFunctionManager
|
|
*/
|
|
@FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTIONS)
|
|
public abstract class AppFunctionService extends Service {
|
|
private static final String TAG = "AppSearchAppFunction";
|
|
|
|
/**
|
|
* The {@link Intent} that must be declared as handled by the service. To be supported, the
|
|
* service must also require the {@link AppFunctionManager#PERMISSION_BIND_APP_FUNCTION_SERVICE}
|
|
* permission so that other applications can not abuse it.
|
|
*/
|
|
@NonNull
|
|
public static final String SERVICE_INTERFACE =
|
|
"android.app.appsearch.functions.AppFunctionService";
|
|
|
|
private final Binder mBinder =
|
|
new IAppFunctionService.Stub() {
|
|
@Override
|
|
public void executeAppFunction(
|
|
@NonNull ExecuteAppFunctionRequest request,
|
|
@NonNull IAppSearchResultCallback callback) {
|
|
// TODO(b/327134039): Replace this check with the new permission
|
|
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
|
|
throw new SecurityException("Can only be called by the system server");
|
|
}
|
|
SafeOneTimeAppSearchResultCallback safeCallback =
|
|
new SafeOneTimeAppSearchResultCallback(callback);
|
|
try {
|
|
AppFunctionService.this.onExecuteFunction(
|
|
request,
|
|
appFunctionResult -> {
|
|
AppSearchResultParcel appSearchResultParcel;
|
|
// Create result from value in success case and errorMessage in
|
|
// failure case.
|
|
if (appFunctionResult.isSuccess()) {
|
|
appSearchResultParcel =
|
|
AppSearchResultParcel
|
|
.fromExecuteAppFunctionResponse(
|
|
appFunctionResult.getResultValue());
|
|
} else {
|
|
appSearchResultParcel =
|
|
AppSearchResultParcel.fromFailedResult(
|
|
appFunctionResult);
|
|
}
|
|
safeCallback.onResult(appSearchResultParcel);
|
|
});
|
|
} catch (Exception ex) {
|
|
// Apps should handle exceptions. But if they don't, report the error on
|
|
// behalf of them.
|
|
AppSearchResult failedResult = AppSearchResult.throwableToFailedResult(ex);
|
|
safeCallback.onResult(AppSearchResultParcel.fromFailedResult(failedResult));
|
|
}
|
|
}
|
|
};
|
|
|
|
@NonNull
|
|
@Override
|
|
public final IBinder onBind(@Nullable Intent intent) {
|
|
return mBinder;
|
|
}
|
|
|
|
/**
|
|
* 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". 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.
|
|
*
|
|
* @param request The function execution request.
|
|
* @param callback A callback to report back the result.
|
|
*/
|
|
@MainThread
|
|
public abstract void onExecuteFunction(
|
|
@NonNull ExecuteAppFunctionRequest request,
|
|
@NonNull Consumer<AppSearchResult<ExecuteAppFunctionResponse>> callback);
|
|
}
|