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 android.app.appfunctions; 18 19 import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER; 20 21 import android.annotation.FlaggedApi; 22 import android.annotation.NonNull; 23 import android.app.appsearch.GenericDocument; 24 import android.os.Bundle; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 28 import java.util.Objects; 29 30 /** 31 * A request to execute an app function. 32 * 33 * <p>The {@link ExecuteAppFunctionRequest#getParameters()} contains the parameters for the function 34 * to be executed in a GenericDocument. Structured classes defined in the AppFunction SDK can be 35 * converted into GenericDocuments. 36 * 37 * <p>The {@link ExecuteAppFunctionRequest#getExtras()} provides any extra metadata for the request. 38 * Structured APIs can be exposed in the SDK by packing and unpacking this Bundle. 39 */ 40 @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) 41 public final class ExecuteAppFunctionRequest implements Parcelable { 42 @NonNull 43 public static final Creator<ExecuteAppFunctionRequest> CREATOR = 44 new Creator<>() { 45 @Override 46 public ExecuteAppFunctionRequest createFromParcel(Parcel parcel) { 47 String targetPackageName = parcel.readString8(); 48 String functionIdentifier = parcel.readString8(); 49 GenericDocumentWrapper parameters = 50 GenericDocumentWrapper.CREATOR.createFromParcel(parcel); 51 Bundle extras = parcel.readBundle(Bundle.class.getClassLoader()); 52 return new ExecuteAppFunctionRequest( 53 targetPackageName, functionIdentifier, extras, parameters); 54 } 55 56 @Override 57 public ExecuteAppFunctionRequest[] newArray(int size) { 58 return new ExecuteAppFunctionRequest[size]; 59 } 60 }; 61 62 /** Returns the package name of the app that hosts/owns the function. */ 63 @NonNull private final String mTargetPackageName; 64 65 /** 66 * The unique string identifier of the app function to be executed. This identifier is used to 67 * execute a specific app function. 68 */ 69 @NonNull private final String mFunctionIdentifier; 70 71 /** Returns additional metadata relevant to this function execution request. */ 72 @NonNull private final Bundle mExtras; 73 74 /** 75 * Returns the parameters required to invoke this function. Within this [GenericDocument], the 76 * property names are the names of the function parameters and the property values are the 77 * values of those parameters. 78 * 79 * <p>The document may have missing parameters. Developers are advised to implement defensive 80 * handling measures. 81 */ 82 @NonNull private final GenericDocumentWrapper mParameters; 83 ExecuteAppFunctionRequest( @onNull String targetPackageName, @NonNull String functionIdentifier, @NonNull Bundle extras, @NonNull GenericDocumentWrapper parameters)84 private ExecuteAppFunctionRequest( 85 @NonNull String targetPackageName, 86 @NonNull String functionIdentifier, 87 @NonNull Bundle extras, 88 @NonNull GenericDocumentWrapper parameters) { 89 mTargetPackageName = Objects.requireNonNull(targetPackageName); 90 mFunctionIdentifier = Objects.requireNonNull(functionIdentifier); 91 mExtras = Objects.requireNonNull(extras); 92 mParameters = Objects.requireNonNull(parameters); 93 } 94 95 /** Returns the package name of the app that hosts the function. */ 96 @NonNull getTargetPackageName()97 public String getTargetPackageName() { 98 return mTargetPackageName; 99 } 100 101 /** 102 * Returns the unique string identifier of the app function to be executed. 103 * 104 * <p>When there is a package change or the device starts up, the metadata of available 105 * functions is indexed by AppSearch. AppSearch stores the indexed information as {@code 106 * AppFunctionStaticMetadata} document. 107 * 108 * <p>The ID can be obtained by querying the {@code AppFunctionStaticMetadata} documents from 109 * AppSearch. 110 * 111 * <p>If the {@code functionId} provided is invalid, the caller will get an invalid argument 112 * response. 113 */ 114 @NonNull getFunctionIdentifier()115 public String getFunctionIdentifier() { 116 return mFunctionIdentifier; 117 } 118 119 /** 120 * Returns the function parameters. The key is the parameter name, and the value is the 121 * parameter value. 122 * 123 * <p>The {@link GenericDocument} may have missing parameters. Developers are advised to 124 * implement defensive handling measures. 125 * 126 * @see AppFunctionManager on how to determine the expected parameters. 127 */ 128 @NonNull getParameters()129 public GenericDocument getParameters() { 130 return mParameters.getValue(); 131 } 132 133 /** Returns the additional metadata for this function execution request. */ 134 @NonNull getExtras()135 public Bundle getExtras() { 136 return mExtras; 137 } 138 139 /** 140 * Returns the size of the request in bytes. 141 * 142 * @hide 143 */ getRequestDataSize()144 public int getRequestDataSize() { 145 return mTargetPackageName.getBytes().length + mFunctionIdentifier.getBytes().length 146 + mParameters.getDataSize() + mExtras.getSize(); 147 } 148 149 @Override writeToParcel(@onNull Parcel dest, int flags)150 public void writeToParcel(@NonNull Parcel dest, int flags) { 151 dest.writeString8(mTargetPackageName); 152 dest.writeString8(mFunctionIdentifier); 153 mParameters.writeToParcel(dest, flags); 154 dest.writeBundle(mExtras); 155 } 156 157 @Override describeContents()158 public int describeContents() { 159 return 0; 160 } 161 162 /** Builder for {@link ExecuteAppFunctionRequest}. */ 163 public static final class Builder { 164 @NonNull private final String mTargetPackageName; 165 @NonNull private final String mFunctionIdentifier; 166 @NonNull private Bundle mExtras = Bundle.EMPTY; 167 168 @NonNull 169 private GenericDocument mParameters = new GenericDocument.Builder<>("", "", "").build(); 170 171 /** 172 * Creates a new instance of this builder class. 173 * 174 * @param targetPackageName The package name of the target app providing the app function to 175 * invoke. 176 * @param functionIdentifier The identifier used by the {@link AppFunctionService} from the 177 * target app to uniquely identify the function to be invoked. 178 */ Builder(@onNull String targetPackageName, @NonNull String functionIdentifier)179 public Builder(@NonNull String targetPackageName, @NonNull String functionIdentifier) { 180 mTargetPackageName = Objects.requireNonNull(targetPackageName); 181 mFunctionIdentifier = Objects.requireNonNull(functionIdentifier); 182 } 183 184 /** Sets the additional metadata for this function execution request. */ 185 @NonNull setExtras(@onNull Bundle extras)186 public Builder setExtras(@NonNull Bundle extras) { 187 mExtras = Objects.requireNonNull(extras); 188 return this; 189 } 190 191 /** 192 * Sets the function parameters. 193 * 194 * @see #ExecuteAppFunctionRequest#getParameters() 195 */ 196 @NonNull setParameters(@onNull GenericDocument parameters)197 public Builder setParameters(@NonNull GenericDocument parameters) { 198 Objects.requireNonNull(parameters); 199 mParameters = parameters; 200 return this; 201 } 202 203 /** Builds the {@link ExecuteAppFunctionRequest}. */ 204 @NonNull build()205 public ExecuteAppFunctionRequest build() { 206 return new ExecuteAppFunctionRequest( 207 mTargetPackageName, 208 mFunctionIdentifier, 209 mExtras, 210 new GenericDocumentWrapper(mParameters)); 211 } 212 } 213 } 214