1 /* 2 * Copyright 2023 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 com.google.android.iwlan; 18 19 import android.content.Context; 20 import android.os.PersistableBundle; 21 import android.support.annotation.NonNull; 22 import android.telephony.CarrierConfigManager; 23 24 import androidx.annotation.VisibleForTesting; 25 26 /** Class for handling IWLAN carrier configuration. */ 27 public class IwlanCarrierConfig { 28 static final String PREFIX = "iwlan."; 29 30 /** 31 * Key for setting the delay in seconds to release the IWLAN connection after a handover to 32 * WWAN. Refer to {@link #DEFAULT_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT} for the default 33 * value. 34 */ 35 public static final String KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT = 36 PREFIX + "handover_to_wwan_release_delay_second_int"; 37 38 /** 39 * Key to exclude IKE N1_MODE_CAPABILITY Notify payload during emergency session setup without 40 * affecting normal sessions. See {@link #DEFAULT_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL} 41 * for the default value. 42 */ 43 public static final String KEY_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL = 44 PREFIX + "n1_mode_exclusion_for_emergency_session_bool"; 45 46 /** 47 * Key to decide whether N1 mode shall be enabled or disabled depending on 5G enabling status 48 * via the UI/UX. See {@link #DEFAULT_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL} for the default value. 49 */ 50 public static final String KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL = 51 PREFIX + "update_n1_mode_on_ui_change_bool"; 52 53 /** 54 * Boolean indicating if distinct ePDG selection for emergency sessions is enabled. Refer to 55 * {@link #DEFAULT_DISTINCT_EPDG_FOR_EMERGENCY_ALLOWED_BOOL} for the default value. 56 */ 57 public static final String KEY_DISTINCT_EPDG_FOR_EMERGENCY_ALLOWED_BOOL = 58 PREFIX + "distinct_epdg_for_emergency_allowed_bool"; 59 60 /** 61 * Key to control whether the UE includes the IKE DEVICE_IDENTITY Notify payload when receiving 62 * a request. See {@link #DEFAULT_IKE_DEVICE_IDENTITY_SUPPORTED_BOOL} for the default value. 63 */ 64 public static final String KEY_IKE_DEVICE_IDENTITY_SUPPORTED_BOOL = 65 PREFIX + "ike_device_identity_supported_bool"; 66 67 /** 68 * Boolean indicating if reordering ike SA transforms enabled. Refer to 69 * {@link #DEFAULT_IKE_SA_TRANSFORMS_REORDER_BOOL} for the default value. 70 */ 71 public static final String KEY_IKE_SA_TRANSFORMS_REORDER_BOOL = 72 PREFIX + "ike_sa_transforms_reorder_bool"; 73 74 /** 75 * IWLAN error policy configs that determine the behavior when error happens during ePDG tunnel 76 * setup. Refer to {@link #DEFAULT_ERROR_POLICY_CONFIG_STRING} for the default value. 77 * 78 * <p>The Error Config is defined as an Array of APNs identified by "ApnName". Other than Apn 79 * names this can also have "*" value which represents that this can be used as a generic 80 * fallback when no other policy matches. 81 * 82 * <p>Each APN associated with "ApnName" has an array of "ErrorTypes". Where each element in 83 * "ErrorTypes" array defines the config for the Error. The element in "ErrorTypes" array has 84 * the following items: 85 * 86 * <ul> 87 * <li>"ErrorType": The type of error in String. Possible error types are: 88 * <ol> 89 * <li>"IKE_PROTOCOL_ERROR_TYPE" refers to the Notify Error coming in Notify payload. 90 * See https://tools.ietf.org/html/rfc4306#section-3.10.1 for global errors and 91 * carrier specific requirements for other carrier specific error codes. 92 * <li>"GENERIC_ERROR_TYPE" refers to the following IWLAN errors - "IO_EXCEPTION", 93 * "TIMEOUT_EXCEPTION", "SERVER_SELECTION_FAILED" and "TUNNEL_TRANSFORM_FAILED". 94 * <li>"*" represents that this policy is a generic fallback when no other policy 95 * matches. 96 * </ol> 97 * <li>"ErrorDetails": Array of errors specifics for which the policy needs to be applied to. 98 * Note: Array can be a mix of numbers, ranges and string formats. Following are the 99 * currently supported formats of elements in the array: 100 * <ol> 101 * <li>Number or Code: "24" - Number specific to the error. 102 * <li>Range: "9000-9050" - Range of specific errors. 103 * <li>Any: "*" value represents that this can be applied to all ErrorDetails when there 104 * is no specific match. This will be a single element array. 105 * <li>String: String describing the specific error. Current allowed string values - 106 * "IO_EXCEPTION", "TIMEOUT_EXCEPTION", "SERVER_SELECTION_FAILED" and 107 * "TUNNEL_TRANSFORM_FAILED" 108 * </ol> 109 * <p>"IKE_PROTOCOL_EXCEPTION" ErrorType expects the "error_detail" to be defined only in 110 * numbers or range of numbers. Examples: ["24"] or ["9000-9050"] or ["7", "14000-14050"] 111 * <p>"GENERIC_ERROR_TYPE" or "*" ErrorType expects only the following to be in 112 * "ErrorDetails" - "IO_EXCEPTION", "TIMEOUT_EXCEPTION", "SERVER_SELECTION_FAILED", 113 * "TUNNEL_TRANSFORM_FAILED" and "*". Examples: ["IO_EXCEPTION", "TIMEOUT_EXCEPTION"] or 114 * ["*"] 115 * <li>"RetryArray": Array of retry times (in secs) represented in string format. Following 116 * formats are currently supported: 117 * <ol> 118 * <li>["0","0", "0"] Retry immediately for maximum 3 times and then fail. 119 * <li>[] Empty array means to fail whenever the error happens. 120 * <li>["2", "4", "8"] Retry times are 2 secs, 4secs and 8 secs - fail after that. 121 * <li>["5", "10", "15", "-1"] Here the "-1" represents infinite retires with the retry 122 * time "15" the last retry number). 123 * <li>["2+r15"] 2 seconds + random time below 15 seconds, fail after that. 124 * </ol> 125 * <p>When fails, by default throttle for 24 hours. 126 * <li>"UnthrottlingEvents": Events for which the retry time can be unthrottled in string. 127 * Possible unthrottling events are: 128 * <ol> 129 * <li>"WIFI_DISABLE_EVENT": Wifi on to off toggle. 130 * <li>"APM_DISABLE_EVENT": APM on to off toggle. 131 * <li>"APM_ENABLE_EVENT": APM off to on toggle. 132 * <li>"WIFI_AP_CHANGED_EVENT": Wifi is connected to an AP with different SSID. 133 * <li>"WIFI_CALLING_DISABLE_EVENT": Wifi calling button on to off toggle. 134 * </ol> 135 * <li>"NumAttemptsPerFqdn" Integer to specify th count of tunnel setup attempts IWLAN must 136 * perform with the IP address(es) returned by a single FQDN, before moving on to the next 137 * FQDN. It is an optional field. 138 * <li>"HandoverAttemptCount": Integer to specify the number of handover request attempts 139 * before using initial attach instead. It is an optional field. 140 * <p>"HandoverAttemptCount" should not be defined in the config when "ErrorType" is 141 * defined as any other error types except "IKE_PROTOCOL_ERROR_TYPE", including "*". 142 * </ul> 143 * 144 * <p>Note: When the value is "*" for any of "ApnName" or "ErrorType" or "ErrorDetails", it 145 * means that the config definition applies to rest of the errors for which the config is not 146 * defined. For example, if "ApnName" is "ims" and one of the "ErrorType" in it is defined as 147 * "*" - this policy will be applied to the error that doesn't fall into other error types 148 * defined under "ims". 149 */ 150 public static final String KEY_ERROR_POLICY_CONFIG_STRING = 151 PREFIX + "key_error_policy_config_string"; 152 153 /** 154 * Default delay in seconds for releasing the IWLAN connection after a WWAN handover. This is 155 * the default value for {@link #KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT}. 156 */ 157 public static final int DEFAULT_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT = 0; 158 159 /** 160 * The default value for determining whether the IKE N1_MODE_CAPABILITY Notify payload is 161 * excluded during emergency session setup. 162 */ 163 public static final boolean DEFAULT_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL = false; 164 165 /** 166 * The default value for determining whether N1 mode shall be enabled or disabled depending on 167 * 5G enabling status via the UI/UX. 168 */ 169 public static final boolean DEFAULT_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL = false; 170 171 /** This is the default value for {@link #KEY_DISTINCT_EPDG_FOR_EMERGENCY_ALLOWED_BOOL}. */ 172 public static final boolean DEFAULT_DISTINCT_EPDG_FOR_EMERGENCY_ALLOWED_BOOL = false; 173 /** 174 * Default value indicating whether the UE includes the IKE DEVICE_IDENTITY Notify payload upon 175 * receiving a request. This is the default setting for {@link 176 * #KEY_IKE_DEVICE_IDENTITY_SUPPORTED_BOOL}. 177 */ 178 public static final boolean DEFAULT_IKE_DEVICE_IDENTITY_SUPPORTED_BOOL = false; 179 180 /** This is the default value for {@link #KEY_IKE_SA_TRANSFORMS_REORDER_BOOL}. */ 181 public static final boolean DEFAULT_IKE_SA_TRANSFORMS_REORDER_BOOL = false; 182 183 /** 184 * The default value for determining IWLAN's behavior when error happens during ePDG tunnel 185 * setup. This is the default value for {@link #KEY_ERROR_POLICY_CONFIG_STRING}. 186 */ 187 public static final String DEFAULT_ERROR_POLICY_CONFIG_STRING = 188 """ 189 [{ 190 "ApnName": "*", 191 "ErrorTypes": [{ 192 "ErrorType": "*", 193 "ErrorDetails": ["*"], 194 "RetryArray": ["1","2","2","10","20","40","80","160", 195 "320","640","1280","1800","3600","-1"], 196 "UnthrottlingEvents": ["APM_ENABLE_EVENT","APM_DISABLE_EVENT", 197 "WIFI_DISABLE_EVENT","WIFI_AP_CHANGED_EVENT"]},{ 198 "ErrorType": "GENERIC_ERROR_TYPE", 199 "ErrorDetails": ["IO_EXCEPTION"], 200 "RetryArray": ["0","0","0","30","60+r15","120","-1"], 201 "UnthrottlingEvents": ["APM_ENABLE_EVENT","APM_DISABLE_EVENT", 202 "WIFI_DISABLE_EVENT","WIFI_AP_CHANGED_EVENT"]},{ 203 "ErrorType": "IKE_PROTOCOL_ERROR_TYPE", 204 "ErrorDetails": ["*"], 205 "RetryArray": ["5","10","10","20","40","80","160", 206 "320","640","1280","1800","3600","-1"], 207 "UnthrottlingEvents": ["APM_ENABLE_EVENT","WIFI_DISABLE_EVENT", 208 "WIFI_CALLING_DISABLE_EVENT"]},{ 209 "ErrorType": "IKE_PROTOCOL_ERROR_TYPE", 210 "ErrorDetails": ["36"], 211 "RetryArray": ["0","0","0","10","20","40","80","160", 212 "320","640","1280","1800","3600","-1"], 213 "UnthrottlingEvents": ["APM_ENABLE_EVENT","WIFI_DISABLE_EVENT", 214 "WIFI_CALLING_DISABLE_EVENT"], 215 "HandoverAttemptCount": "3"}] 216 }] 217 """; 218 219 private static final PersistableBundle sTestBundle = new PersistableBundle(); 220 221 private static PersistableBundle sHiddenBundle = new PersistableBundle(); 222 223 static { 224 sHiddenBundle = createHiddenDefaultConfig(); 225 } 226 227 /** 228 * Creates a hidden default configuration. 229 * 230 * @return a PersistableBundle containing the hidden default configuration 231 */ createHiddenDefaultConfig()232 private static @NonNull PersistableBundle createHiddenDefaultConfig() { 233 PersistableBundle bundle = new PersistableBundle(); 234 bundle.putInt( 235 KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT, 236 DEFAULT_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT); 237 bundle.putBoolean( 238 KEY_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL, 239 DEFAULT_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL); 240 bundle.putBoolean( 241 KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL, DEFAULT_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL); 242 bundle.putBoolean( 243 KEY_DISTINCT_EPDG_FOR_EMERGENCY_ALLOWED_BOOL, 244 DEFAULT_DISTINCT_EPDG_FOR_EMERGENCY_ALLOWED_BOOL); 245 bundle.putBoolean( 246 KEY_IKE_DEVICE_IDENTITY_SUPPORTED_BOOL, DEFAULT_IKE_DEVICE_IDENTITY_SUPPORTED_BOOL); 247 bundle.putBoolean( 248 KEY_IKE_SA_TRANSFORMS_REORDER_BOOL, DEFAULT_IKE_SA_TRANSFORMS_REORDER_BOOL); 249 bundle.putString(KEY_ERROR_POLICY_CONFIG_STRING, DEFAULT_ERROR_POLICY_CONFIG_STRING); 250 return bundle; 251 } 252 getConfig(Context context, int slotId, String key)253 private static PersistableBundle getConfig(Context context, int slotId, String key) { 254 if (sTestBundle.containsKey(key)) { 255 return sTestBundle; 256 } 257 258 CarrierConfigManager carrierConfigManager = 259 context.getSystemService(CarrierConfigManager.class); 260 if (carrierConfigManager == null) { 261 return getDefaultConfig(key); 262 } 263 264 int subId = IwlanHelper.getSubId(context, slotId); 265 PersistableBundle bundle = carrierConfigManager.getConfigForSubId(subId, key); 266 return bundle.containsKey(key) ? bundle : getDefaultConfig(key); 267 } 268 getDefaultConfig(String key)269 private static PersistableBundle getDefaultConfig(String key) { 270 PersistableBundle bundle = CarrierConfigManager.getDefaultConfig(); 271 if (bundle.containsKey(key)) { 272 return bundle; 273 } 274 275 if (sHiddenBundle.containsKey(key)) { 276 return sHiddenBundle; 277 } 278 279 throw new IllegalArgumentException("Default config not found for key: " + key); 280 } 281 282 /** 283 * Gets a configuration int value for a given slot ID and key. 284 * 285 * @param context the application context 286 * @param slotId the slot ID 287 * @param key the configuration key 288 * @return the configuration int value 289 */ getConfigInt(Context context, int slotId, String key)290 public static int getConfigInt(Context context, int slotId, String key) { 291 return getConfig(context, slotId, key).getInt(key); 292 } 293 294 /** 295 * Gets a configuration long value for a given slot ID and key. 296 * 297 * @param context the application context 298 * @param slotId the slot ID 299 * @param key the configuration key 300 * @return the configuration long value 301 */ getConfigLong(Context context, int slotId, String key)302 public static long getConfigLong(Context context, int slotId, String key) { 303 return getConfig(context, slotId, key).getLong(key); 304 } 305 306 /** 307 * Gets a configuration double value for a given slot ID and key. 308 * 309 * @param context the application context 310 * @param slotId the slot ID 311 * @param key the configuration key 312 * @return the configuration double value 313 */ getConfigDouble(Context context, int slotId, String key)314 public static double getConfigDouble(Context context, int slotId, String key) { 315 return getConfig(context, slotId, key).getDouble(key); 316 } 317 318 /** 319 * Gets a configuration boolean value for a given slot ID and key. 320 * 321 * @param context the application context 322 * @param slotId the slot ID 323 * @param key the configuration key 324 * @return the configuration boolean value 325 */ getConfigBoolean(Context context, int slotId, String key)326 public static boolean getConfigBoolean(Context context, int slotId, String key) { 327 return getConfig(context, slotId, key).getBoolean(key); 328 } 329 330 /** 331 * Gets a configuration string value for a given slot ID and key. 332 * 333 * @param context the application context 334 * @param slotId the slot ID 335 * @param key the configuration key 336 * @return the configuration string value 337 */ getConfigString(Context context, int slotId, String key)338 public static String getConfigString(Context context, int slotId, String key) { 339 return getConfig(context, slotId, key).getString(key); 340 } 341 342 /** 343 * Gets a configuration int[] value for a given slot ID and key. 344 * 345 * @param context the application context 346 * @param slotId the slot ID 347 * @param key the configuration key 348 * @return the configuration int[] value 349 */ getConfigIntArray(Context context, int slotId, String key)350 public static int[] getConfigIntArray(Context context, int slotId, String key) { 351 return getConfig(context, slotId, key).getIntArray(key); 352 } 353 354 /** 355 * Gets a configuration long[] value for a given slot ID and key. 356 * 357 * @param context the application context 358 * @param slotId the slot ID 359 * @param key the configuration key 360 * @return the configuration long[] value 361 */ getConfigLongArray(Context context, int slotId, String key)362 public static long[] getConfigLongArray(Context context, int slotId, String key) { 363 return getConfig(context, slotId, key).getLongArray(key); 364 } 365 366 /** 367 * Gets a configuration double[] value for a given slot ID and key. 368 * 369 * @param context the application context 370 * @param slotId the slot ID 371 * @param key the configuration key 372 * @return the configuration double[] value 373 */ getConfigDoubleArray(Context context, int slotId, String key)374 public static double[] getConfigDoubleArray(Context context, int slotId, String key) { 375 return getConfig(context, slotId, key).getDoubleArray(key); 376 } 377 378 /** 379 * Gets a configuration boolean[] value for a given slot ID and key. 380 * 381 * @param context the application context 382 * @param slotId the slot ID 383 * @param key the configuration key 384 * @return the configuration boolean[] value 385 */ getConfigBooleanArray(Context context, int slotId, String key)386 public static boolean[] getConfigBooleanArray(Context context, int slotId, String key) { 387 return getConfig(context, slotId, key).getBooleanArray(key); 388 } 389 390 /** 391 * Gets a configuration string[] value for a given slot ID and key. 392 * 393 * @param context the application context 394 * @param slotId the slot ID 395 * @param key the configuration key 396 * @return the configuration string[] value 397 */ getConfigStringArray(Context context, int slotId, String key)398 public static String[] getConfigStringArray(Context context, int slotId, String key) { 399 return getConfig(context, slotId, key).getStringArray(key); 400 } 401 402 /** 403 * Gets the default configuration int value for a given key. 404 * 405 * @param key the configuration key 406 * @return the default configuration int value 407 * @throws IllegalArgumentException if the default configuration is null for the given key 408 */ getDefaultConfigInt(String key)409 public static int getDefaultConfigInt(String key) { 410 return getDefaultConfig(key).getInt(key); 411 } 412 413 /** 414 * Gets the default configuration long value for a given key. 415 * 416 * @param key the configuration key 417 * @return the default configuration long value 418 * @throws IllegalArgumentException if the default configuration is null for the given key 419 */ getDefaultConfigLong(String key)420 public static long getDefaultConfigLong(String key) { 421 return getDefaultConfig(key).getLong(key); 422 } 423 424 /** 425 * Gets the default configuration double value for a given key. 426 * 427 * @param key the configuration key 428 * @return the default configuration double value 429 * @throws IllegalArgumentException if the default configuration is null for the given key 430 */ getDefaultConfigDouble(String key)431 public static double getDefaultConfigDouble(String key) { 432 return getDefaultConfig(key).getDouble(key); 433 } 434 435 /** 436 * Gets the default configuration string value for a given key. 437 * 438 * @param key the configuration key 439 * @return the default configuration string value 440 * @throws IllegalArgumentException if the default configuration is null for the given key 441 */ getDefaultConfigString(String key)442 public static String getDefaultConfigString(String key) { 443 return getDefaultConfig(key).getString(key); 444 } 445 446 /** 447 * Gets the default configuration boolean value for a given key. 448 * 449 * @param key the configuration key 450 * @return the default configuration boolean value 451 * @throws IllegalArgumentException if the default configuration is null for the given key 452 */ getDefaultConfigBoolean(String key)453 public static boolean getDefaultConfigBoolean(String key) { 454 return getDefaultConfig(key).getBoolean(key); 455 } 456 457 /** 458 * Gets the default configuration int[] value for a given key. 459 * 460 * @param key the configuration key 461 * @return the default configuration int[] value 462 * @throws IllegalArgumentException if the default configuration is null for the given key 463 */ getDefaultConfigIntArray(String key)464 public static int[] getDefaultConfigIntArray(String key) { 465 return getDefaultConfig(key).getIntArray(key); 466 } 467 468 /** 469 * Gets the default configuration long value for a given key. 470 * 471 * @param key the configuration key 472 * @return the default configuration long value 473 * @throws IllegalArgumentException if the default configuration is null for the given key 474 */ getDefaultConfigLongArray(String key)475 public static long[] getDefaultConfigLongArray(String key) { 476 return getDefaultConfig(key).getLongArray(key); 477 } 478 479 /** 480 * Gets the default configuration double[] value for a given key. 481 * 482 * @param key the configuration key 483 * @return the default configuration double[] value 484 * @throws IllegalArgumentException if the default configuration is null for the given key 485 */ getDefaultConfigDoubleArray(String key)486 public static double[] getDefaultConfigDoubleArray(String key) { 487 return getDefaultConfig(key).getDoubleArray(key); 488 } 489 490 /** 491 * Gets the default configuration string[] value for a given key. 492 * 493 * @param key the configuration key 494 * @return the default configuration string[] value 495 * @throws IllegalArgumentException if the default configuration is null for the given key 496 */ getDefaultConfigStringArray(String key)497 public static String[] getDefaultConfigStringArray(String key) { 498 return getDefaultConfig(key).getStringArray(key); 499 } 500 501 /** 502 * Gets the default configuration boolean[] value for a given key. 503 * 504 * @param key the configuration key 505 * @return the default configuration boolean[] value 506 * @throws IllegalArgumentException if the default configuration is null for the given key 507 */ getDefaultConfigBooleanArray(String key)508 public static boolean[] getDefaultConfigBooleanArray(String key) { 509 return getDefaultConfig(key).getBooleanArray(key); 510 } 511 512 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigBundle(PersistableBundle bundle)513 public static void putTestConfigBundle(PersistableBundle bundle) { 514 sTestBundle.putAll(bundle); 515 } 516 517 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigInt(@onNull String key, int value)518 public static void putTestConfigInt(@NonNull String key, int value) { 519 sTestBundle.putInt(key, value); 520 } 521 522 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigLong(@onNull String key, long value)523 public static void putTestConfigLong(@NonNull String key, long value) { 524 sTestBundle.putLong(key, value); 525 } 526 527 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigDouble(@onNull String key, double value)528 public static void putTestConfigDouble(@NonNull String key, double value) { 529 sTestBundle.putDouble(key, value); 530 } 531 532 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigBoolean(@onNull String key, boolean value)533 public static void putTestConfigBoolean(@NonNull String key, boolean value) { 534 sTestBundle.putBoolean(key, value); 535 } 536 537 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigString(@onNull String key, String value)538 public static void putTestConfigString(@NonNull String key, String value) { 539 sTestBundle.putString(key, value); 540 } 541 542 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigIntArray(@onNull String key, @NonNull int[] value)543 public static void putTestConfigIntArray(@NonNull String key, @NonNull int[] value) { 544 sTestBundle.putIntArray(key, value); 545 } 546 547 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigLongArray(@onNull String key, @NonNull long[] value)548 public static void putTestConfigLongArray(@NonNull String key, @NonNull long[] value) { 549 sTestBundle.putLongArray(key, value); 550 } 551 552 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigDoubleArray(@onNull String key, @NonNull double[] value)553 public static void putTestConfigDoubleArray(@NonNull String key, @NonNull double[] value) { 554 sTestBundle.putDoubleArray(key, value); 555 } 556 557 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigBooleanArray(@onNull String key, @NonNull boolean[] value)558 public static void putTestConfigBooleanArray(@NonNull String key, @NonNull boolean[] value) { 559 sTestBundle.putBooleanArray(key, value); 560 } 561 562 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) putTestConfigStringArray(@onNull String key, @NonNull String[] value)563 public static void putTestConfigStringArray(@NonNull String key, @NonNull String[] value) { 564 sTestBundle.putStringArray(key, value); 565 } 566 567 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) resetTestConfig()568 public static void resetTestConfig() { 569 sTestBundle.clear(); 570 } 571 } 572