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

Commit 69b20806 authored by Aldi Fahrezi's avatar Aldi Fahrezi
Browse files

Add AppFunctions Sidecar

Test: atest CtsAppFunctionTestCases
Flag: NONE sidecar library (non platform)

Change-Id: I2f8af326a2852314ab4ed9b54166024a8888dc63
parent 5268d622
Loading
Loading
Loading
Loading
+47 −22
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
@@ -60,20 +61,39 @@ public abstract class AppFunctionService extends Service {
    @NonNull
    public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService";

    private final Binder mBinder =
            new IAppFunctionService.Stub() {
    /**
     * Functional interface to represent the execution logic of an app function.
     *
     * @hide
     */
    @FunctionalInterface
    public interface OnExecuteFunction {
        /**
         * Performs the semantic of executing the function specified by the provided request and
         * return the response through the provided callback.
         */
        void perform(
                @NonNull ExecuteAppFunctionRequest request,
                @NonNull Consumer<ExecuteAppFunctionResponse> callback);
    }

    /** @hide */
    @NonNull
    public static Binder createBinder(
            @NonNull Context context, @NonNull OnExecuteFunction onExecuteFunction) {
        return new IAppFunctionService.Stub() {
            @Override
            public void executeAppFunction(
                    @NonNull ExecuteAppFunctionRequest request,
                    @NonNull IExecuteAppFunctionCallback callback) {
                    if (AppFunctionService.this.checkCallingPermission(BIND_APP_FUNCTION_SERVICE)
                if (context.checkCallingPermission(BIND_APP_FUNCTION_SERVICE)
                        == PERMISSION_DENIED) {
                    throw new SecurityException("Can only be called by the system server.");
                }
                SafeOneTimeExecuteAppFunctionCallback safeCallback =
                        new SafeOneTimeExecuteAppFunctionCallback(callback);
                try {
                        AppFunctionService.this.onExecuteFunction(request, safeCallback::onResult);
                    onExecuteFunction.perform(request, safeCallback::onResult);
                } catch (Exception ex) {
                    // Apps should handle exceptions. But if they don't, report the error on
                    // behalf of them.
@@ -83,6 +103,11 @@ public abstract class AppFunctionService extends Service {
                }
            }
        };
    }

    private final Binder mBinder = createBinder(
            AppFunctionService.this,
            AppFunctionService.this::onExecuteFunction);

    @NonNull
    @Override
+31 −0
Original line number Diff line number Diff line
// 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 {
    default_applicable_licenses: ["Android-Apache-2.0"],
}

java_sdk_library {
    name: "com.google.android.appfunctions.sidecar",
    owner: "google",
    srcs: ["java/**/*.java"],
    api_packages: ["com.google.android.appfunctions.sidecar"],
    dex_preopt: {
        enabled: false,
    },
    system_ext_specific: true,
    no_dist: true,
    unsafe_ignore_missing_latest_api: true,
}
+49 −0
Original line number Diff line number Diff line
// Signature format: 2.0
package com.google.android.appfunctions.sidecar {

  public final class AppFunctionManager {
    ctor public AppFunctionManager(android.content.Context);
    method public void executeAppFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
  }

  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 com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
    field @NonNull public static final String BIND_APP_FUNCTION_SERVICE = "android.permission.BIND_APP_FUNCTION_SERVICE";
    field @NonNull public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService";
  }

  public final class ExecuteAppFunctionRequest {
    method @NonNull public android.os.Bundle getExtras();
    method @NonNull public String getFunctionIdentifier();
    method @NonNull public android.app.appsearch.GenericDocument getParameters();
    method @NonNull public String getTargetPackageName();
  }

  public static final class ExecuteAppFunctionRequest.Builder {
    ctor public ExecuteAppFunctionRequest.Builder(@NonNull String, @NonNull String);
    method @NonNull public com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest build();
    method @NonNull public com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest.Builder setExtras(@NonNull android.os.Bundle);
    method @NonNull public com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest.Builder setParameters(@NonNull android.app.appsearch.GenericDocument);
  }

  public final class ExecuteAppFunctionResponse {
    method @Nullable public String getErrorMessage();
    method @NonNull public android.os.Bundle getExtras();
    method public int getResultCode();
    method @NonNull public android.app.appsearch.GenericDocument getResultDocument();
    method public boolean isSuccess();
    method @NonNull public static com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse newFailure(int, @Nullable String, @Nullable android.os.Bundle);
    method @NonNull public static com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse newSuccess(@NonNull android.app.appsearch.GenericDocument, @Nullable android.os.Bundle);
    field public static final String PROPERTY_RETURN_VALUE = "returnValue";
    field public static final int RESULT_APP_UNKNOWN_ERROR = 2; // 0x2
    field public static final int RESULT_DENIED = 1; // 0x1
    field public static final int RESULT_INTERNAL_ERROR = 3; // 0x3
    field public static final int RESULT_INVALID_ARGUMENT = 4; // 0x4
    field public static final int RESULT_OK = 0; // 0x0
    field public static final int RESULT_TIMED_OUT = 5; // 0x5
  }

}
+1 −0
Original line number Diff line number Diff line
// Signature format: 2.0
+1 −0
Original line number Diff line number Diff line
// Signature format: 2.0
Loading