Loading core/api/current.txt +2 −7 Original line number Diff line number Diff line Loading @@ -8756,6 +8756,8 @@ package android.app.appfunctions { method public int getResultCode(); method @NonNull public android.app.appsearch.GenericDocument getResultDocument(); method public boolean isSuccess(); method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @NonNull public static android.app.appfunctions.ExecuteAppFunctionResponse newFailure(int, @Nullable String, @Nullable android.os.Bundle); method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @NonNull public static android.app.appfunctions.ExecuteAppFunctionResponse newSuccess(@NonNull android.app.appsearch.GenericDocument, @Nullable android.os.Bundle); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.appfunctions.ExecuteAppFunctionResponse> CREATOR; field public static final String PROPERTY_RETURN_VALUE = "returnValue"; Loading @@ -8767,13 +8769,6 @@ package android.app.appfunctions { field public static final int RESULT_TIMED_OUT = 5; // 0x5 } @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final class ExecuteAppFunctionResponse.Builder { ctor public ExecuteAppFunctionResponse.Builder(@NonNull android.app.appsearch.GenericDocument); ctor public ExecuteAppFunctionResponse.Builder(int, @NonNull String); method @NonNull public android.app.appfunctions.ExecuteAppFunctionResponse build(); method @NonNull public android.app.appfunctions.ExecuteAppFunctionResponse.Builder setExtras(@NonNull android.os.Bundle); } } package android.app.assist { core/java/android/app/appfunctions/AppFunctionManager.java +3 −4 Original line number Diff line number Diff line Loading @@ -51,7 +51,6 @@ public final class AppFunctionManager { * * @param mService An interface to the backing service. * @param context A {@link Context}. * * @hide */ public AppFunctionManager(IAppFunctionManager service, Context context) { Loading Loading @@ -108,8 +107,8 @@ public final class AppFunctionManager { } catch (RuntimeException e) { // Ideally shouldn't happen since errors are wrapped into the // response, but we catch it here for additional safety. callback.accept(new ExecuteAppFunctionResponse.Builder( getResultCode(e), e.getMessage()).build()); callback.accept(ExecuteAppFunctionResponse.newFailure( getResultCode(e), e.getMessage(), /*extras=*/ null)); } } }); Loading core/java/android/app/appfunctions/AppFunctionService.java +3 −6 Original line number Diff line number Diff line Loading @@ -81,8 +81,9 @@ public abstract class AppFunctionService extends Service { // Apps should handle exceptions. But if they don't, report the error on // behalf of them. safeCallback.onResult( new ExecuteAppFunctionResponse.Builder( getResultCode(ex), getExceptionMessage(ex)).build()); ExecuteAppFunctionResponse.newFailure( getResultCode(ex), ex.getMessage(), /*extras=*/ null)); } } }; Loading Loading @@ -117,8 +118,4 @@ public abstract class AppFunctionService extends Service { public abstract void onExecuteFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull Consumer<ExecuteAppFunctionResponse> callback); private String getExceptionMessage(Exception exception) { return exception.getMessage() == null ? "" : exception.getMessage(); } } core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java +49 −60 Original line number Diff line number Diff line Loading @@ -161,6 +161,55 @@ public final class ExecuteAppFunctionResponse implements Parcelable { return ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR; } /** * Returns a successful response. * * @param resultDocument The return value of the executed function. * @param extras The additional metadata data relevant to this function execution * response. */ @NonNull @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) public static ExecuteAppFunctionResponse newSuccess(@NonNull GenericDocument resultDocument, @Nullable Bundle extras) { Objects.requireNonNull(resultDocument); Bundle actualExtras = getActualExtras(extras); GenericDocumentWrapper resultDocumentWrapper = new GenericDocumentWrapper(resultDocument); return new ExecuteAppFunctionResponse( resultDocumentWrapper, actualExtras, RESULT_OK, /*errorMessage=*/null); } /** * Returns a failure response. * * @param resultCode The result code of the app function execution. * @param extras The additional metadata data relevant to this function execution * response. * @param errorMessage The error message associated with the result, if any. */ @NonNull @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) public static ExecuteAppFunctionResponse newFailure(@ResultCode int resultCode, @Nullable String errorMessage, @Nullable Bundle extras) { if (resultCode == RESULT_OK) { throw new IllegalArgumentException("resultCode must not be RESULT_OK"); } Bundle actualExtras = getActualExtras(extras); GenericDocumentWrapper emptyWrapper = new GenericDocumentWrapper( new GenericDocument.Builder<>("", "", "").build()); return new ExecuteAppFunctionResponse( emptyWrapper, actualExtras, resultCode, errorMessage); } private static Bundle getActualExtras(@Nullable Bundle extras) { if (extras == null) { return Bundle.EMPTY; } return extras; } /** * Returns a generic document containing the return value of the executed function. * Loading Loading @@ -250,64 +299,4 @@ public final class ExecuteAppFunctionResponse implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface ResultCode { } /** * The builder for creating {@link ExecuteAppFunctionResponse} instances. */ @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) public static final class Builder { @NonNull private GenericDocument mResultDocument = new GenericDocument.Builder<>("", "", "").build(); @NonNull private Bundle mExtras = Bundle.EMPTY; private int mResultCode; @Nullable private String mErrorMessage; /** * Creates a new builder for {@link ExecuteAppFunctionResponse}. */ private Builder() { } /** * Creates a new builder for {@link ExecuteAppFunctionResponse} to build a success response * with a result code of {@link #RESULT_OK} and a resultDocument. */ public Builder(@NonNull GenericDocument resultDocument) { Objects.requireNonNull(resultDocument); mResultDocument = resultDocument; mResultCode = RESULT_OK; } /** * Creates a new builder for {@link ExecuteAppFunctionResponse} to build an error response * with a result code and an error message. */ public Builder(@ResultCode int resultCode, @NonNull String errorMessage) { mResultCode = resultCode; mErrorMessage = Objects.requireNonNull(errorMessage); } /** * Sets the extras of the app function execution. */ @NonNull public Builder setExtras(@NonNull Bundle extras) { mExtras = Objects.requireNonNull(extras); return this; } /** * Builds the {@link ExecuteAppFunctionResponse} instance. */ @NonNull public ExecuteAppFunctionResponse build() { return new ExecuteAppFunctionResponse( new GenericDocumentWrapper(mResultDocument), mExtras, mResultCode, mErrorMessage); } } } services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +36 −32 Original line number Diff line number Diff line Loading @@ -94,36 +94,39 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { targetUser = mCallerValidator.verifyTargetUserHandle( requestInternal.getUserHandle(), validatedCallingPackage); } catch (SecurityException exception) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse .Builder(ExecuteAppFunctionResponse.RESULT_DENIED, getExceptionMessage(exception)).build()); safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse .newFailure(ExecuteAppFunctionResponse.RESULT_DENIED, exception.getMessage(), /*extras=*/ null)); return; } // TODO(b/354956319): Add and honor the new enterprise policies. if (mCallerValidator.isUserOrganizationManaged(targetUser)) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder( safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR, "Cannot run on a device with a device owner or from the managed profile." ).build()); "Cannot run on a device with a device owner or from the managed profile.", /*extras=*/ null )); return; } String targetPackageName = requestInternal.getClientRequest().getTargetPackageName(); if (TextUtils.isEmpty(targetPackageName)) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder( safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT, "Target package name cannot be empty." ).build()); "Target package name cannot be empty.", /*extras=*/ null )); return; } if (!mCallerValidator.verifyCallerCanExecuteAppFunction( validatedCallingPackage, targetPackageName)) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse .Builder(ExecuteAppFunctionResponse.RESULT_DENIED, "Caller does not have permission to execute the appfunction") .build()); safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse .newFailure(ExecuteAppFunctionResponse.RESULT_DENIED, "Caller does not have permission to execute the appfunction", /*extras=*/ null)); return; } Loading @@ -131,10 +134,11 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { targetPackageName, targetUser); if (serviceIntent == null) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder( safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR, "Cannot find the target service." ).build()); "Cannot find the target service.", /*extras=*/ null )); return; } bindAppFunctionServiceUnchecked(requestInternal, serviceIntent, targetUser, Loading Loading @@ -171,9 +175,10 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { } ); } catch (Exception e) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse .Builder(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR, getExceptionMessage(e)).build()); safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse .newFailure(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR, e.getMessage(), /*extras=*/ null)); serviceUsageCompleteListener.onCompleted(); } } Loading @@ -181,33 +186,32 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { @Override public void onFailedToConnect() { Slog.e(TAG, "Failed to connect to service"); safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse .Builder(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR, "Failed to connect to AppFunctionService").build()); safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse .newFailure(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR, "Failed to connect to AppFunctionService", /*extras=*/ null)); } @Override public void onTimedOut() { Slog.e(TAG, "Timed out"); safeExecuteAppFunctionCallback.onResult( new ExecuteAppFunctionResponse.Builder( ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_TIMED_OUT, "Binding to AppFunctionService timed out." ).build()); "Binding to AppFunctionService timed out.", /*extras=*/ null )); } } ); if (!bindServiceResult) { Slog.e(TAG, "Failed to bind to the AppFunctionService"); safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder( safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_TIMED_OUT, "Failed to bind the AppFunctionService." ).build()); "Failed to bind the AppFunctionService.", /*extras=*/ null )); } } private String getExceptionMessage(Exception exception) { return exception.getMessage() == null ? "" : exception.getMessage(); } } Loading
core/api/current.txt +2 −7 Original line number Diff line number Diff line Loading @@ -8756,6 +8756,8 @@ package android.app.appfunctions { method public int getResultCode(); method @NonNull public android.app.appsearch.GenericDocument getResultDocument(); method public boolean isSuccess(); method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @NonNull public static android.app.appfunctions.ExecuteAppFunctionResponse newFailure(int, @Nullable String, @Nullable android.os.Bundle); method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @NonNull public static android.app.appfunctions.ExecuteAppFunctionResponse newSuccess(@NonNull android.app.appsearch.GenericDocument, @Nullable android.os.Bundle); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.appfunctions.ExecuteAppFunctionResponse> CREATOR; field public static final String PROPERTY_RETURN_VALUE = "returnValue"; Loading @@ -8767,13 +8769,6 @@ package android.app.appfunctions { field public static final int RESULT_TIMED_OUT = 5; // 0x5 } @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final class ExecuteAppFunctionResponse.Builder { ctor public ExecuteAppFunctionResponse.Builder(@NonNull android.app.appsearch.GenericDocument); ctor public ExecuteAppFunctionResponse.Builder(int, @NonNull String); method @NonNull public android.app.appfunctions.ExecuteAppFunctionResponse build(); method @NonNull public android.app.appfunctions.ExecuteAppFunctionResponse.Builder setExtras(@NonNull android.os.Bundle); } } package android.app.assist {
core/java/android/app/appfunctions/AppFunctionManager.java +3 −4 Original line number Diff line number Diff line Loading @@ -51,7 +51,6 @@ public final class AppFunctionManager { * * @param mService An interface to the backing service. * @param context A {@link Context}. * * @hide */ public AppFunctionManager(IAppFunctionManager service, Context context) { Loading Loading @@ -108,8 +107,8 @@ public final class AppFunctionManager { } catch (RuntimeException e) { // Ideally shouldn't happen since errors are wrapped into the // response, but we catch it here for additional safety. callback.accept(new ExecuteAppFunctionResponse.Builder( getResultCode(e), e.getMessage()).build()); callback.accept(ExecuteAppFunctionResponse.newFailure( getResultCode(e), e.getMessage(), /*extras=*/ null)); } } }); Loading
core/java/android/app/appfunctions/AppFunctionService.java +3 −6 Original line number Diff line number Diff line Loading @@ -81,8 +81,9 @@ public abstract class AppFunctionService extends Service { // Apps should handle exceptions. But if they don't, report the error on // behalf of them. safeCallback.onResult( new ExecuteAppFunctionResponse.Builder( getResultCode(ex), getExceptionMessage(ex)).build()); ExecuteAppFunctionResponse.newFailure( getResultCode(ex), ex.getMessage(), /*extras=*/ null)); } } }; Loading Loading @@ -117,8 +118,4 @@ public abstract class AppFunctionService extends Service { public abstract void onExecuteFunction( @NonNull ExecuteAppFunctionRequest request, @NonNull Consumer<ExecuteAppFunctionResponse> callback); private String getExceptionMessage(Exception exception) { return exception.getMessage() == null ? "" : exception.getMessage(); } }
core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java +49 −60 Original line number Diff line number Diff line Loading @@ -161,6 +161,55 @@ public final class ExecuteAppFunctionResponse implements Parcelable { return ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR; } /** * Returns a successful response. * * @param resultDocument The return value of the executed function. * @param extras The additional metadata data relevant to this function execution * response. */ @NonNull @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) public static ExecuteAppFunctionResponse newSuccess(@NonNull GenericDocument resultDocument, @Nullable Bundle extras) { Objects.requireNonNull(resultDocument); Bundle actualExtras = getActualExtras(extras); GenericDocumentWrapper resultDocumentWrapper = new GenericDocumentWrapper(resultDocument); return new ExecuteAppFunctionResponse( resultDocumentWrapper, actualExtras, RESULT_OK, /*errorMessage=*/null); } /** * Returns a failure response. * * @param resultCode The result code of the app function execution. * @param extras The additional metadata data relevant to this function execution * response. * @param errorMessage The error message associated with the result, if any. */ @NonNull @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) public static ExecuteAppFunctionResponse newFailure(@ResultCode int resultCode, @Nullable String errorMessage, @Nullable Bundle extras) { if (resultCode == RESULT_OK) { throw new IllegalArgumentException("resultCode must not be RESULT_OK"); } Bundle actualExtras = getActualExtras(extras); GenericDocumentWrapper emptyWrapper = new GenericDocumentWrapper( new GenericDocument.Builder<>("", "", "").build()); return new ExecuteAppFunctionResponse( emptyWrapper, actualExtras, resultCode, errorMessage); } private static Bundle getActualExtras(@Nullable Bundle extras) { if (extras == null) { return Bundle.EMPTY; } return extras; } /** * Returns a generic document containing the return value of the executed function. * Loading Loading @@ -250,64 +299,4 @@ public final class ExecuteAppFunctionResponse implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface ResultCode { } /** * The builder for creating {@link ExecuteAppFunctionResponse} instances. */ @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) public static final class Builder { @NonNull private GenericDocument mResultDocument = new GenericDocument.Builder<>("", "", "").build(); @NonNull private Bundle mExtras = Bundle.EMPTY; private int mResultCode; @Nullable private String mErrorMessage; /** * Creates a new builder for {@link ExecuteAppFunctionResponse}. */ private Builder() { } /** * Creates a new builder for {@link ExecuteAppFunctionResponse} to build a success response * with a result code of {@link #RESULT_OK} and a resultDocument. */ public Builder(@NonNull GenericDocument resultDocument) { Objects.requireNonNull(resultDocument); mResultDocument = resultDocument; mResultCode = RESULT_OK; } /** * Creates a new builder for {@link ExecuteAppFunctionResponse} to build an error response * with a result code and an error message. */ public Builder(@ResultCode int resultCode, @NonNull String errorMessage) { mResultCode = resultCode; mErrorMessage = Objects.requireNonNull(errorMessage); } /** * Sets the extras of the app function execution. */ @NonNull public Builder setExtras(@NonNull Bundle extras) { mExtras = Objects.requireNonNull(extras); return this; } /** * Builds the {@link ExecuteAppFunctionResponse} instance. */ @NonNull public ExecuteAppFunctionResponse build() { return new ExecuteAppFunctionResponse( new GenericDocumentWrapper(mResultDocument), mExtras, mResultCode, mErrorMessage); } } }
services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +36 −32 Original line number Diff line number Diff line Loading @@ -94,36 +94,39 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { targetUser = mCallerValidator.verifyTargetUserHandle( requestInternal.getUserHandle(), validatedCallingPackage); } catch (SecurityException exception) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse .Builder(ExecuteAppFunctionResponse.RESULT_DENIED, getExceptionMessage(exception)).build()); safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse .newFailure(ExecuteAppFunctionResponse.RESULT_DENIED, exception.getMessage(), /*extras=*/ null)); return; } // TODO(b/354956319): Add and honor the new enterprise policies. if (mCallerValidator.isUserOrganizationManaged(targetUser)) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder( safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR, "Cannot run on a device with a device owner or from the managed profile." ).build()); "Cannot run on a device with a device owner or from the managed profile.", /*extras=*/ null )); return; } String targetPackageName = requestInternal.getClientRequest().getTargetPackageName(); if (TextUtils.isEmpty(targetPackageName)) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder( safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT, "Target package name cannot be empty." ).build()); "Target package name cannot be empty.", /*extras=*/ null )); return; } if (!mCallerValidator.verifyCallerCanExecuteAppFunction( validatedCallingPackage, targetPackageName)) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse .Builder(ExecuteAppFunctionResponse.RESULT_DENIED, "Caller does not have permission to execute the appfunction") .build()); safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse .newFailure(ExecuteAppFunctionResponse.RESULT_DENIED, "Caller does not have permission to execute the appfunction", /*extras=*/ null)); return; } Loading @@ -131,10 +134,11 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { targetPackageName, targetUser); if (serviceIntent == null) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder( safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR, "Cannot find the target service." ).build()); "Cannot find the target service.", /*extras=*/ null )); return; } bindAppFunctionServiceUnchecked(requestInternal, serviceIntent, targetUser, Loading Loading @@ -171,9 +175,10 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { } ); } catch (Exception e) { safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse .Builder(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR, getExceptionMessage(e)).build()); safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse .newFailure(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR, e.getMessage(), /*extras=*/ null)); serviceUsageCompleteListener.onCompleted(); } } Loading @@ -181,33 +186,32 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { @Override public void onFailedToConnect() { Slog.e(TAG, "Failed to connect to service"); safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse .Builder(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR, "Failed to connect to AppFunctionService").build()); safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse .newFailure(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR, "Failed to connect to AppFunctionService", /*extras=*/ null)); } @Override public void onTimedOut() { Slog.e(TAG, "Timed out"); safeExecuteAppFunctionCallback.onResult( new ExecuteAppFunctionResponse.Builder( ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_TIMED_OUT, "Binding to AppFunctionService timed out." ).build()); "Binding to AppFunctionService timed out.", /*extras=*/ null )); } } ); if (!bindServiceResult) { Slog.e(TAG, "Failed to bind to the AppFunctionService"); safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder( safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure( ExecuteAppFunctionResponse.RESULT_TIMED_OUT, "Failed to bind the AppFunctionService." ).build()); "Failed to bind the AppFunctionService.", /*extras=*/ null )); } } private String getExceptionMessage(Exception exception) { return exception.getMessage() == null ? "" : exception.getMessage(); } }