1 /* 2 * Copyright 2025 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 androidx.appfunctions 18 19 import android.os.Bundle 20 import androidx.annotation.IntDef 21 import androidx.annotation.RestrictTo 22 23 /** 24 * An exception that is thrown when an error occurs during an app function execution. 25 * 26 * This exception can be used by the app to report errors to the caller. 27 */ 28 public abstract class AppFunctionException 29 internal constructor( 30 /** The error code. */ 31 @ErrorCode internal val internalErrorCode: Int, 32 /** The error message. */ 33 public val errorMessage: String?, 34 internal val extras: Bundle 35 ) : Exception(errorMessage) { 36 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) toPlatformExtensionsClassnull37 public fun toPlatformExtensionsClass(): 38 com.android.extensions.appfunctions.AppFunctionException { 39 return com.android.extensions.appfunctions.AppFunctionException( 40 internalErrorCode, 41 errorMessage, 42 extras 43 ) 44 } 45 46 /** 47 * Returns the error category. 48 * 49 * This method categorizes errors based on their underlying cause, allowing developers to 50 * implement targeted error handling and provide more informative error messages to users. It 51 * maps ranges of error codes to specific error categories. 52 * 53 * This method returns [ERROR_CATEGORY_UNKNOWN] if the error code does not belong to any error 54 * category. 55 */ 56 @ErrorCategory 57 internal val errorCategory: Int = 58 when (internalErrorCode) { 59 in 1000..1999 -> ERROR_CATEGORY_REQUEST_ERROR 60 in 2000..2999 -> ERROR_CATEGORY_SYSTEM 61 in 3000..3999 -> ERROR_CATEGORY_APP 62 else -> ERROR_CATEGORY_UNKNOWN 63 } 64 65 @IntDef( 66 value = 67 [ 68 ERROR_CATEGORY_UNKNOWN, 69 ERROR_CATEGORY_REQUEST_ERROR, 70 ERROR_CATEGORY_APP, 71 ERROR_CATEGORY_SYSTEM, 72 ] 73 ) 74 internal annotation class ErrorCategory 75 76 @IntDef( 77 value = 78 [ 79 ERROR_DENIED, 80 ERROR_INVALID_ARGUMENT, 81 ERROR_DISABLED, 82 ERROR_FUNCTION_NOT_FOUND, 83 ERROR_RESOURCE_NOT_FOUND, 84 ERROR_LIMIT_EXCEEDED, 85 ERROR_RESOURCE_ALREADY_EXISTS, 86 ERROR_SYSTEM_ERROR, 87 ERROR_CANCELLED, 88 ERROR_APP_UNKNOWN_ERROR, 89 ERROR_PERMISSION_REQUIRED, 90 ERROR_NOT_SUPPORTED, 91 ] 92 ) 93 internal annotation class ErrorCode 94 95 public companion object { 96 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 97 @SuppressWarnings("WrongConstant") fromPlatformExtensionsClassnull98 public fun fromPlatformExtensionsClass( 99 exception: com.android.extensions.appfunctions.AppFunctionException 100 ): AppFunctionException { 101 return when (exception.errorCode) { 102 ERROR_DENIED -> AppFunctionDeniedException(exception.errorMessage, exception.extras) 103 ERROR_INVALID_ARGUMENT -> 104 AppFunctionInvalidArgumentException(exception.errorMessage, exception.extras) 105 ERROR_DISABLED -> 106 AppFunctionDisabledException(exception.errorMessage, exception.extras) 107 ERROR_FUNCTION_NOT_FOUND -> 108 AppFunctionFunctionNotFoundException(exception.errorMessage, exception.extras) 109 ERROR_RESOURCE_NOT_FOUND -> 110 AppFunctionElementNotFoundException(exception.errorMessage, exception.extras) 111 ERROR_LIMIT_EXCEEDED -> 112 AppFunctionLimitExceededException(exception.errorMessage, exception.extras) 113 ERROR_RESOURCE_ALREADY_EXISTS -> 114 AppFunctionElementAlreadyExistsException( 115 exception.errorMessage, 116 exception.extras 117 ) 118 ERROR_SYSTEM_ERROR -> 119 AppFunctionSystemUnknownException(exception.errorMessage, exception.extras) 120 ERROR_CANCELLED -> 121 AppFunctionCancelledException(exception.errorMessage, exception.extras) 122 ERROR_APP_UNKNOWN_ERROR -> 123 AppFunctionAppUnknownException(exception.errorMessage, exception.extras) 124 ERROR_PERMISSION_REQUIRED -> 125 AppFunctionPermissionRequiredException(exception.errorMessage, exception.extras) 126 ERROR_NOT_SUPPORTED -> 127 AppFunctionNotSupportedException(exception.errorMessage, exception.extras) 128 else -> 129 AppFunctionUnknownException( 130 exception.errorCode, 131 exception.errorMessage, 132 exception.extras, 133 ) 134 } 135 } 136 137 // Error categories 138 /** The error category is unknown. */ 139 internal const val ERROR_CATEGORY_UNKNOWN: Int = 0 140 141 /** 142 * The error is caused by the app requesting a function execution. 143 * 144 * For example, the caller provided invalid parameters in the execution request e.g. an 145 * invalid function ID. 146 * 147 * Errors in the category fall in the range 1000-1999 inclusive. 148 */ 149 internal const val ERROR_CATEGORY_REQUEST_ERROR: Int = 1 150 151 /** 152 * The error is caused by an issue in the system. 153 * 154 * For example, the AppFunctionService implementation is not found by the system. 155 * 156 * Errors in the category fall in the range 2000-2999 inclusive. 157 */ 158 internal const val ERROR_CATEGORY_SYSTEM: Int = 2 159 160 /** 161 * The error is caused by the app providing the function. 162 * 163 * For example, the app crashed when the system is executing the request. 164 * 165 * Errors in the category fall in the range 3000-3999 inclusive. 166 */ 167 internal const val ERROR_CATEGORY_APP: Int = 3 168 169 // Error codes 170 /** 171 * The caller does not have the permission to execute an app function. 172 * 173 * This is different from [ERROR_PERMISSION_REQUIRED] in that the caller is missing this 174 * specific permission, as opposed to the target app missing a permission. 175 * 176 * This error is in the [ERROR_CATEGORY_REQUEST_ERROR] category. 177 */ 178 internal const val ERROR_DENIED: Int = 1000 179 180 /** 181 * The caller supplied invalid arguments to the execution request. 182 * 183 * This error may be considered similar to [IllegalArgumentException]. 184 * 185 * This error is in the [ERROR_CATEGORY_REQUEST_ERROR] category. 186 */ 187 internal const val ERROR_INVALID_ARGUMENT: Int = 1001 188 189 /** 190 * The caller tried to execute a disabled app function. 191 * 192 * This error is in the [ERROR_CATEGORY_REQUEST_ERROR] category. 193 */ 194 internal const val ERROR_DISABLED: Int = 1002 195 196 /** 197 * The caller tried to execute a function that does not exist. 198 * 199 * This error is in the [ERROR_CATEGORY_REQUEST_ERROR] category. 200 */ 201 internal const val ERROR_FUNCTION_NOT_FOUND: Int = 1003 202 203 // SDK-defined error codes in the [ERROR_CATEGORY_REQUEST_ERROR] category start from 1500. 204 /** 205 * The caller tried to request a resource/entity that does not exist. 206 * 207 * This error is in the [ERROR_CATEGORY_REQUEST_ERROR] category. 208 */ 209 internal const val ERROR_RESOURCE_NOT_FOUND: Int = 1500 210 211 /** 212 * The caller exceeded the allowed request rate. 213 * 214 * This error is in the [ERROR_CATEGORY_REQUEST_ERROR] category. 215 */ 216 internal const val ERROR_LIMIT_EXCEEDED: Int = 1501 217 218 /** 219 * The caller tried to create a resource/entity that already exists or has conflicts with 220 * existing resource/entity. 221 * 222 * This error is in the [ERROR_CATEGORY_REQUEST_ERROR] category. 223 */ 224 internal const val ERROR_RESOURCE_ALREADY_EXISTS: Int = 1502 225 226 /** 227 * An internal unexpected error coming from the system. 228 * 229 * This error is in the [ERROR_CATEGORY_SYSTEM] category. 230 */ 231 internal const val ERROR_SYSTEM_ERROR: Int = 2000 232 233 /** 234 * The operation was cancelled. Use this error code to report that a cancellation is done 235 * after receiving a cancellation signal. 236 * 237 * This error is in the [ERROR_CATEGORY_SYSTEM] category. 238 */ 239 internal const val ERROR_CANCELLED: Int = 2001 240 241 /** 242 * An unknown error occurred while processing the call in the AppFunctionService. 243 * 244 * This error is thrown when the service is connected in the remote application but an 245 * unexpected error is thrown from the bound application. 246 * 247 * This error is in the [ERROR_CATEGORY_APP] category. 248 */ 249 internal const val ERROR_APP_UNKNOWN_ERROR: Int = 3000 250 251 // SDK-defined error codes in the [ERROR_CATEGORY_APP] category start from 3500. 252 /** 253 * Indicates the app lacks the necessary permission to fulfill the request. 254 * 255 * This occurs when the app attempts an operation requiring user-granted permission that has 256 * not been provided. For example, creating a calendar event requires access to the calendar 257 * content. If the user hasn't granted this permission, this error should be thrown. 258 * 259 * This is different from [ERROR_DENIED] in that the required permission is missing from the 260 * target app, as opposed to the caller. 261 * 262 * This error is in the [ERROR_CATEGORY_APP] category. 263 */ 264 internal const val ERROR_PERMISSION_REQUIRED: Int = 3500 265 266 /** 267 * Indicates the action is not supported by the app. 268 * 269 * This error occurs when an app receives a request to perform an unsupported action. For 270 * example, a clock app might support updating timer properties such as label but may not 271 * allow updating the timer's duration once the timer has already started. 272 * 273 * This error is in the [ERROR_CATEGORY_APP] category. 274 */ 275 internal const val ERROR_NOT_SUPPORTED: Int = 3501 276 } 277 } 278 279 /** 280 * Thrown when an unknown error has occurred. 281 * 282 * This Exception is used when the error doesn't belong to any other AppFunctionException. This may 283 * happen due to version skews in the error codes between the platform and the sdk. E.g. if the app 284 * is running on a newer platform version (with a new error code) and an older sdk. 285 * 286 * Note that this is different from [AppFunctionAppUnknownException], in that the error wasn't 287 * necessarily caused by the app. 288 */ 289 public class AppFunctionUnknownException 290 internal constructor(public val errorCode: Int, errorMessage: String? = null, extras: Bundle) : 291 AppFunctionException(errorCode, errorMessage, extras) { 292 /** 293 * Create an [AppFunctionUnknownException]. 294 * 295 * @param errorCode The error code. 296 * @param errorMessage The error message. 297 */ 298 public constructor( 299 errorCode: Int, 300 errorMessage: String? = null 301 ) : this(errorCode, errorMessage, Bundle.EMPTY) 302 } 303